-
Notifications
You must be signed in to change notification settings - Fork 625
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Django: Prepend OpenTelemetry middleware instead of append #1163
Django: Prepend OpenTelemetry middleware instead of append #1163
Conversation
|
Since we have varying opinions about this, should it be made configurable? |
@ebrake could you link to the discussion with arguments against doing this please or list them here if that's not too much trouble? I think this should be the default behavior. Unless there are very good reasons to append in some cases, people who really want it to be appended for whatever reason can may be add the middleware manually instead of using the intrumentor, change the order right after instrumenting or sub-class the instrumentor and change the behavior there. |
Can you explain why the bug in #1160 occurs and how this change solves that? |
@lzchen I think it's because this django tracing middleware is the one responsible for extracting span context from incoming request and start the "local root span" and setting active context. If there is a middleware that executes before this middleware and internally uses another traced library (e.g, mysql) then the spans generated will not be the children of the "local root span" for the incoming HTTP request as the span would not even exist yet. So making the django tracing middleware execute before all other middlewares making the local root span the parent for any spans generated by any other middlewares and eventually by the views. |
@owais |
@owais I read some discussion/arguments here: open-telemetry/opentelemetry-specification#591 - But, django middleware is part of the request/response cycle (invoked on each request, and run through before business logic and the response generated). This change would align with the specifications of spans mentioned here:
In my case, middleware is a part of the same application, making service calls based on the user's session data, location, etc, to provide additional context to business logic, not instrumenting it gives an incomplete picture of how long the request/response has taken. It's executed as a part of the http operation. |
I don't it should be a separate trace. We usually want to trace requests end to end and middlewares are on the critical path for all requests. For example, we may have an authentication middleware which makes some calls to redis, mysql or an external authentication service. Those operations should definitely be part of the trace representing the HTTP request handled by Django. If we don't create the local root span as soon as the request is received then all such operations will not be part of the trace. A django project may contains a number of "applications" but they are just python modules to help organize the codebase and usually a number of different django applications combine and call each other to serve a request. It's no different from micro-services architecture for example, in the sense we may have a number of services but for a single HTTP request, all spans from every single service that did any work to serve a single request should be part of a single trace. |
@ebrake I agree and I'd argue that would be the case for every single django project. Can you think of a use case where this wouldn't hold true wrt Django? |
I don't think this is true. Probably the term application is causing the confusion here since Django calls it's building blocks applications but conceptually, one Django project is a single application and all middlewares are definitely part of the same django application. |
Django middleware is a series of hooks into request/response processing, and a part of the same application. I can't think of anywhere that hasn't held true, in my experience with django development. I have always seen separate "apps" used for models, views, etc. to be more organizable within the same project, or providing additional modules to the application. Agreed, I think the terminology may be confusing! |
Oh maybe I misunderstood the behaviour of middlewares. Are they always only executed based off a request made to the django app? If that's the case then I can see how this makes sense to be all in one trace. However, if the middleware simply executes some logic (ex. initialization) and calls a traced service (mysql) without it being related to any request I don't think that should be part of the same trace correct? |
Yep! It executes based on each request. During the request phase, before calling the view, Django applies middleware in the order it’s defined in MIDDLEWARE, top-down. |
Description
Prepends Django Instrumentation in the middleware (instead of append) so that middleware methods get instrumented, included as spans of the original request and improving overall latency.
Fixes #659
Fixes #1160
Type of change
How Has This Been Tested?
Tested on production, mysql queries in the middleware are now included as spans of the trace, instead of new/separate traces, latency is more accurate.