From 8ac2dc34d361e45d6185aa1f7373cbaeba76e3cb Mon Sep 17 00:00:00 2001 From: Philipp Metzner Date: Tue, 29 Oct 2024 17:04:45 +0100 Subject: [PATCH 1/3] Enable OpenTelemetry metrics on Google Cloud --- back/boxtribute_server/app.py | 43 +++++++++++++++++++++++++++++++++++ back/requirements-deploy.txt | 3 +++ 2 files changed, 46 insertions(+) diff --git a/back/boxtribute_server/app.py b/back/boxtribute_server/app.py index aa4a31ae0..e0ee174c3 100644 --- a/back/boxtribute_server/app.py +++ b/back/boxtribute_server/app.py @@ -9,6 +9,7 @@ from sentry_sdk.integrations.flask import FlaskIntegration from .db import create_db_interface, db +from .utils import in_staging_environment def create_app(): @@ -76,6 +77,7 @@ def before_sentry_send(event, hint): # pragma: no cover ) app = create_app() + setup_opentelemetry(app) configure_app( app, *blueprints, @@ -91,3 +93,44 @@ def before_sentry_send(event, hint): # pragma: no cover replica_socket=os.getenv("MYSQL_REPLICA_SOCKET"), ) return app + + +def setup_opentelemetry(app): + if not in_staging_environment(): + return + + # https://cloud.google.com/stackdriver/docs/instrumentation/choose-approach#app_engine + # https://cloud.google.com/trace/docs/setup/python-ot + # https://github.com/GoogleCloudPlatform/opentelemetry-operations-python/blob/1f1775886d7314b113acd322633afb278f875687/samples/instrumentation-quickstart/setup_opentelemetry.py + from opentelemetry.sdk.resources import SERVICE_INSTANCE_ID, SERVICE_NAME, Resource + + # No permission for trace.googleapis.com + # from opentelemetry import trace + # from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter + # from opentelemetry.sdk.trace import TracerProvider + # from opentelemetry.sdk.trace.export import BatchSpanProcessor + + from opentelemetry import metrics + from opentelemetry.exporter.otlp.proto.http.metric_exporter import OTLPMetricExporter + from opentelemetry.sdk.metrics import MeterProvider + from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader + + resource = Resource.create(attributes={ + # Use the PID as the service.instance.id to avoid duplicate timeseries + # from different Gunicorn worker processes. + SERVICE_INSTANCE_ID: f"worker-{os.getpid()}", + }) + + # tracer_provider = TracerProvider(resource=resource) + # processor = BatchSpanProcessor(OTLPSpanExporter()) + # tracer_provider.add_span_processor(processor) + # trace.set_tracer_provider(tracer_provider) + + reader = PeriodicExportingMetricReader( + OTLPMetricExporter() + ) + meter_provider = MeterProvider(metric_readers=[reader], resource=resource) + metrics.set_meter_provider(meter_provider) + + from opentelemetry.instrumentation.flask import FlaskInstrumentor + FlaskInstrumentor().instrument_app(app) diff --git a/back/requirements-deploy.txt b/back/requirements-deploy.txt index 9c97e00f7..d2f451312 100644 --- a/back/requirements-deploy.txt +++ b/back/requirements-deploy.txt @@ -1 +1,4 @@ google-cloud-logging==3.11.3 +opentelemetry-sdk==1.27.0 +opentelemetry-exporter-otlp-proto-http==1.27.0 +opentelemetry-instrumentation-flask==0.48b0 From 379b77f3f5749847986032321574ac7bf4a2b848 Mon Sep 17 00:00:00 2001 From: Philipp Metzner Date: Tue, 29 Oct 2024 17:07:20 +0100 Subject: [PATCH 2/3] Temporarily deploy branch to staging --- .circleci/config.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1bf5f781d..87874002b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -454,6 +454,7 @@ workflows: only: - master - production + - enable-otel - install-node-packages: requires: - checkout-to-workspace @@ -462,6 +463,7 @@ workflows: only: - master - production + - enable-otel # staging - build-front: @@ -473,6 +475,7 @@ workflows: branches: only: - master + - enable-otel - deploy: name: deploy-staging context: STAGING @@ -483,6 +486,7 @@ workflows: branches: only: - master + - enable-otel - deploy-api: name: deploy-api-staging context: STAGING From 6462152e59cef2a431d1a16096ca79b4c0691e3d Mon Sep 17 00:00:00 2001 From: James Crowley <509533+jamescrowley@users.noreply.github.com> Date: Fri, 8 Nov 2024 13:28:59 +1100 Subject: [PATCH 3/3] Testing GCP cloud trace exporter --- back/boxtribute_server/app.py | 51 +++++++++++++++++------------------ back/requirements-deploy.txt | 3 ++- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/back/boxtribute_server/app.py b/back/boxtribute_server/app.py index e0ee174c3..da4090a5f 100644 --- a/back/boxtribute_server/app.py +++ b/back/boxtribute_server/app.py @@ -102,35 +102,34 @@ def setup_opentelemetry(app): # https://cloud.google.com/stackdriver/docs/instrumentation/choose-approach#app_engine # https://cloud.google.com/trace/docs/setup/python-ot # https://github.com/GoogleCloudPlatform/opentelemetry-operations-python/blob/1f1775886d7314b113acd322633afb278f875687/samples/instrumentation-quickstart/setup_opentelemetry.py - from opentelemetry.sdk.resources import SERVICE_INSTANCE_ID, SERVICE_NAME, Resource - # No permission for trace.googleapis.com - # from opentelemetry import trace + from opentelemetry import trace + from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter + from opentelemetry.propagate import set_global_textmap + from opentelemetry.propagators.cloud_trace_propagator import ( + CloudTraceFormatPropagator, + ) + from opentelemetry.sdk.resources import SERVICE_INSTANCE_ID, Resource + # from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter - # from opentelemetry.sdk.trace import TracerProvider - # from opentelemetry.sdk.trace.export import BatchSpanProcessor - - from opentelemetry import metrics - from opentelemetry.exporter.otlp.proto.http.metric_exporter import OTLPMetricExporter - from opentelemetry.sdk.metrics import MeterProvider - from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader - - resource = Resource.create(attributes={ - # Use the PID as the service.instance.id to avoid duplicate timeseries - # from different Gunicorn worker processes. - SERVICE_INSTANCE_ID: f"worker-{os.getpid()}", - }) - - # tracer_provider = TracerProvider(resource=resource) - # processor = BatchSpanProcessor(OTLPSpanExporter()) - # tracer_provider.add_span_processor(processor) - # trace.set_tracer_provider(tracer_provider) - - reader = PeriodicExportingMetricReader( - OTLPMetricExporter() + from opentelemetry.sdk.trace import TracerProvider + from opentelemetry.sdk.trace.export import BatchSpanProcessor + + resource = Resource.create( + attributes={ + # Use the PID as the service.instance.id to avoid duplicate timeseries + # from different Gunicorn worker processes. + SERVICE_INSTANCE_ID: f"worker-{os.getpid()}", + } ) - meter_provider = MeterProvider(metric_readers=[reader], resource=resource) - metrics.set_meter_provider(meter_provider) + + provider = TracerProvider(resource=resource) + processor = BatchSpanProcessor(CloudTraceSpanExporter()) + provider.add_span_processor(processor) + + trace.set_tracer_provider(provider) + set_global_textmap(CloudTraceFormatPropagator()) from opentelemetry.instrumentation.flask import FlaskInstrumentor + FlaskInstrumentor().instrument_app(app) diff --git a/back/requirements-deploy.txt b/back/requirements-deploy.txt index d2f451312..19941da7a 100644 --- a/back/requirements-deploy.txt +++ b/back/requirements-deploy.txt @@ -1,4 +1,5 @@ google-cloud-logging==3.11.3 opentelemetry-sdk==1.27.0 -opentelemetry-exporter-otlp-proto-http==1.27.0 opentelemetry-instrumentation-flask==0.48b0 +opentelemetry-exporter-gcp-trace==1.7.0 +opentelemetry-propagator-gcp==1.7.0