From 67e2cfd2f9ed64bb0f45b45a3ff70a83f3484dc9 Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Sun, 21 Jan 2024 02:51:25 +0000 Subject: [PATCH] Attach build and environment info to Sentry --- .github/workflows/push-image.yml | 2 ++ Dockerfile | 4 +++ app.py | 55 ++++++++++++++++++++++++-------- 3 files changed, 48 insertions(+), 13 deletions(-) diff --git a/.github/workflows/push-image.yml b/.github/workflows/push-image.yml index 55366c8..72c9a48 100644 --- a/.github/workflows/push-image.yml +++ b/.github/workflows/push-image.yml @@ -40,5 +40,7 @@ jobs: with: context: . push: true + build-args: | + DOCKER_METADATA_OUTPUT_JSON tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 5d38fe0..80f6d6e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,9 @@ FROM python:3.11.5-slim +# Pass information about the build to the container +ARG DOCKER_METADATA_OUTPUT_JSON='{}' +ENV DOCKER_METADATA_OUTPUT_JSON=${DOCKER_METADATA_OUTPUT_JSON} + COPY requirements.txt /app/ WORKDIR /app diff --git a/app.py b/app.py index 73afacb..59a2b70 100644 --- a/app.py +++ b/app.py @@ -17,28 +17,57 @@ LOG_LEVEL = os.environ.get("LOG_LEVEL", "DEBUG") PORT = os.environ.get("PORT", 5000) HOST = os.environ.get("HOST", "0.0.0.0") -SENTRY_DSN = os.environ.get("SENTRY_DSN", "") logging.basicConfig(level=LOG_LEVEL) -if SENTRY_DSN: - logging.info("Sentry DSN provided, enabling Sentry SDK") + +# BUILD_INFO is generated by the build pipeline (e.g. docker/metadata-action). +# It looks like: +# {"tags":["ghcr.io/watonomous/repo-ingestion:main"],"labels":{"org.opencontainers.image.title":"repo-ingestion","org.opencontainers.image.description":"Simple server to receive file changes and open GitHub pull requests","org.opencontainers.image.url":"https://github.com/WATonomous/repo-ingestion","org.opencontainers.image.source":"https://github.com/WATonomous/repo-ingestion","org.opencontainers.image.version":"main","org.opencontainers.image.created":"2024-01-20T16:10:39.421Z","org.opencontainers.image.revision":"1d55b62b15c78251e0560af9e97927591e260a98","org.opencontainers.image.licenses":""}} +BUILD_INFO=json.loads(os.getenv("DOCKER_METADATA_OUTPUT_JSON", "{}")) + + +# Set up Sentry +if os.getenv("SENTRY_DSN"): + build_labels = BUILD_INFO.get("labels", {}) + image_title = build_labels.get("org.opencontainers.image.title", "unknown_image") + image_version = build_labels.get("org.opencontainers.image.version", "unknown_version") + image_rev = build_labels.get("org.opencontainers.image.revision", "unknown_rev") + + sentry_config = { + "dsn": os.getenv("SENTRY_DSN"), + "environment": os.getenv("SENTRY_ENVIRONMENT", "unknown"), + "release": os.getenv("SENTRY_RELEASE", f'{image_title}:{image_version}@{image_rev}'), + } + + logging.info(f"Sentry DSN found. Setting up Sentry with config: {sentry_config}") + sentry_logging = LoggingIntegration( level=logging.INFO, # Capture info and above as breadcrumbs event_level=logging.ERROR # Send errors as events ) + + def sentry_traces_sampler(sampling_context): + # Inherit parent sampling decision + if sampling_context["parent_sampled"] is not None: + return sampling_context["parent_sampled"] + + # Don't need to sample health checks + if sampling_context.get("asgi_scope", {}).get("path", "").startswith("/health"): + return 0 + + # Sample everything else + return 1 + sentry_sdk.init( - dsn=SENTRY_DSN, - integrations=[ - sentry_logging, - ], - - # Set traces_sample_rate to 1.0 to capture 100% - # of transactions for performance monitoring. - # We recommend adjusting this value in production, - traces_sample_rate=1.0, + **sentry_config, + integrations=[sentry_logging], + + traces_sampler=sentry_traces_sampler, + + enable_tracing=True, ) else: - logging.info("No Sentry DSN provided, Sentry SDK disabled") + logging.info("No Sentry DSN found. Skipping Sentry setup.") def split_dsn(dsn): """