Spring Boot 3整合客户端Sentry追踪与Micrometer、OpenTelemetry实现上下文传播
简单说,上下文传播就是把客户端发起请求时生成的追踪元数据(比如Trace ID、Span ID)通过HTTP头传到服务端,服务端不用重新生成全新的Trace,而是把自己的Span挂到客户端的Trace链上,或者直接复用客户端的Trace ID,这样从客户端到服务端的整条调用链路就能在追踪系统里串起来,排查问题时一眼就能看到完整流程。
你这里的情况是客户端用Sentry生成追踪信息,通过sentry-trace(格式是{TraceID}-{SpanID})和baggage(携带环境、版本这类业务元数据的键值对)两个头传递,服务端需要解析这两个头来关联上下文。
你的应用用了Micrometer + OpenTelemetry,所以核心是给OpenTelemetry配置能解析Sentry头的传播器(Propagator),具体步骤如下:
1. 添加必要依赖
需要引入OpenTelemetry SDK、Sentry与OpenTelemetry的集成包,以及Micrometer到OpenTelemetry的桥接包(让Micrometer的追踪数据走OpenTelemetry的链路):
<!-- Maven 依赖,版本请适配你的Spring Boot 3版本 --> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-sdk</artifactId> <version>1.32.0</version> </dependency> <dependency> <groupId>io.sentry</groupId> <artifactId>sentry-opentelemetry</artifactId> <version>6.31.0</version> </dependency> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-tracing-bridge-otel</artifactId> </dependency>
2. 配置OpenTelemetry传播器
创建Spring配置类,把Sentry的传播器注册到OpenTelemetry中,这样应用就能自动解析sentry-trace和baggage头:
import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.trace.SdkTracerProvider; import io.sentry.opentelemetry.SentryPropagator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class SentryOtelConfig { @Bean public OpenTelemetry openTelemetry(SdkTracerProvider tracerProvider) { return OpenTelemetrySdk.builder() .setTracerProvider(tracerProvider) // 注册Sentry传播器,支持解析sentry-trace和baggage .addPropagator(SentryPropagator.getInstance()) .buildAndRegisterGlobal(); } }
如果你的应用同时需要支持W3C标准的traceparent头(比如其他服务用标准格式),可以用CompositeTextMapPropagator组合多个传播器:
import io.opentelemetry.context.propagation.CompositeTextMapPropagator; import io.opentelemetry.sdk.trace.propagation.W3CTraceContextPropagator; // 修改OpenTelemetry构建器的传播器配置: .addPropagator(CompositeTextMapPropagator.of( SentryPropagator.getInstance(), W3CTraceContextPropagator.getInstance() ))
3. Spring Boot 上下文传播配置
Spring Boot 3会自动识别OpenTelemetry的传播器,只需确保以下配置开启:
# application.properties # 启用自定义上下文传播类型 management.tracing.propagation.type=custom # 确保Micrometer桥接OpenTelemetry生效 management.tracing.otel.enabled=true
4. 验证链路关联效果
- 日志验证:在你的日志配置(比如logback.xml)里添加
%X{traceId},查看日志中的Trace ID是否和客户端sentry-trace里的Trace ID一致 - 追踪数据验证:检查OpenTelemetry导出的追踪数据,服务端Span的父Span ID应该等于客户端
sentry-trace里的Span ID,Trace ID完全复用客户端的 - Baggage数据复用:可以通过
Baggage.current().getEntryValue("sentry-environment")这类代码获取客户端传递的baggage元数据,把它加到日志或业务埋点里
如果因为某些限制无法直接复用客户端Trace ID(比如现有追踪系统要求服务端生成独立Trace),可以通过过滤器把客户端的Trace/Span ID作为属性附加到服务端的Span上:
import io.opentelemetry.api.trace.Span; import jakarta.servlet.Filter; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; import jakarta.servlet.http.HttpServletRequest; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import java.io.IOException; @Configuration public class SentryTraceAttachConfig { @Bean public FilterRegistrationBean<Filter> sentryTraceAttachFilter() { FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter((ServletRequest request, ServletResponse response, FilterChain chain) -> { HttpServletRequest httpRequest = (HttpServletRequest) request; String sentryTraceHeader = httpRequest.getHeader("sentry-trace"); if (sentryTraceHeader != null) { String[] traceParts = sentryTraceHeader.split("-"); if (traceParts.length >= 1) { // 把客户端Trace ID加到服务端Span的属性中 Span.current().setAttribute("external.sentry.trace_id", traceParts[0]); if (traceParts.length >= 2) { Span.current().setAttribute("external.sentry.span_id", traceParts[1]); } } } chain.doFilter(request, response); }); registrationBean.addUrlPatterns("/*"); registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE); return registrationBean; } }
这样在追踪系统里,服务端的Span会带上客户端的Trace/Span ID属性,方便排查时关联两端数据。
内容的提问来源于stack exchange,提问作者mnille

