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 aa0ea393b8..d705ea30a4 100644 --- a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware.py +++ b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware.py @@ -12,9 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +import types from logging import getLogger from time import time -import types from typing import Callable from django.http import HttpRequest, HttpResponse @@ -25,11 +25,11 @@ get_global_response_propagator, ) from opentelemetry.instrumentation.utils import extract_attributes_from_object +from opentelemetry.instrumentation.wsgi import add_response_attributes from opentelemetry.instrumentation.wsgi import ( - add_response_attributes, collect_request_attributes as wsgi_collect_request_attributes, - wsgi_getter, ) +from opentelemetry.instrumentation.wsgi import wsgi_getter from opentelemetry.propagate import extract from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.trace import Span, SpanKind, use_span @@ -54,11 +54,11 @@ ASGIRequest = None try: + from opentelemetry.instrumentation.asgi import asgi_getter from opentelemetry.instrumentation.asgi import ( - asgi_getter, collect_request_attributes as asgi_collect_request_attributes, - set_status_code, ) + from opentelemetry.instrumentation.asgi import set_status_code _is_asgi_supported = True except ImportError: @@ -91,6 +91,10 @@ ] +def _is_asgi_request(request: HttpRequest) -> bool: + return bool(ASGIRequest and isinstance(request, ASGIRequest)) + + class _DjangoMiddleware(MiddlewareMixin): """Django Middleware for OpenTelemetry""" @@ -132,9 +136,6 @@ def _get_span_name(request): except Resolver404: return "HTTP {}".format(request.method) - def _is_asgi_request(self, request): - return ASGIRequest and isinstance(request, ASGIRequest) - def process_request(self, request): # request.META is a dictionary containing all available HTTP headers # Read more about request.META here: @@ -143,7 +144,7 @@ def process_request(self, request): if self._excluded_urls.url_disabled(request.build_absolute_uri("?")): return - is_asgi_request = self._is_asgi_request(request) + is_asgi_request = _is_asgi_request(request) if is_asgi_request and not _is_asgi_supported: return @@ -181,13 +182,17 @@ def process_request(self, request): # contents, for the extract_attributes_from_object function to be able to retrieve # attributes from it. attributes = extract_attributes_from_object( - types.SimpleNamespace(**{ - **request.__dict__, + types.SimpleNamespace( **{ - name.decode('latin1'): value.decode('latin1') - for name, value in request.scope.get('headers', []) - }, - }), + **request.__dict__, + **{ + name.decode("latin1"): value.decode("latin1") + for name, value in request.scope.get( + "headers", [] + ) + }, + } + ), self._traced_request_attrs, attributes, ) @@ -241,9 +246,9 @@ def process_response(self, request, response): if self._excluded_urls.url_disabled(request.build_absolute_uri("?")): return response - is_asgi_request = self._is_asgi_request(request) + is_asgi_request = _is_asgi_request(request) if is_asgi_request and not _is_asgi_supported: - return + return response activation = request.META.pop(self._environ_activation_key, None) span = request.META.pop(self._environ_span_key, None) @@ -254,7 +259,9 @@ def process_response(self, request, response): else: add_response_attributes( span, - "{} {}".format(response.status_code, response.reason_phrase), + "{} {}".format( + response.status_code, response.reason_phrase + ), response, ) diff --git a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py index 07ea388ed5..78e0972657 100644 --- a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py +++ b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py @@ -16,7 +16,6 @@ from unittest.mock import Mock, patch from django import VERSION, conf -from django.conf.urls import url from django.http import HttpRequest, HttpResponse from django.test.client import Client from django.test.utils import setup_test_environment, teardown_test_environment @@ -365,6 +364,7 @@ def test_trace_response_headers(self): class TestMiddlewareWithTracerProvider(TestBase, WsgiTestBase): @classmethod def setUpClass(cls): + conf.settings.configure(ROOT_URLCONF=modules[__name__]) super().setUpClass() def setUp(self): @@ -383,6 +383,11 @@ def tearDown(self): teardown_test_environment() _django_instrumentor.uninstrument() + @classmethod + def tearDownClass(cls): + super().tearDownClass() + conf.settings = conf.LazySettings() + def test_tracer_provider_traced(self): Client().post("/traced/") diff --git a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py index dc9857a52a..36a45c5fc1 100644 --- a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py +++ b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py @@ -15,13 +15,12 @@ from sys import modules from unittest.mock import Mock, patch +import pytest from django import VERSION, conf -from django.conf.urls import url from django.http import HttpRequest, HttpResponse from django.test import SimpleTestCase from django.test.utils import setup_test_environment, teardown_test_environment from django.urls import re_path -import pytest from opentelemetry.instrumentation.django import ( DjangoInstrumentor, @@ -56,11 +55,6 @@ DJANGO_3_1 = VERSION >= (3, 1) -if DJANGO_3_1: - from django.test.client import AsyncClient -else: - AsyncClient = None - urlpatterns = [ re_path(r"^traced/", async_traced), re_path(r"^route/(?P[0-9]{4})/template/$", async_traced_template), @@ -351,6 +345,7 @@ async def test_trace_response_headers(self): class TestMiddlewareAsgiWithTracerProvider(SimpleTestCase, TestBase): @classmethod def setUpClass(cls): + conf.settings.configure(ROOT_URLCONF=modules[__name__]) super().setUpClass() def setUp(self): @@ -369,6 +364,11 @@ def tearDown(self): teardown_test_environment() _django_instrumentor.uninstrument() + @classmethod + def tearDownClass(cls): + super().tearDownClass() + conf.settings = conf.LazySettings() + async def test_tracer_provider_traced(self): await self.async_client.post("/traced/")