如何在trace crate的on_failure回调中检查响应状态码?
解决方案
要实现只在"失败场景"中检查客户端错误并处理,你需要完成两步核心操作:自定义失败分类规则,以及在on_failure回调中处理目标逻辑。
1. 自定义失败分类规则
tower_http的TraceLayer默认仅将5xx服务器错误判定为失败以触发on_failure回调。我们需要修改分类逻辑,让4xx客户端错误也被纳入失败触发范围:
use tower_http::classify::ClassifyResponse; // 自定义分类器:将4xx客户端错误和5xx服务器错误都视为失败 struct ClientAndServerErrorsAsFailures; impl ClassifyResponse for ClientAndServerErrorsAsFailures { type FailureClass = (); type ClassifyEos = (); fn classify_response<B>(&self, res: &http::Response<B>) -> Result<(), Self::FailureClass> { if res.status().is_client_error() || res.status().is_server_error() { Err(()) } else { Ok(()) } } fn classify_eos(&self, _: Result<(), std::io::Error>) -> Result<(), Self::FailureClass> { Ok(()) } fn into_inner(self) -> Self { self } }
2. 配置TraceLayer使用on_failure回调
接下来调整TraceLayer的初始化逻辑,使用自定义分类器,并在on_failure中完成客户端错误的检查、警告记录,以及将追踪标记为无错误的操作:
let trace_layer = TraceLayer::new(ClientAndServerErrorsAsFailures) .on_failure(|_failure, response, _duration, span| { // 仅当响应存在且为客户端错误时执行目标逻辑 if let Some(response) = response { if response.status().is_client_error() { warn!(parent: span, "ControlPlane.http_request_trace warning: {}", response.status()); // 将追踪span标记为无错误,避免被归类为失败追踪 span.record("otel.status_code", "OK"); span.record("status_code", response.status().as_str()); } } }) .make_span_with(|request: &Request<_>| { tracing::info_span!( "ControlPlane.http_request_trace", method = %request.method(), uri = %request.uri(), otel.status_code = "OK", // 默认标记为成功状态 ) });
关键说明
- 自定义分类器确保只有4xx/5xx错误会触发
on_failure,避免无意义地遍历所有响应; on_failure回调中的response参数仅在响应被判定为失败时存在,可安全用于状态码检查;- 通过
span.record修改追踪字段(以OpenTelemetry为例),将客户端错误标记为非失败状态,符合业务需求。
内容的提问来源于stack exchange,提问作者Aviral Srivastava
相关产品推荐
相关产品推荐

