From 1183546712912962544934bd05aaf56751682e51 Mon Sep 17 00:00:00 2001 From: Becky Smith Date: Wed, 20 Mar 2024 11:49:56 +0000 Subject: [PATCH] Add tests for tracing Also moves tracing.py into a services/ directory, and adds it to the coverage paths. --- gunicorn.conf.py | 2 +- justfile | 1 + manage.py | 2 +- pyproject.toml | 3 ++ services/__init__.py | 0 tracing.py => services/tracing.py | 13 ++++--- tests/conftest.py | 6 ++-- tests/test_tracing.py | 60 +++++++++++++++++++++++++++++++ 8 files changed, 78 insertions(+), 9 deletions(-) create mode 100644 services/__init__.py rename tracing.py => services/tracing.py (88%) create mode 100644 tests/test_tracing.py diff --git a/gunicorn.conf.py b/gunicorn.conf.py index f47e8194e..b5cf951b6 100644 --- a/gunicorn.conf.py +++ b/gunicorn.conf.py @@ -1,4 +1,4 @@ -import tracing +import services.tracing as tracing # workers diff --git a/justfile b/justfile index a4fdb1552..96a95081d 100644 --- a/justfile +++ b/justfile @@ -146,6 +146,7 @@ test *ARGS: devenv --cov=local_db \ --cov=tests \ --cov=old_api \ + --cov=services \ --cov-report=html \ --cov-report=term-missing:skip-covered diff --git a/manage.py b/manage.py index 94aa30c85..e543df9c8 100755 --- a/manage.py +++ b/manage.py @@ -4,7 +4,7 @@ import os import sys -import tracing +import services.tracing as tracing def main(): diff --git a/pyproject.toml b/pyproject.toml index aa7cc48f8..04ccc2a27 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,6 +25,9 @@ DJANGO_SETTINGS_MODULE = "airlock.settings" testpaths = [ "tests" ] +filterwarnings = [ + "ignore::DeprecationWarning:opentelemetry.*:", +] [tool.coverage.run] branch = true diff --git a/services/__init__.py b/services/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tracing.py b/services/tracing.py similarity index 88% rename from tracing.py rename to services/tracing.py index 986ed2089..4c2d25cf2 100644 --- a/tracing.py +++ b/services/tracing.py @@ -11,13 +11,11 @@ def get_provider(): # https://github.com/open-telemetry/semantic-conventions/tree/main/docs/resource#service resource = Resource.create( attributes={ - "service.name": "airlock", + "service.name": os.environ.get("OTEL_SERVICE_NAME", "airlock"), "service.namespace": os.environ.get("BACKEND", "unknown"), } ) - provider = TracerProvider(resource=resource) - trace.set_tracer_provider(provider) - return provider + return TracerProvider(resource=resource) def add_exporter(provider, exporter, processor=BatchSpanProcessor): @@ -34,7 +32,7 @@ def add_exporter(provider, exporter, processor=BatchSpanProcessor): provider.add_span_processor(processor(exporter)) -def setup_default_tracing(): +def setup_default_tracing(set_global=True): provider = get_provider() """Inspect environment variables and set up exporters accordingly.""" @@ -49,6 +47,11 @@ def setup_default_tracing(): if "OTEL_EXPORTER_CONSOLE" in os.environ: add_exporter(provider, ConsoleSpanExporter()) + if set_global: # pragma: nocover + trace.set_tracer_provider(provider) + from opentelemetry.instrumentation.auto_instrumentation import ( # noqa: F401 sitecustomize, ) + + return provider diff --git a/tests/conftest.py b/tests/conftest.py index 581898181..936a229f3 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,13 +5,15 @@ from opentelemetry.sdk.trace.export.in_memory_span_exporter import InMemorySpanExporter import airlock.business_logic +import services.tracing as tracing import tests.factories -import tracing # set up tracing for tests +provider = tracing.get_provider() +tracing.trace.set_tracer_provider(provider) test_exporter = InMemorySpanExporter() -tracing.add_exporter(tracing.get_provider(), test_exporter, SimpleSpanProcessor) +tracing.add_exporter(provider, test_exporter, SimpleSpanProcessor) def get_trace(): diff --git a/tests/test_tracing.py b/tests/test_tracing.py new file mode 100644 index 000000000..6dd071012 --- /dev/null +++ b/tests/test_tracing.py @@ -0,0 +1,60 @@ +import os + +import opentelemetry.exporter.otlp.proto.http.trace_exporter +from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter +from opentelemetry.sdk.trace.export import ConsoleSpanExporter + +import services.tracing as tracing + + +def test_setup_default_tracing_empty_env(monkeypatch): + env = {"PYTHONPATH": ""} + monkeypatch.setattr(os, "environ", env) + provider = tracing.setup_default_tracing(set_global=False) + assert provider._active_span_processor._span_processors == () + + +def test_setup_default_tracing_console(monkeypatch): + env = {"PYTHONPATH": "", "OTEL_EXPORTER_CONSOLE": "1"} + monkeypatch.setattr(os, "environ", env) + provider = tracing.setup_default_tracing(set_global=False) + + processor = provider._active_span_processor._span_processors[0] + assert isinstance(processor.span_exporter, ConsoleSpanExporter) + + +def test_setup_default_tracing_otlp_defaults(monkeypatch): + env = {"PYTHONPATH": "", "OTEL_EXPORTER_OTLP_HEADERS": "foo=bar"} + monkeypatch.setattr(os, "environ", env) + monkeypatch.setattr( + opentelemetry.exporter.otlp.proto.http.trace_exporter, "environ", env + ) + provider = tracing.setup_default_tracing(set_global=False) + assert provider.resource.attributes["service.name"] == "airlock" + + exporter = provider._active_span_processor._span_processors[0].span_exporter + assert isinstance(exporter, OTLPSpanExporter) + assert exporter._endpoint == "https://api.honeycomb.io/v1/traces" + assert exporter._headers == {"foo": "bar"} + assert env["OTEL_EXPORTER_OTLP_ENDPOINT"] == "https://api.honeycomb.io" + + +def test_setup_default_tracing_otlp_with_env(monkeypatch): + env = { + "PYTHONPATH": "", + "OTEL_EXPORTER_OTLP_HEADERS": "foo=bar", + "OTEL_SERVICE_NAME": "service", + "OTEL_EXPORTER_OTLP_ENDPOINT": "https://endpoint", + } + monkeypatch.setattr(os, "environ", env) + monkeypatch.setattr( + opentelemetry.exporter.otlp.proto.http.trace_exporter, "environ", env + ) + provider = tracing.setup_default_tracing(set_global=False) + assert provider.resource.attributes["service.name"] == "service" + + exporter = provider._active_span_processor._span_processors[0].span_exporter + + assert isinstance(exporter, OTLPSpanExporter) + assert exporter._endpoint == "https://endpoint/v1/traces" + assert exporter._headers == {"foo": "bar"}