From 5b8e8b2fa7e3165676f56c6fd4a9019c9a41878c Mon Sep 17 00:00:00 2001 From: Michael Manganiello Date: Mon, 25 Oct 2021 13:14:47 -0300 Subject: [PATCH] django: Fix carrier usage on ASGI requests (#767) * django: Fix carrier usage on ASGI requests For ASGI requests, we must use `request.scope` instead of `request.META`. This is because `ASGIGetter` retrieves the `headers` key from the carrier [0], which is only present in `request.scope`. [0] https://github.com/open-telemetry/opentelemetry-python-contrib/blob/main/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py#L133 * Add unit tests --- CHANGELOG.md | 2 ++ .../instrumentation/django/middleware.py | 2 +- .../tests/test_middleware.py | 31 ++++++++++++++++++- .../tests/test_middleware_asgi.py | 24 ++++++++++++++ 4 files changed, 57 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5afb9f39ba..941fa396f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#766](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/766)) - `opentelemetry-instrumentation-falcon` Dropped broken support for Python 3.4. ([#774](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/774)) +- `opentelemetry-instrumentation-django` Fixed carrier usage on ASGI requests. + ([#767](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/767)) ## [1.6.2-0.25b2](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.6.2-0.25b2) - 2021-10-19 diff --git a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware.py b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware.py index 114f6f4a51..91af787c28 100644 --- a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware.py +++ b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware.py @@ -184,7 +184,7 @@ def process_request(self, request): carrier_getter = wsgi_getter collect_request_attributes = wsgi_collect_request_attributes - token = attach(extract(request_meta, getter=carrier_getter)) + token = attach(extract(carrier, getter=carrier_getter)) span = self._tracer.start_span( self._get_span_name(request), diff --git a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py index 99ee57da84..0b90a9bb7c 100644 --- a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py +++ b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py @@ -31,10 +31,16 @@ ) from opentelemetry.sdk import resources from opentelemetry.sdk.trace import Span +from opentelemetry.sdk.trace.id_generator import RandomIdGenerator from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.test.test_base import TestBase from opentelemetry.test.wsgitestutil import WsgiTestBase -from opentelemetry.trace import SpanKind, StatusCode +from opentelemetry.trace import ( + SpanKind, + StatusCode, + format_span_id, + format_trace_id, +) from opentelemetry.util.http import get_excluded_urls, get_traced_request_attrs # pylint: disable=import-error @@ -331,6 +337,29 @@ def response_hook(span, request, response): self.assertIsInstance(response_hook_args[2], HttpResponse) self.assertEqual(response_hook_args[2], response) + async def test_trace_parent(self): + id_generator = RandomIdGenerator() + trace_id = format_trace_id(id_generator.generate_trace_id()) + span_id = format_span_id(id_generator.generate_span_id()) + traceparent_value = f"00-{trace_id}-{span_id}-01" + + Client().get( + "/span_name/1234/", traceparent=traceparent_value, + ) + span = self.memory_exporter.get_finished_spans()[0] + + self.assertEqual( + trace_id, format_trace_id(span.get_span_context().trace_id), + ) + self.assertIsNotNone(span.parent) + self.assertEqual( + trace_id, format_trace_id(span.parent.trace_id), + ) + self.assertEqual( + span_id, format_span_id(span.parent.span_id), + ) + self.memory_exporter.clear() + def test_trace_response_headers(self): response = Client().get("/span_name/1234/") diff --git a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py index d1f578ccc8..0bac1c7243 100644 --- a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py +++ b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py @@ -32,6 +32,7 @@ ) from opentelemetry.sdk import resources from opentelemetry.sdk.trace import Span +from opentelemetry.sdk.trace.id_generator import RandomIdGenerator from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.test.test_base import TestBase from opentelemetry.trace import ( @@ -317,6 +318,29 @@ def response_hook(span, request, response): self.assertIsInstance(response_hook_args[2], HttpResponse) self.assertEqual(response_hook_args[2], response) + async def test_trace_parent(self): + id_generator = RandomIdGenerator() + trace_id = format_trace_id(id_generator.generate_trace_id()) + span_id = format_span_id(id_generator.generate_span_id()) + traceparent_value = f"00-{trace_id}-{span_id}-01" + + await self.async_client.get( + "/span_name/1234/", traceparent=traceparent_value, + ) + span = self.memory_exporter.get_finished_spans()[0] + + self.assertEqual( + trace_id, format_trace_id(span.get_span_context().trace_id), + ) + self.assertIsNotNone(span.parent) + self.assertEqual( + trace_id, format_trace_id(span.parent.trace_id), + ) + self.assertEqual( + span_id, format_span_id(span.parent.span_id), + ) + self.memory_exporter.clear() + async def test_trace_response_headers(self): response = await self.async_client.get("/span_name/1234/")