Skip to content

Commit fd0dd61

Browse files
committed
Added ability to extract span attributes from django request objects.
OTEL_PYTHON_DJANGO_TRACED_REQUEST_ATTRS env var can be set to a command separated list of attributes names that will be extracted from Django's request object and set as attributes on spans.
1 parent 7636547 commit fd0dd61

File tree

4 files changed

+54
-0
lines changed

4 files changed

+54
-0
lines changed

instrumentation/opentelemetry-instrumentation-django/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Unreleased
44

55
- Changed span name extraction from request to comply semantic convention ([#992](https://github.com/open-telemetry/opentelemetry-python/pull/992))
6+
- Added support for `OTEL_PYTHON_DJANGO_TRACED_REQUEST_ATTRS` ([#1154](https://github.com/open-telemetry/opentelemetry-python/pull/1154))
67

78
## Version 0.13b0
89

instrumentation/opentelemetry-instrumentation-django/README.rst

+13
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,19 @@ For example,
3030

3131
will exclude requests such as ``https://site/client/123/info`` and ``https://site/xyz/healthcheck``.
3232

33+
Request attributes
34+
********************
35+
To extract certain attributes from Django's request object and use them as span attributes, set the environment variable ``OTEL_PYTHON_DJANGO_TRACED_REQUEST_ATTRS`` to a comma
36+
delimited list of request attribute names.
37+
38+
For example,
39+
40+
::
41+
42+
export OTEL_PYTHON_DJANGO_TRACED_REQUEST_ATTRS='path_info,content_type'
43+
44+
will extract path_info and content_type attributes from every traced request and add them as span attritbues.
45+
3346
References
3447
----------
3548

instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware.py

+12
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ class _DjangoMiddleware(MiddlewareMixin):
5858
else:
5959
_excluded_urls = ExcludeList(_excluded_urls)
6060

61+
_traced_request_attrs = [
62+
attr.strip()
63+
for attr in (Configuration().DJANGO_TRACED_REQUEST_ATTRS or "").split(
64+
","
65+
)
66+
]
67+
6168
@staticmethod
6269
def _get_span_name(request):
6370
try:
@@ -95,6 +102,11 @@ def process_request(self, request):
95102
tracer = get_tracer(__name__, __version__)
96103

97104
attributes = collect_request_attributes(environ)
105+
for attr in self._traced_request_attrs:
106+
if hasattr(request, attr):
107+
value = str(getattr(request, attr))
108+
if value:
109+
attributes[attr] = value
98110

99111
span = tracer.start_span(
100112
self._get_span_name(request),

instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py

+28
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
from sys import modules
1616
from unittest.mock import patch
17+
from test.support import EnvironmentVarGuard
1718

1819
from django import VERSION
1920
from django.conf import settings
@@ -174,3 +175,30 @@ def test_span_name_404(self):
174175

175176
span = span_list[0]
176177
self.assertEqual(span.name, "HTTP GET")
178+
179+
def test_traced_request_attrs(self):
180+
with patch(
181+
"opentelemetry.instrumentation.django.middleware._DjangoMiddleware._traced_request_attrs",
182+
[],
183+
):
184+
Client().get("/span_name/1234/", CONTENT_TYPE="test/ct")
185+
span_list = self.memory_exporter.get_finished_spans()
186+
self.assertEqual(len(span_list), 1)
187+
188+
span = span_list[0]
189+
self.assertNotIn("path_info", span.attributes)
190+
self.assertNotIn("content_type", span.attributes)
191+
self.memory_exporter.clear()
192+
193+
with patch(
194+
"opentelemetry.instrumentation.django.middleware._DjangoMiddleware._traced_request_attrs",
195+
["path_info", "content_type", "non_existing_variable"],
196+
):
197+
Client().get("/span_name/1234/", CONTENT_TYPE="test/ct")
198+
span_list = self.memory_exporter.get_finished_spans()
199+
self.assertEqual(len(span_list), 1)
200+
201+
span = span_list[0]
202+
self.assertEqual(span.attributes["path_info"], "/span_name/1234/")
203+
self.assertEqual(span.attributes["content_type"], "test/ct")
204+
self.assertNotIn("non_existing_variable", span.attributes)

0 commit comments

Comments
 (0)