mirror of
https://github.com/open-telemetry/opentelemetry-python-contrib.git
synced 2026-03-13 08:10:39 +08:00
opentelemetry-instrumentation-django: improve docs for response_hook with examples of providing attributes from middlewares (#3923)
* instrumentation/django: improve docs for response hooks * changelog * modify new sections as subsections under "Request and Response hooks" --------- Co-authored-by: Tammy Baylis <96076570+tammy-baylis-swi@users.noreply.github.com> Co-authored-by: Riccardo Magliocchetti <riccardo.magliocchetti@gmail.com>
This commit is contained in:
@@ -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))
|
||||
- Update for Log SDK breaking changes. Rename InMemoryLogExporter to InMemoryLogRecordExporter in several tests
|
||||
([#3850](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3589))
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ For example,
|
||||
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.
|
||||
|
||||
@@ -57,10 +57,10 @@ For example,
|
||||
|
||||
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:
|
||||
@@ -77,8 +77,76 @@ The hooks can be configured as follows:
|
||||
|
||||
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
|
||||
*****************************************
|
||||
|
||||
Reference in New Issue
Block a user