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

Spring Boot 3 OpenTelemetry Trace ID传播及创建机制与源码查询

Trace ID 跨应用传播与Spring/Micrometer源码解析

核心传播机制

Spring Boot 3+的可观测性依赖Micrometer Tracing,底层对接OpenTelemetry或Brave(OpenTracing实现)。Trace ID跨应用传播的本质是通过请求头传递链路上下文——上游应用在请求头中携带Trace ID,下游应用解析头信息并绑定到当前线程的Tracer上下文。

默认Micrometer遵循W3C规范用traceparent头传递,但可以配置适配自定义的x-trace-id。


从x-trace-id提取并绑定上下文的源码位置

1. 请求头解析入口

对于Spring MVC场景,请求链路的入口是org.springframework.web.filter.ServerHttpObservationFilter——这个过滤器会触发Micrometer Tracing的请求解析逻辑。

具体解析请求头的逻辑在io.micrometer.tracing.handler.HttpServerRequestParser的实现类中,默认实现是DefaultHttpServerRequestParser。如果要支持自定义的x-trace-id,要么扩展这个Parser,要么通过配置指定自定义头(下文有配置示例)。

2. 上下文绑定到TracerContext

当解析到x-trace-id后,会构建SpanContext对象,然后通过Tracer的withSpan(Span span)方法将上下文绑定到当前线程的本地变量。

如果用Brave作为底层实现,核心代码在io.micrometer.tracing.brave.bridge.BraveTracer中,withSpan()会调用Brave的CurrentTraceContext完成线程绑定;如果用OpenTelemetry,则对应io.micrometer.tracing.otel.bridge.OtelTracer的实现。


Trace ID的创建逻辑

1. 无传入Trace ID时的自动生成

当请求头中没有携带x-trace-id或标准traceparent时,Micrometer会自动生成新的Trace ID:

  • 生成逻辑由底层Tracer实现提供:Brave用RandomTraceIdGenerator,OpenTelemetry用TraceIdGenerator。
  • 核心触发点在Tracer.nextSpan()方法,比如Brave实现的BraveTracer.nextSpan()会调用Brave原生Tracer生成包含新Trace ID的Span。
  • 默认生成的Trace ID是16字节(32位十六进制字符串),符合W3C规范。

2. 自定义Trace ID生成规则

如果需要自定义Trace ID格式(比如业务前缀、固定长度),可以实现io.micrometer.tracing.TraceIdGenerator接口,然后注册为Spring Bean,Micrometer会自动替换默认生成器。


适配x-trace-id的配置示例

不想改源码的话,直接通过配置或自定义Bean就能支持x-trace-id:

方式1:配置文件指定自定义头

在application.yml中添加:

management:
  tracing:
    propagation:
      type: custom
      custom:
        headers: x-trace-id, x-span-id

方式2:自定义请求解析Bean

如果需要更灵活的逻辑,比如同时兼容traceparent和x-trace-id,可以自定义HttpServerRequestParser:

@Bean
public HttpServerRequestParser customTraceIdParser(Tracer tracer) {
    return (request, context) -> {
        // 优先读取x-trace-id
        String traceId = request.getHeader("x-trace-id");
        String spanId = request.getHeader("x-span-id");
        
        if (traceId != null && spanId != null) {
            SpanContext spanContext = tracer.traceContextBuilder()
                    .traceId(traceId)
                    .spanId(spanId)
                    .build();
            Span span = tracer.nextSpan(spanContext);
            context.setSpan(span);
        }
        // 没有的话走默认逻辑
        else {
            new DefaultHttpServerRequestParser().parse(request, context);
        }
    };
}

内容的提问来源于stack exchange,提问作者cjava

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 09:11:14