Skip to content

TraceLayer some requests don't have span attached #655

@juchiast

Description

@juchiast
  • I have looked for existing issues (including closed) about this

Bug Report

Version

0.6.8

Platform

Linux

Description

I'm using tower-http TraceLayer to log axum requests, however, sometime the log doesn't have any span attached to it, for example:

server-1  | 2026-03-07T06:47:27.963867Z DEBUG tower_http::trace::on_request: started processing request
server-1  | 2026-03-07T06:47:27.963959Z DEBUG tower_http::trace::on_response: finished processing request latency=0 ms status=200
server-1  | 2026-03-07T06:47:28.375252Z DEBUG tower_http::trace::on_request: started processing request
server-1  | 2026-03-07T06:47:51.871866Z DEBUG request{method=OPTIONS uri=/v1/game/me/currency/data/balance version=HTTP/1.1}: tower_http::trace::on_request: started processing request
server-1  | 2026-03-07T06:47:51.872013Z DEBUG request{method=OPTIONS uri=/v1/game/me/currency/data/balance version=HTTP/1.1}: tower_http::trace::on_response: finished processing request latency=0 ms status=200
server-1  | 2026-03-07T06:47:53.819640Z DEBUG request{method=GET uri=/v1/game/me/currency/data/balance version=HTTP/1.1}: tower_http::trace::on_request: started processing request
server-1  | 2026-03-07T06:47:54.477762Z DEBUG request{method=OPTIONS uri=/v1/game/me/casual/energy_balance version=HTTP/1.1}: tower_http::trace::on_request: started processing request
server-1  | 2026-03-07T06:47:54.477868Z DEBUG request{method=OPTIONS uri=/v1/game/me/casual/energy_balance version=HTTP/1.1}: tower_http::trace::on_response: finished processing request latency=0 ms status=200
server-1  | 2026-03-07T06:47:55.132684Z DEBUG request{method=GET uri=/v1/game/me/casual/energy_balance version=HTTP/1.1}: tower_http::trace::on_request: started processing request
server-1  | 2026-03-07T06:48:17.030890Z DEBUG tower_http::trace::on_request: started processing request
server-1  | 2026-03-07T06:48:17.030990Z DEBUG tower_http::trace::on_response: finished processing request latency=0 ms status=200
server-1  | 2026-03-07T06:48:17.283262Z DEBUG request{method=POST uri=/v1/game/me/run/start version=HTTP/1.1}: tower_http::trace::on_request: started processing request
server-1  | 2026-03-07T06:54:21.256843Z DEBUG tower_http::trace::on_request: started processing request
server-1  | 2026-03-07T06:54:22.811286Z DEBUG request{method=GET uri=/ version=HTTP/1.1}: tower_http::trace::on_request: started processing request

Lines like this:

server-1  | 2026-03-07T06:48:17.030890Z DEBUG tower_http::trace::on_request: started processing request
server-1  | 2026-03-07T06:48:17.030990Z DEBUG tower_http::trace::on_response: finished processing request latency=0 ms status=200

This is how I configure logging:

pub mod log {
    use std::time::Duration;

    use axum::http::StatusCode;
    use tower_http::trace::{DefaultOnResponse, OnResponse, TraceLayer};
    use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Layer};

    #[derive(Clone)]
    pub struct OnResponseImpl<T> {
        inner: T,
    }

    impl<B, T> OnResponse<B> for OnResponseImpl<T>
    where
        T: OnResponse<B>,
    {
        fn on_response(
            self,
            response: &axum::http::Response<B>,
            latency: Duration,
            span: &tracing::Span,
        ) {
            if response.status() != StatusCode::NOT_FOUND {
                self.inner.on_response(response, latency, span)
            }
        }
    }

    pub fn init_tracing() {
        tracing_subscriber::registry()
            .with(tracing_subscriber::fmt::layer().with_filter(
                EnvFilter::from_default_env().add_directive("tower_http=debug".parse().unwrap()),
            ))
            .init();
    }

    pub fn layer() -> TraceLayer<
        tower_http::classify::SharedClassifier<tower_http::classify::ServerErrorsAsFailures>,
        tower_http::trace::DefaultMakeSpan,
        tower_http::trace::DefaultOnRequest,
        OnResponseImpl<DefaultOnResponse>,
    > {
        TraceLayer::new_for_http().on_response(OnResponseImpl {
            inner: DefaultOnResponse::new(),
        })
    }
}

I have a custom OnResponseImpl to filter out the 404 responses.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions