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

如何结合Micrometer的@Observed与B3 Trace ID并注入方法?

关联B3 Trace-ID与Micrometer @Observed方法调用的实现方案

核心思路

要把B3-Trace-ID和@Observed注解生成的观测Span关联,本质是把B3的追踪标识注入到Micrometer的Span上下文或标签中,主要有三种落地方式:


1. 直接给观测Span添加B3标签(快速实现)

在被@Observed注解的方法内部,通过Micrometer的TracerAPI获取当前Span,手动添加B3-Trace-ID标签,这样观测数据里就能直接看到关联的追踪ID。

import io.micrometer.tracing.Tracer;
import io.micrometer.observation.annotation.Observed;
import org.springframework.stereotype.Component;

@Component
public class BusinessService {
    private final Tracer tracer;

    public BusinessService(Tracer tracer) {
        this.tracer = tracer;
    }

    @Observed(name = "order.process")
    public void processOrder(String b3TraceId) {
        // 将B3 Trace-ID绑定到当前观测Span
        if (tracer.currentSpan() != null) {
            tracer.currentSpan().tag("b3.trace.id", b3TraceId);
        }
        // 业务逻辑代码...
    }
}

2. 自动关联到追踪上下文(链路打通)

如果项目集成了Micrometer Tracing的B3适配,可在请求入口(过滤器/拦截器)解析B3头并构建TraceContext,后续@Observed方法生成的Span会自动继承这个Trace-ID,实现网络调用与方法观测链路的完全串联。

import io.micrometer.tracing.TraceContext;
import io.micrometer.tracing.TraceContextBuilder;
import io.micrometer.tracing.Tracer;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;

@Component
public class B3TraceContextFilter implements Filter {
    private final Tracer tracer;

    public B3TraceContextFilter(Tracer tracer) {
        this.tracer = tracer;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
        HttpServletRequest httpReq = (HttpServletRequest) request;
        String b3TraceId = httpReq.getHeader("B3-Trace-ID");
        String b3SpanId = httpReq.getHeader("B3-Span-ID");

        if (b3TraceId != null) {
            // 构建包含B3标识的TraceContext
            TraceContext traceContext = TraceContextBuilder.create()
                    .traceId(b3TraceId)
                    .spanId(b3SpanId != null ? b3SpanId : tracer.nextSpan().context().spanId())
                    .build();
            // 将上下文绑定到当前线程,后续@Observed方法自动复用
            try (Tracer.SpanInScope ignored = tracer.withSpan(tracer.nextSpan(traceContext))) {
                chain.doFilter(request, response);
            }
        } else {
            chain.doFilter(request, response);
        }
    }
}

3. 切面统一处理(批量方法适配)

如果多个@Observed方法都需要关联B3-Trace-ID,可自定义切面拦截所有被@Observed注解的方法,统一注入标签,避免重复代码。

import io.micrometer.tracing.Tracer;
import io.micrometer.observation.annotation.Observed;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

@Aspect
@Component
public class ObservedMethodB3Aspect {
    private final Tracer tracer;

    public ObservedMethodB3Aspect(Tracer tracer) {
        this.tracer = tracer;
    }

    @Before("@annotation(Observed)")
    public void injectB3TraceId(JoinPoint joinPoint) {
        ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attrs != null) {
            HttpServletRequest request = attrs.getRequest();
            String b3TraceId = request.getHeader("B3-Trace-ID");
            if (b3TraceId != null && tracer.currentSpan() != null) {
                tracer.currentSpan().tag("b3.trace.id", b3TraceId);
            }
        }
    }
}

方案选择建议

  • 仅需在观测数据中标记B3 ID:选方法内加标签的方式;
  • 需要打通网络调用与方法观测的完整链路:选入口处绑定TraceContext的方式;
  • 大量方法需要统一处理:选切面方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 19:27:22