LukeMathWalker/tracing-actix-web

Extracting RootSpan and RequestId in middleware

Closed this issue · 3 comments

In my system I allow users to provide and X-Request-ID and I always respond with an X-Request-ID, either the one they provided or one generated by the API, both for system wide tracing and correlating user errors to internal diagnostics. To do this I've reached into what is currently internal/private information of TracingLogger and wondered about exposing that officially.

To record the external request id, I need the root span in my middleware, which can't be done with FromRequest, since it can't be called withServiceRequest and it does not expose its internals. So I currently do this:

pub fn get_root_span_from_service_request(req: &ServiceRequest) -> RootSpan {
    req.extensions()
        .get::<RootSpan>()
        .cloned()
        .expect("No RootSpan in request. This is a bug")
}

although I'd suggest it as a member on RootSpan:

impl RootSpan {
   // ...
    pub fn from_service_request(req: &ServiceRequest) -> RootSpan {
        req.extensions()
            .get::<RootSpan>()
            .cloned()
            .expect("No root span in request. This is a bug")
    }
}

To get at the request_id from tracing logger to add to my response headers i extract it with tracing_actix_web::root_span_macro::private::get_request_id which I would propose exposing as

impl RequestId {
  // ...
  pub fn from_service_request(req: &ServiceRequest) -> RequestId {
        req.extensions()
            .get::<RequestId>()
            .cloned()
            .expect("No RequestId in request. This is a bug."})
    }
}

If these changes sound useful, I'll create a PR.

I have a very similar use-case, except request id is returned in the body. Would love for this to be possible.

I've implemented this on a branch on my fork to make sure it would do what I intended.

https://github.com/sdether/tracing-actix-web/tree/issue_84_from_servicerequest

Need to make some time to submit a PR with the changes

I've added an extract method on ServiceRequest directly.
You can now do:

service_request.extract::<RequestId>().await;