From 6e503c71c205b98afcc4f85ee6b2b0654f22fafa Mon Sep 17 00:00:00 2001 From: Lukas Hering Date: Thu, 25 Dec 2025 01:44:06 -0500 Subject: [PATCH 1/2] refactor: remove usage of deprecated SpanAttributes where applicable --- CHANGELOG.md | 2 + .../django/middleware/otel_middleware.py | 12 ++- .../tests/test_middleware_asgi.py | 95 +++++++++---------- 3 files changed, 55 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cf8b6d504..3672a1c44c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -116,6 +116,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#3681](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3681)) - `opentelemetry-instrumentation-flask`: Fix exemplars generation for `http.server.request.duration` and `http.server.duration` metrics ([#3912](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3912)) +- `opentelemetry-instrumentation-django`: Replace SpanAttributes with semconv constants where applicable + ([#4059](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/4059)) ### Added diff --git a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/otel_middleware.py b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/otel_middleware.py index 418a7fd433..438692a93c 100644 --- a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/otel_middleware.py +++ b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/otel_middleware.py @@ -53,8 +53,10 @@ from opentelemetry.instrumentation.wsgi import ( collect_request_attributes as wsgi_collect_request_attributes, ) +from opentelemetry.semconv._incubating.attributes.http_attributes import ( + HTTP_TARGET, +) from opentelemetry.semconv.attributes.http_attributes import HTTP_ROUTE -from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.trace import Span, SpanKind, use_span from opentelemetry.util.http import ( OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS, @@ -320,12 +322,12 @@ def process_view(self, request, view_func, *args, **kwargs): if route: if span.is_recording(): # http.route is present for both old and new semconv - span.set_attribute(SpanAttributes.HTTP_ROUTE, route) + span.set_attribute(HTTP_ROUTE, route) duration_attrs = request.META[ self._environ_duration_attr_key ] if _report_old(self._sem_conv_opt_in_mode): - duration_attrs[SpanAttributes.HTTP_TARGET] = route + duration_attrs[HTTP_TARGET] = route if _report_new(self._sem_conv_opt_in_mode): duration_attrs[HTTP_ROUTE] = route @@ -424,9 +426,9 @@ def process_response(self, request, response): duration_attrs, _StabilityMode.DEFAULT ) # http.target to be included in old semantic conventions - target = duration_attrs.get(SpanAttributes.HTTP_TARGET) + target = duration_attrs.get(HTTP_TARGET) if target: - duration_attrs_old[SpanAttributes.HTTP_TARGET] = target + duration_attrs_old[HTTP_TARGET] = target self._duration_histogram_old.record( max(round(duration_s * 1000), 0), duration_attrs_old, diff --git a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py index a527f404b2..f2e3bd5109 100644 --- a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py +++ b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py @@ -39,6 +39,12 @@ from opentelemetry.sdk import resources from opentelemetry.sdk.trace import Span from opentelemetry.sdk.trace.id_generator import RandomIdGenerator +from opentelemetry.semconv._incubating.attributes.http_attributes import ( + HTTP_METHOD, + HTTP_SCHEME, + HTTP_STATUS_CODE, + HTTP_URL, +) from opentelemetry.semconv.attributes.client_attributes import CLIENT_ADDRESS from opentelemetry.semconv.attributes.exception_attributes import ( EXCEPTION_MESSAGE, @@ -55,7 +61,6 @@ ) from opentelemetry.semconv.attributes.server_attributes import SERVER_PORT from opentelemetry.semconv.attributes.url_attributes import URL_SCHEME -from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.test.test_base import TestBase from opentelemetry.trace import ( SpanKind, @@ -171,17 +176,17 @@ async def test_templated_route_get(self): self.assertEqual(span.name, "GET ^route/(?P[0-9]{4})/template/$") self.assertEqual(span.kind, SpanKind.SERVER) self.assertEqual(span.status.status_code, StatusCode.UNSET) - self.assertEqual(span.attributes[SpanAttributes.HTTP_METHOD], "GET") + self.assertEqual(span.attributes[HTTP_METHOD], "GET") self.assertEqual( - span.attributes[SpanAttributes.HTTP_URL], + span.attributes[HTTP_URL], "http://testserver/route/2020/template/", ) self.assertEqual( - span.attributes[SpanAttributes.HTTP_ROUTE], + span.attributes[HTTP_ROUTE], "^route/(?P[0-9]{4})/template/$", ) - self.assertEqual(span.attributes[SpanAttributes.HTTP_SCHEME], "http") - self.assertEqual(span.attributes[SpanAttributes.HTTP_STATUS_CODE], 200) + self.assertEqual(span.attributes[HTTP_SCHEME], "http") + self.assertEqual(span.attributes[HTTP_STATUS_CODE], 200) async def test_templated_route_get_new_semconv(self): await self.async_client.get("/route/2020/template/") @@ -216,13 +221,13 @@ async def test_templated_route_get_both_semconv(self): self.assertEqual(span.name, "GET ^route/(?P[0-9]{4})/template/$") self.assertEqual(span.kind, SpanKind.SERVER) self.assertEqual(span.status.status_code, StatusCode.UNSET) - self.assertEqual(span.attributes[SpanAttributes.HTTP_METHOD], "GET") + self.assertEqual(span.attributes[HTTP_METHOD], "GET") self.assertEqual( - span.attributes[SpanAttributes.HTTP_URL], + span.attributes[HTTP_URL], "http://testserver/route/2020/template/", ) - self.assertEqual(span.attributes[SpanAttributes.HTTP_SCHEME], "http") - self.assertEqual(span.attributes[SpanAttributes.HTTP_STATUS_CODE], 200) + self.assertEqual(span.attributes[HTTP_SCHEME], "http") + self.assertEqual(span.attributes[HTTP_STATUS_CODE], 200) self.assertEqual(span.attributes[HTTP_REQUEST_METHOD], "GET") self.assertEqual(span.attributes[SERVER_PORT], 80) self.assertEqual(span.attributes[CLIENT_ADDRESS], "127.0.0.1") @@ -245,16 +250,14 @@ async def test_traced_get(self): self.assertEqual(span.name, "GET ^traced/") self.assertEqual(span.kind, SpanKind.SERVER) self.assertEqual(span.status.status_code, StatusCode.UNSET) - self.assertEqual(span.attributes[SpanAttributes.HTTP_METHOD], "GET") + self.assertEqual(span.attributes[HTTP_METHOD], "GET") self.assertEqual( - span.attributes[SpanAttributes.HTTP_URL], + span.attributes[HTTP_URL], "http://testserver/traced/", ) - self.assertEqual( - span.attributes[SpanAttributes.HTTP_ROUTE], "^traced/" - ) - self.assertEqual(span.attributes[SpanAttributes.HTTP_SCHEME], "http") - self.assertEqual(span.attributes[SpanAttributes.HTTP_STATUS_CODE], 200) + self.assertEqual(span.attributes[HTTP_ROUTE], "^traced/") + self.assertEqual(span.attributes[HTTP_SCHEME], "http") + self.assertEqual(span.attributes[HTTP_STATUS_CODE], 200) async def test_traced_get_new_semconv(self): await self.async_client.get("/traced/") @@ -286,13 +289,13 @@ async def test_traced_get_both_semconv(self): self.assertEqual(span.name, "GET ^traced/") self.assertEqual(span.kind, SpanKind.SERVER) self.assertEqual(span.status.status_code, StatusCode.UNSET) - self.assertEqual(span.attributes[SpanAttributes.HTTP_METHOD], "GET") + self.assertEqual(span.attributes[HTTP_METHOD], "GET") self.assertEqual( - span.attributes[SpanAttributes.HTTP_URL], + span.attributes[HTTP_URL], "http://testserver/traced/", ) - self.assertEqual(span.attributes[SpanAttributes.HTTP_SCHEME], "http") - self.assertEqual(span.attributes[SpanAttributes.HTTP_STATUS_CODE], 200) + self.assertEqual(span.attributes[HTTP_SCHEME], "http") + self.assertEqual(span.attributes[HTTP_STATUS_CODE], 200) self.assertEqual(span.attributes[HTTP_REQUEST_METHOD], "GET") self.assertEqual(span.attributes[URL_SCHEME], "http") self.assertEqual(span.attributes[SERVER_PORT], 80) @@ -325,16 +328,14 @@ async def test_traced_post(self): self.assertEqual(span.name, "POST ^traced/") self.assertEqual(span.kind, SpanKind.SERVER) self.assertEqual(span.status.status_code, StatusCode.UNSET) - self.assertEqual(span.attributes[SpanAttributes.HTTP_METHOD], "POST") + self.assertEqual(span.attributes[HTTP_METHOD], "POST") self.assertEqual( - span.attributes[SpanAttributes.HTTP_URL], + span.attributes[HTTP_URL], "http://testserver/traced/", ) - self.assertEqual( - span.attributes[SpanAttributes.HTTP_ROUTE], "^traced/" - ) - self.assertEqual(span.attributes[SpanAttributes.HTTP_SCHEME], "http") - self.assertEqual(span.attributes[SpanAttributes.HTTP_STATUS_CODE], 200) + self.assertEqual(span.attributes[HTTP_ROUTE], "^traced/") + self.assertEqual(span.attributes[HTTP_SCHEME], "http") + self.assertEqual(span.attributes[HTTP_STATUS_CODE], 200) async def test_traced_post_new_semconv(self): await self.async_client.post("/traced/") @@ -366,13 +367,13 @@ async def test_traced_post_both_semconv(self): self.assertEqual(span.name, "POST ^traced/") self.assertEqual(span.kind, SpanKind.SERVER) self.assertEqual(span.status.status_code, StatusCode.UNSET) - self.assertEqual(span.attributes[SpanAttributes.HTTP_METHOD], "POST") + self.assertEqual(span.attributes[HTTP_METHOD], "POST") self.assertEqual( - span.attributes[SpanAttributes.HTTP_URL], + span.attributes[HTTP_URL], "http://testserver/traced/", ) - self.assertEqual(span.attributes[SpanAttributes.HTTP_SCHEME], "http") - self.assertEqual(span.attributes[SpanAttributes.HTTP_STATUS_CODE], 200) + self.assertEqual(span.attributes[HTTP_SCHEME], "http") + self.assertEqual(span.attributes[HTTP_STATUS_CODE], 200) self.assertEqual(span.attributes[HTTP_REQUEST_METHOD], "POST") self.assertEqual(span.attributes[URL_SCHEME], "http") self.assertEqual(span.attributes[SERVER_PORT], 80) @@ -393,24 +394,20 @@ async def test_error(self): self.assertEqual(span.name, "GET ^error/") self.assertEqual(span.kind, SpanKind.SERVER) self.assertEqual(span.status.status_code, StatusCode.ERROR) - self.assertEqual(span.attributes[SpanAttributes.HTTP_METHOD], "GET") + self.assertEqual(span.attributes[HTTP_METHOD], "GET") self.assertEqual( - span.attributes[SpanAttributes.HTTP_URL], + span.attributes[HTTP_URL], "http://testserver/error/", ) - self.assertEqual(span.attributes[SpanAttributes.HTTP_ROUTE], "^error/") - self.assertEqual(span.attributes[SpanAttributes.HTTP_SCHEME], "http") - self.assertEqual(span.attributes[SpanAttributes.HTTP_STATUS_CODE], 500) + self.assertEqual(span.attributes[HTTP_ROUTE], "^error/") + self.assertEqual(span.attributes[HTTP_SCHEME], "http") + self.assertEqual(span.attributes[HTTP_STATUS_CODE], 500) self.assertEqual(len(span.events), 1) event = span.events[0] self.assertEqual(event.name, "exception") - self.assertEqual( - event.attributes[SpanAttributes.EXCEPTION_TYPE], "ValueError" - ) - self.assertEqual( - event.attributes[SpanAttributes.EXCEPTION_MESSAGE], "error" - ) + self.assertEqual(event.attributes[EXCEPTION_TYPE], "ValueError") + self.assertEqual(event.attributes[EXCEPTION_MESSAGE], "error") async def test_error_new_semconv(self): with self.assertRaises(ValueError): @@ -447,14 +444,14 @@ async def test_error_both_semconv(self): self.assertEqual(span.name, "GET ^error/") self.assertEqual(span.kind, SpanKind.SERVER) self.assertEqual(span.status.status_code, StatusCode.ERROR) - self.assertEqual(span.attributes[SpanAttributes.HTTP_METHOD], "GET") + self.assertEqual(span.attributes[HTTP_METHOD], "GET") self.assertEqual( - span.attributes[SpanAttributes.HTTP_URL], + span.attributes[HTTP_URL], "http://testserver/error/", ) - self.assertEqual(span.attributes[SpanAttributes.HTTP_ROUTE], "^error/") - self.assertEqual(span.attributes[SpanAttributes.HTTP_SCHEME], "http") - self.assertEqual(span.attributes[SpanAttributes.HTTP_STATUS_CODE], 500) + self.assertEqual(span.attributes[HTTP_ROUTE], "^error/") + self.assertEqual(span.attributes[HTTP_SCHEME], "http") + self.assertEqual(span.attributes[HTTP_STATUS_CODE], 500) self.assertEqual(span.attributes[HTTP_REQUEST_METHOD], "GET") self.assertEqual(span.attributes[HTTP_ROUTE], "^error/") self.assertEqual(span.attributes[URL_SCHEME], "http") @@ -544,7 +541,7 @@ async def test_nonstandard_http_method_span_name_both_semconv(self): span = span_list[0] self.assertEqual(span.name, "HTTP") - self.assertEqual(span.attributes[SpanAttributes.HTTP_METHOD], "_OTHER") + self.assertEqual(span.attributes[HTTP_METHOD], "_OTHER") self.assertEqual(span.attributes[HTTP_REQUEST_METHOD], "_OTHER") self.assertEqual( span.attributes[HTTP_REQUEST_METHOD_ORIGINAL], "NONSTANDARD" From 8495b24934cb7cb1f5610410207aea826c787c6d Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Mon, 29 Dec 2025 12:00:31 +0100 Subject: [PATCH 2/2] Update CHANGELOG.md --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ed63c428d..973f9c2c7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#3956](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3956)) - `opentelemetry-instrumentation-dbapi`: Replace SpanAttributes with semconv constants where applicable ([#4058](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/4058)) +- `opentelemetry-instrumentation-django`: Replace SpanAttributes with semconv constants where applicable + ([#4059](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/4059)) ## Version 1.39.0/0.60b0 (2025-12-03) @@ -118,8 +120,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#3681](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3681)) - `opentelemetry-instrumentation-flask`: Fix exemplars generation for `http.server.request.duration` and `http.server.duration` metrics ([#3912](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3912)) -- `opentelemetry-instrumentation-django`: Replace SpanAttributes with semconv constants where applicable - ([#4059](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/4059)) ### Added