What problem do you want to solve?
The current Django instrumentation uses a Middleware to open and close spans. While this works perfectly for standard HTTP responses, it falls short for StreamingHttpResponse.
Because streaming responses continue to process and send data after the middleware chain has finished executing, the request lifecycle is not properly traced, leading to incomplete or inaccurate span durations.
Describe the solution you'd like
A way to solve this is to hook into the response's close() method, which Django guarantees will be called after the stream finishes. We can wrap the original close method to ensure the span is ended at the very end of the response lifecycle.
This approach would gracefully handle both regular and StreamingHttpResponse objects.
Here is a conceptual implementation:
original_close = response.close
def close_span():
try:
original_close()
finally:
# TODO: End the span here
response.close = close_span
Note: I haven't fully tested this with async responses under ASGI yet, where response.close might be executed via sync_to_async.
Describe alternatives you've considered
Another option would be listening to Django's built-in request_finished signal. However, this signal doesn't always carry the exact context of the specific request/response object as cleanly as wrapping the response itself, and might make correlation trickier in concurrent environments.
Additional Context
No response
Would you like to implement a fix?
Yes
Tip
React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding +1 or me too, to help us triage it. Learn more here.
What problem do you want to solve?
The current Django instrumentation uses a Middleware to open and close spans. While this works perfectly for standard HTTP responses, it falls short for StreamingHttpResponse.
Because streaming responses continue to process and send data after the middleware chain has finished executing, the request lifecycle is not properly traced, leading to incomplete or inaccurate span durations.
Describe the solution you'd like
A way to solve this is to hook into the response's
close()method, which Django guarantees will be called after the stream finishes. We can wrap the original close method to ensure the span is ended at the very end of the response lifecycle.This approach would gracefully handle both regular and StreamingHttpResponse objects.
Here is a conceptual implementation:
Note: I haven't fully tested this with async responses under ASGI yet, where
response.closemight be executed viasync_to_async.Describe alternatives you've considered
Another option would be listening to Django's built-in
request_finishedsignal. However, this signal doesn't always carry the exact context of the specific request/response object as cleanly as wrapping the response itself, and might make correlation trickier in concurrent environments.Additional Context
No response
Would you like to implement a fix?
Yes
Tip
React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding
+1orme too, to help us triage it. Learn more here.