//! Run with //! //! ```not_rust //! cargo run -p example-request-id //! ``` use axum::{ http::{HeaderName, Request}, response::Html, routing::get, Router, }; use tower::ServiceBuilder; use tower_http::{ request_id::{MakeRequestUuid, PropagateRequestIdLayer, SetRequestIdLayer}, trace::TraceLayer, }; use tracing::{error, info, info_span}; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; const REQUEST_ID_HEADER: &str = "x-request-id"; #[tokio::main] async fn main() { tracing_subscriber::registry() .with( tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| { // axum logs rejections from built-in extractors with the `axum::rejection` // target, at `TRACE` level. `axum::rejection=trace` enables showing those events format!( "{}=debug,tower_http=debug,axum::rejection=trace", env!("CARGO_CRATE_NAME") ) .into() }), ) .with(tracing_subscriber::fmt::layer()) .init(); let x_request_id = HeaderName::from_static(REQUEST_ID_HEADER); let middleware = ServiceBuilder::new() .layer(SetRequestIdLayer::new( x_request_id.clone(), MakeRequestUuid, )) .layer( TraceLayer::new_for_http().make_span_with(|request: &Request<_>| { // Log the request id as generated. let request_id = request.headers().get(REQUEST_ID_HEADER); match request_id { Some(request_id) => info_span!( "http_request", request_id = ?request_id, ), None => { error!("could not extract request_id"); info_span!("http_request") } } }), ) // send headers from request to response headers .layer(PropagateRequestIdLayer::new(x_request_id)); // build our application with a route let app = Router::new().route("/", get(handler)).layer(middleware); // run it let listener = tokio::net::TcpListener::bind("127.0.0.1:3000") .await .unwrap(); println!("listening on {}", listener.local_addr().unwrap()); axum::serve(listener, app).await.unwrap(); } async fn handler() -> Html<&'static str> { info!("Hello world!"); Html("