You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 21:03:15