Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `opentelemetry-instrumentation-aiohttp-server`: add support for custom header captures via `OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST` and `OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE`
([#3916](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3916))
- `opentelemetry-instrumentation-redis`: add support for `suppress_instrumentation` context manager for both sync and async Redis clients and pipelines
- `opentelemetry-instrumentation-django`: improve docs for response_hook with examples of providing attributes from middlewares
([#3923](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3923))

### Fixed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
will exclude requests such as ``https://site/client/123/info`` and ``https://site/xyz/healthcheck``.

Request attributes
********************
******************
To extract 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 delimited list of request attribute names.

Expand All @@ -57,10 +57,10 @@

will extract the ``path_info`` and ``content_type`` attributes from every traced request and add them as span attributes.

Django Request object reference: https://docs.djangoproject.com/en/3.1/ref/request-response/#attributes
* `Django Request object reference <https://docs.djangoproject.com/en/5.2/ref/request-response/#attributes>`_

Request and Response hooks
***************************
**************************
This instrumentation supports request and response hooks. These are functions that get called
right after a span is created for a request and right before the span is finished for the response.
The hooks can be configured as follows:
Expand All @@ -77,8 +77,76 @@ def response_hook(span, request, response):

DjangoInstrumentor().instrument(request_hook=request_hook, response_hook=response_hook)

Django Request object: https://docs.djangoproject.com/en/3.1/ref/request-response/#httprequest-objects
Django Response object: https://docs.djangoproject.com/en/3.1/ref/request-response/#httpresponse-objects
* `Django Request object <https://docs.djangoproject.com/en/5.2/ref/request-response/#httprequest-objects>`_
* `Django Response object <https://docs.djangoproject.com/en/5.2/ref/request-response/#httpresponse-objects>`_

Adding attributes from middleware context
#########################################
In many Django applications, certain request attributes become available only *after*
specific middlewares have executed. For example:

- ``django.contrib.auth.middleware.AuthenticationMiddleware`` populates ``request.user``
- ``django.contrib.sites.middleware.CurrentSiteMiddleware`` populates ``request.site``

Because the OpenTelemetry instrumentation creates the span **before** Django middlewares run,
these attributes are **not yet available** in the ``request_hook`` stage.

Therefore, such attributes should be safely attached in the **response_hook**, which executes
after Django finishes processing the request (and after all middlewares have completed).

Example: Attaching the authenticated user and current site to the span:

.. code:: python

def response_hook(span, request, response):
# Attach user information if available
if request.user.is_authenticated:
span.set_attribute("enduser.id", request.user.pk)
span.set_attribute("enduser.username", request.user.get_username())

# Attach current site (if provided by CurrentSiteMiddleware)
if hasattr(request, "site"):
span.set_attribute("site.id", getattr(request.site, "pk", None))
span.set_attribute("site.domain", getattr(request.site, "domain", None))

DjangoInstrumentor().instrument(response_hook=response_hook)

This ensures that middleware-dependent context (like user or site information) is properly
recorded once Django’s middleware stack has finished execution.

Custom Django middleware can also attach arbitrary data to the ``request`` object,
which can later be included as span attributes in the ``response_hook``.

* `Django middleware reference <https://docs.djangoproject.com/en/5.2/topics/http/middleware/>`_

Best practices
##############
- Use **response_hook** (not request_hook) when accessing attributes added by Django middlewares.
- Common middleware-provided attributes include:

- ``request.user`` (AuthenticationMiddleware)
- ``request.site`` (CurrentSiteMiddleware)

- Avoid adding large or sensitive data (e.g., passwords, session tokens, PII) to spans.
- Use **namespaced attribute keys**, e.g., ``enduser.*``, ``site.*``, or ``custom.*``, for clarity.
- Hooks should execute quickly — avoid blocking or long-running operations.
- Hooks can be safely combined with OpenTelemetry **Context propagation** or **Baggage**
for consistent tracing across services.

* `OpenTelemetry semantic conventions <https://opentelemetry.io/docs/specs/semconv/http/http-spans/>`_

Middleware execution order
##########################
In Django’s request lifecycle, the OpenTelemetry `request_hook` is executed before
the first middleware runs. Therefore:

- At `request_hook` time → only the bare `HttpRequest` object is available.
- After middlewares → `request.user`, `request.site` etc. become available.
- At `response_hook` time → all middlewares (including authentication and site middlewares)
have already run, making it the correct place to attach these attributes.

Developers who need to trace attributes from middlewares should always use `response_hook`
to ensure complete and accurate span data.

Capture HTTP request and response headers
*****************************************
Expand Down
Loading