要让 spring boot 全局异常处理与 sleuth/zipkin 无缝结合,关键在于异常时保留 trace 上下文、日志自动携带 traceid/spanid、手动标记 span 为 error 并 finish,配置 logback mdc 透传,网关/dubbo/异步场景需额外保障上下文延续。

要让 Spring Boot 的全局异常处理和 Sleuth/Zipkin 链路追踪真正“无缝结合”,关键不是把两者堆在一起,而是让异常信息自动带上 Trace ID,并能被日志、监控、告警系统统一消费。核心在于:异常发生时,Trace 上下文不能丢失;异常日志必须携带 traceId 和 spanId;异常数据要能被 Zipkin 捕获并标记为 error。
统一异常处理器中注入 Trace 上下文
Spring Boot 的 @ControllerAdvice 全局异常处理器默认不感知 Sleuth 上下文。需主动从当前 Span 中提取 traceId、spanId,并注入到返回体和日志中:
- 使用
Tracer.currentSpan()获取当前活跃 Span(注意判空,异步或无 trace 场景可能为 null) - 在自定义返回对象(如
Result<t></t>)中显式设置traceId字段,值来自currentSpan().context().traceIdString() - 记录 ERROR 级别日志时,用
log.error("业务异常: {}", msg, e)—— Sleuth 的 Logback 配置已自动将 MDC 中的 traceId/spanId 注入日志行
确保异常 Span 被正确标记为 error
Sleuth 默认不会自动将异常传播为 Span 的 error 标签,需手动增强:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 在异常处理器中调用
tracer.currentSpan().tag("error", e.getClass().getSimpleName()) - 补充关键标签如
"error.message"、"error.stack"(注意截断避免日志爆炸) - 调用
tracer.currentSpan().finish()显式结束 Span(尤其当异常中断正常流程时)
Logback 配置支持 MDC 自动透传
日志格式必须包含 MDC 中的追踪字段,否则异常日志就“脱链”了。在 logback-spring.xml 中配置 pattern:
%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{traceId:-},%X{spanId:-}] [%thread] %-5level %logger{36} - %msg%n
其中 %X{traceId:-} 表示从 MDC 取 traceId,缺失时显示空字符串。该机制由 Sleuth 自动填充,无需手动 put。
网关与 Dubbo 场景下的上下文延续
若项目含 API 网关(如 Spring Cloud Gateway)或 Dubbo 服务,需额外保障异常路径不中断链路:
- 网关层:启用
spring.cloud.gateway.filter.rewrite-location.enabled=true并确认TraceWebFilter生效,确保异常响应头仍携带X-B3-TraceId - Dubbo 层:引入
brave-instrumentation-dubbo,它会自动在 RPC 异常抛出前将 error tag 写入当前 Span - 跨线程场景(如异步任务、定时任务):使用
@Async时务必搭配TraceableExecutorService,否则 MDC 会丢失










