Spring Boot 3集成Micrometer/Brave桥接时如何记录W3C ParentId
解决W3C链路追踪中Parent ID的日志输出问题
核心原因
Micrometer 默认仅将 traceId 和 spanId 注入到 MDC(Mapped Diagnostic Context)中,parentId 并不会自动添加进去,所以直接用 [%X{parentId}] 无法获取到值。
解决方案
1. 自定义MdcObservationHandler(Spring Boot环境推荐)
通过扩展Micrometer的MdcObservationHandler,手动将parentId放入MDC:
import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationHandler; import org.slf4j.MDC; import org.springframework.stereotype.Component; @Component public class CustomMdcObservationHandler implements ObservationHandler<Observation.Context> { private static final String PARENT_ID_KEY = "parentId"; @Override public boolean supportsContext(Observation.Context context) { return true; } @Override public void onStart(Observation.Context context) { // 获取当前观测的父Span ID并放入MDC context.getParentObservationId().ifPresent(parentId -> { MDC.put(PARENT_ID_KEY, parentId); }); // 保留原有MDC注入逻辑 new io.micrometer.observation.handler.MdcObservationHandler().onStart(context); } @Override public void onStop(Observation.Context context) { // 清理MDC中的parentId,避免线程复用导致脏数据 MDC.remove(PARENT_ID_KEY); // 保留原有MDC清理逻辑 new io.micrometer.observation.handler.MdcObservationHandler().onStop(context); } }
2. 修改日志配置
完成上述代码后,修改日志格式配置,添加[%X{parentId}]即可:
# Logback示例 logging.pattern.console=Micrometer Trace ID[%X{traceId}] Span [%X{spanId}] Parent [%X{parentId}] %msg%n # Log4j2示例 appender.console.layout.pattern=Micrometer Trace ID[%X{traceId}] Span [%X{spanId}] Parent [%X{parentId}] %msg%n
3. 非Spring Boot环境的处理
如果不是Spring Boot环境,需在创建Span的逻辑中手动将parentId放入MDC:
// 获取父Span并将其ID存入MDC Span parentSpan = ...; Span childSpan = tracer.nextSpan(parentSpan); MDC.put("parentId", parentSpan.context().spanId()); // 业务执行完成后清理并结束Span try (SpanInScope scope = tracer.withSpan(childSpan.start())) { // 业务逻辑代码 } finally { childSpan.end(); MDC.remove("parentId"); }
注意事项
- 必须在Span结束时清理MDC中的
parentId,否则线程池复用会导致后续请求携带错误的父ID。 - 如果使用自定义的ObservationFilter或SpanProcessor,需确保不会覆盖或清除已放入MDC的
parentId。
内容的提问来源于stack exchange,提问作者N4zroth
相关产品推荐
相关产品推荐

