diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b2a950742..9e253d8ac 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -76,7 +76,7 @@ repos: - id: requirements.txt name: requirements.txt description: Generate requirements.txt - entry: tools/extract_requirements.py dev + entry: tools/extract_requirements.py dev sentry pass_filenames: false language: script files: setup.py$ diff --git a/Dockerfile b/Dockerfile index 4465d8cd0..ab3f7b6dd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -83,7 +83,7 @@ RUN --mount=type=cache,target=/root/.cache/pip \ COPY analyzer . RUN --mount=type=cache,target=/root/.cache/pip \ - pip install --editable . + pip install --editable .[sentry] # Run USER ${UID}:${GID} @@ -122,7 +122,7 @@ RUN --mount=type=cache,target=/root/.cache/pip \ COPY playout . RUN --mount=type=cache,target=/root/.cache/pip \ - pip install --editable . + pip install --editable .[sentry] # Run USER ${UID}:${GID} @@ -158,7 +158,7 @@ RUN --mount=type=cache,target=/root/.cache/pip \ COPY api . RUN --mount=type=cache,target=/root/.cache/pip \ - pip install --editable .[prod] + pip install --editable .[prod,sentry] # Run USER ${UID}:${GID} @@ -191,7 +191,7 @@ RUN --mount=type=cache,target=/root/.cache/pip \ COPY worker . RUN --mount=type=cache,target=/root/.cache/pip \ - pip install --editable . + pip install --editable .[sentry] # Run USER ${UID}:${GID} diff --git a/analyzer/Makefile b/analyzer/Makefile index 32e862fd0..810d9db1f 100644 --- a/analyzer/Makefile +++ b/analyzer/Makefile @@ -4,7 +4,7 @@ include ../tools/python.mk PIP_INSTALL := \ --editable ../shared \ - --editable .[dev] + --editable .[dev,sentry] PYLINT_ARG := libretime_analyzer tests || true MYPY_ARG := libretime_analyzer tests || true BANDIT_ARG := libretime_analyzer || true diff --git a/analyzer/libretime_analyzer/main.py b/analyzer/libretime_analyzer/main.py index 43c33a02b..fb6a831d7 100644 --- a/analyzer/libretime_analyzer/main.py +++ b/analyzer/libretime_analyzer/main.py @@ -1,3 +1,5 @@ +import logging +import os from pathlib import Path from typing import Optional @@ -6,10 +8,13 @@ from libretime_shared.cli import cli_config_options, cli_logging_options from libretime_shared.config import DEFAULT_ENV_PREFIX from libretime_shared.logging import setup_logger +from . import PACKAGE, VERSION from .config import Config from .message_listener import MessageListener from .status_reporter import StatusReporter +logger = logging.getLogger(__name__) + VERSION = "1.0" DEFAULT_RETRY_QUEUE_FILEPATH = Path("retry_queue") @@ -36,6 +41,16 @@ def cli( setup_logger(log_level, log_filepath) config = Config(config_filepath) + if "SENTRY_DSN" in os.environ: + logger.info("installing sentry") + # pylint: disable=import-outside-toplevel + import sentry_sdk + + sentry_sdk.init( + traces_sample_rate=1.0, + release=f"{PACKAGE}@{VERSION}", + ) + # Start up the StatusReporter process StatusReporter.start_thread(retry_queue_filepath) diff --git a/analyzer/setup.py b/analyzer/setup.py index 94bb9a4da..e46eac548 100644 --- a/analyzer/setup.py +++ b/analyzer/setup.py @@ -30,6 +30,9 @@ setup( "distro>=1.8.0,<1.9", "types-requests>=2.25.1,<2.29", ], + "sentry": [ + "sentry-sdk>=1.15.0,<1.16", + ], }, zip_safe=False, ) diff --git a/api/Makefile b/api/Makefile index 1943f0852..4dc3ee288 100644 --- a/api/Makefile +++ b/api/Makefile @@ -4,7 +4,7 @@ include ../tools/python.mk PIP_INSTALL := \ --editable ../shared \ - --editable .[dev] + --editable .[dev,sentry] PYLINT_ARG := libretime_api MYPY_ARG := libretime_api BANDIT_ARG := --exclude '*/tests/*' libretime_api || true diff --git a/api/libretime_api/settings/_internal.py b/api/libretime_api/settings/_internal.py index 13ced00ae..4280ab45a 100644 --- a/api/libretime_api/settings/_internal.py +++ b/api/libretime_api/settings/_internal.py @@ -1,6 +1,8 @@ -from os import getenv +from os import environ, getenv from typing import Optional +from .. import PACKAGE, VERSION + API_VERSION = "2.0.0" # SECURITY WARNING: don't run with debug turned on in production! @@ -178,3 +180,18 @@ SPECTACULAR_SETTINGS = { "VERSION": API_VERSION, "ENUM_NAME_OVERRIDES": SPECTACULAR_ENUM_NAME_OVERRIDES, } + +# Sentry +# https://docs.sentry.io/platforms/python/guides/django/ +if "SENTRY_DSN" in environ: + # pylint: disable=import-outside-toplevel + import sentry_sdk + from sentry_sdk.integrations.django import DjangoIntegration + + sentry_sdk.init( + traces_sample_rate=1.0, + release=f"{PACKAGE}@{VERSION}", + integrations=[ + DjangoIntegration(), + ], + ) diff --git a/api/setup.py b/api/setup.py index d7e18f178..a29905724 100644 --- a/api/setup.py +++ b/api/setup.py @@ -44,5 +44,8 @@ setup( "pytest-django>=4.5.2,<4.6", "requests-mock>=1.10.0,<1.11", ], + "sentry": [ + "sentry-sdk[django]>=1.15.0,<1.16", + ], }, ) diff --git a/playout/Makefile b/playout/Makefile index e3a0c4998..512bb6924 100644 --- a/playout/Makefile +++ b/playout/Makefile @@ -6,7 +6,7 @@ APP := playout PIP_INSTALL := \ --editable ../api-client \ --editable ../shared \ - --editable .[dev] + --editable .[dev,sentry] PYLINT_ARG := libretime_playout tests MYPY_ARG := libretime_playout tests || true BANDIT_ARG := libretime_playout || true diff --git a/playout/libretime_playout/main.py b/playout/libretime_playout/main.py index d0e432dd8..fa69ec4e9 100644 --- a/playout/libretime_playout/main.py +++ b/playout/libretime_playout/main.py @@ -1,8 +1,8 @@ """ Python part of radio playout (pypo) """ - import logging +import os import sys import time from datetime import datetime @@ -18,6 +18,7 @@ from libretime_shared.cli import cli_config_options, cli_logging_options from libretime_shared.config import DEFAULT_ENV_PREFIX from libretime_shared.logging import setup_logger +from . import PACKAGE, VERSION from .config import CACHE_DIR, RECORD_DIR, Config from .history.stats import StatsCollectorThread from .liquidsoap.client import LiquidsoapClient @@ -75,6 +76,16 @@ def cli( setup_logger(log_level, log_filepath) config = Config(config_filepath) + if "SENTRY_DSN" in os.environ: + logger.info("installing sentry") + # pylint: disable=import-outside-toplevel + import sentry_sdk + + sentry_sdk.init( + traces_sample_rate=1.0, + release=f"{PACKAGE}@{VERSION}", + ) + try: for dir_path in [CACHE_DIR, RECORD_DIR]: dir_path.mkdir(exist_ok=True) diff --git a/playout/setup.py b/playout/setup.py index 16551d9c0..3de3c4415 100644 --- a/playout/setup.py +++ b/playout/setup.py @@ -41,6 +41,9 @@ setup( "types-python-dateutil>=2.8.1,<2.9", "types-requests>=2.25.1,<2.29", ], + "sentry": [ + "sentry-sdk>=1.15.0,<1.16", + ], }, zip_safe=False, ) diff --git a/worker/Makefile b/worker/Makefile index 352480426..cecf2b4c5 100644 --- a/worker/Makefile +++ b/worker/Makefile @@ -4,7 +4,7 @@ include ../tools/python.mk PIP_INSTALL := \ --editable ../shared \ - --editable .[dev] + --editable .[dev,sentry] PYLINT_ARG := libretime_worker MYPY_ARG := libretime_worker || true BANDIT_ARG := libretime_worker diff --git a/worker/libretime_worker/tasks.py b/worker/libretime_worker/tasks.py index ff5bfc9e8..d7d189cc0 100644 --- a/worker/libretime_worker/tasks.py +++ b/worker/libretime_worker/tasks.py @@ -1,4 +1,5 @@ import json +import os from email.message import EmailMessage from pathlib import Path from tempfile import NamedTemporaryFile @@ -7,17 +8,35 @@ from urllib.parse import urlsplit import mutagen import requests -from celery import Celery +from celery import Celery, signals from celery.utils.log import get_task_logger from mutagen import MutagenError from requests import RequestException, Response +from . import PACKAGE, VERSION from .config import config worker = Celery() logger = get_task_logger(__name__) +@signals.worker_init.connect +def init_sentry(**_kwargs): + if "SENTRY_DSN" in os.environ: + logger.info("installing sentry") + # pylint: disable=import-outside-toplevel + import sentry_sdk + from sentry_sdk.integrations.celery import CeleryIntegration + + sentry_sdk.init( + traces_sample_rate=1.0, + release=f"{PACKAGE}@{VERSION}", + integrations=[ + CeleryIntegration(), + ], + ) + + @worker.task(name="podcast-download", acks_late=True) def podcast_download( episode_id: int, diff --git a/worker/setup.py b/worker/setup.py index e1a767fe2..32469457b 100644 --- a/worker/setup.py +++ b/worker/setup.py @@ -25,6 +25,9 @@ setup( "requests-mock>=1.10.0,<1.11", "types-requests>=2.25.1,<2.29", ], + "sentry": [ + "sentry-sdk>=1.15.0,<1.16", + ], }, zip_safe=False, )