Module tower_http::request_id

source ·
Available on crate feature request-id only.
Expand description

Set and propagate request ids.

§Example

use http::{Request, Response, header::HeaderName};
use tower::{Service, ServiceExt, ServiceBuilder};
use tower_http::request_id::{
    SetRequestIdLayer, PropagateRequestIdLayer, MakeRequestId, RequestId,
};
use http_body_util::Full;
use bytes::Bytes;
use std::sync::{Arc, atomic::{AtomicU64, Ordering}};

// A `MakeRequestId` that increments an atomic counter
#[derive(Clone, Default)]
struct MyMakeRequestId {
    counter: Arc<AtomicU64>,
}

impl MakeRequestId for MyMakeRequestId {
    fn make_request_id<B>(&mut self, request: &Request<B>) -> Option<RequestId> {
        let request_id = self.counter
            .fetch_add(1, Ordering::SeqCst)
            .to_string()
            .parse()
            .unwrap();

        Some(RequestId::new(request_id))
    }
}

let x_request_id = HeaderName::from_static("x-request-id");

let mut svc = ServiceBuilder::new()
    // set `x-request-id` header on all requests
    .layer(SetRequestIdLayer::new(
        x_request_id.clone(),
        MyMakeRequestId::default(),
    ))
    // propagate `x-request-id` headers from request to response
    .layer(PropagateRequestIdLayer::new(x_request_id))
    .service(handler);

let request = Request::new(Full::default());
let response = svc.ready().await?.call(request).await?;

assert_eq!(response.headers()["x-request-id"], "0");

Additional convenience methods are available on ServiceBuilderExt:

use tower_http::ServiceBuilderExt;

let mut svc = ServiceBuilder::new()
    .set_x_request_id(MyMakeRequestId::default())
    .propagate_x_request_id()
    .service(handler);

let request = Request::new(Full::default());
let response = svc.ready().await?.call(request).await?;

assert_eq!(response.headers()["x-request-id"], "0");

See SetRequestId and PropagateRequestId for more details.

§Using Trace

To have request ids show up correctly in logs produced by Trace you must apply the layers in this order:

use tower_http::{
    ServiceBuilderExt,
    trace::{TraceLayer, DefaultMakeSpan, DefaultOnResponse},
};

let svc = ServiceBuilder::new()
    // make sure to set request ids before the request reaches `TraceLayer`
    .set_x_request_id(MyMakeRequestId::default())
    // log requests and responses
    .layer(
        TraceLayer::new_for_http()
            .make_span_with(DefaultMakeSpan::new().include_headers(true))
            .on_response(DefaultOnResponse::new().include_headers(true))
    )
    // propagate the header to the response before the response reaches `TraceLayer`
    .propagate_x_request_id()
    .service(handler);

§Doesn’t override existing headers

SetRequestId and PropagateRequestId wont override request ids if its already present on requests or responses. Among other things, this allows other middleware to conditionally set request ids and use the middleware in this module as a fallback.

Structs§

Traits§