如何用Axum正确过滤请求日志?解决日志详情丢失问题
解决Axum请求日志过滤后丢失详情的问题
问题原因
你设置的过滤规则仅允许tower_http::trace::on_request和tower_http::trace::on_response的TRACE级别日志通过,但请求方法、URI、参数等核心信息是附加在tracing span上的——这些span的默认级别是DEBUG,且对应的target是tower_http::trace而非单独的on_request/on_response,因此被你的过滤规则拦截,导致详情丢失。
解决方案
调整过滤规则,允许tower_http::trace整体的DEBUG及以上级别日志,同时自定义TraceLayer的span和事件级别,确保核心信息被保留,其余冗余日志被过滤。
完整代码示例
use axum::{Router, routing::get}; use tower_http::trace::{TraceLayer, DefaultMakeSpan, DefaultOnRequest, DefaultOnResponse}; use tracing::{Level}; use tracing_subscriber::{fmt, filter::{Targets, LevelFilter}}; async fn hello_img() -> &'static str { "Hello, World!" } #[tokio::main] async fn main() { // 配置过滤规则:允许tower_http::trace的DEBUG及以上,其他默认INFO let filter = Targets::new() .with_target("tower_http::trace", LevelFilter::DEBUG) .with_default(LevelFilter::INFO); // 配置fmt层,显示span事件和核心字段 let tracing_layer = fmt::layer() .with_span_events(fmt::format::FmtSpan::ACTIVE) .with_level(true) .with_target(true); // 初始化订阅者 tracing_subscriber::registry() .with(tracing_layer) .with(filter) .init(); // 自定义TraceLayer,设置span和事件级别 let trace_layer = TraceLayer::new_for_http() // 设置span级别为DEBUG,包含请求方法、URI等信息 .make_span_with(DefaultMakeSpan::new().level(Level::DEBUG)) // 设置请求事件级别为TRACE .on_request(DefaultOnRequest::new().level(Level::TRACE)) // 设置响应事件级别为TRACE .on_response(DefaultOnResponse::new().level(Level::TRACE)); let app = Router::new() .route("/hello", get(hello_img)) .layer(trace_layer); let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 3000)); println!("Listening on {}", addr); axum::Server::bind(&addr) .serve(app.into_make_svc()) .await .unwrap(); }
关键说明
- 过滤规则调整:将
tower_http::trace整体的级别设为DEBUG,确保包含请求详情的span能被输出,同时保持其他日志的默认INFO级别过滤冗余。 - TraceLayer自定义:明确设置span的级别为
DEBUG,请求/响应事件的级别为TRACE,与过滤规则匹配,确保核心信息不丢失。 - fmt层配置:通过
with_span_events开启span事件显示,确保请求方法、URI等span属性被打印到日志中。
内容的提问来源于stack exchange,提问作者Alen Siljak
相关产品推荐
相关产品推荐

