从Spring Cloud Sleuth迁移到Micrometer Tracing后Brave Baggage失效
背景
Spring项目升级后收到系统提示:
您的项目设置不符合要求,原因:Spring Cloud Sleuth与此Spring Cloud版本不兼容,建议操作:从Spring Cloud Sleuth迁移到Micrometer Tracing。
随后移除Sleuth依赖,添加micrometer-tracing和micrometer-tracing-bridge-brave依赖,并配置了如下YAML:
management: tracing: enabled: true baggage: enabled: true correlation: enabled: true fields: USER_ID remote-fields: USER_ID
问题现象
迁移后,BaggageField无法像Sleuth时期那样自动同步到MDC中。排查发现调用BaggageField.updateValue()时,tracing.currentTraceContext().get()返回null,导致更新操作失效。
相关排查代码片段:
@Nullable static TraceContext currentTraceContext() { Tracing tracing = Tracing.current(); return tracing != null ? tracing.currentTraceContext().get() : null; }
现有配置与代码
Baggage配置类
import brave.baggage.BaggageField; import brave.baggage.CorrelationScopeConfig; import brave.context.slf4j.MDCScopeDecorator; import brave.propagation.CurrentTraceContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class BaggageConfig { public static final String USER_ID_KEY = "USER_ID"; @Bean BaggageField userIdField() { return BaggageField.create(USER_ID_KEY); } @Bean public CurrentTraceContext.ScopeDecorator mdcScopeDecorator(BaggageField userIdField) { return MDCScopeDecorator.newBuilder() .clear() .add(CorrelationScopeConfig.SingleCorrelationField.newBuilder(userIdField).flushOnUpdate().build()) .build(); } }
注入并更新BaggageField
// 注入自定义的BaggageField private final BaggageField userIdField; // 更新字段值的代码 userIdField.updateValue(requestMetadataContext.getUserId());
使用的依赖版本
org.springframework.boot:3.0.6 org.springframework.cloud:spring-cloud-starter-bootstrap:4.0.2 org.springframework.cloud:spring-cloud-starter-consul-all:4.0.2 io.micrometer:micrometer-tracing:1.1.0 io.micrometer:micrometer-tracing-bridge-brave:1.1.0
1. 问题根源
手动创建的BaggageField未被Micrometer Tracing的Brave桥接器纳入管理,无法关联到当前活跃的TraceContext;同时YAML配置中定义的USER_ID baggage字段会被自动生成实例,和自定义Bean产生冲突,导致上下文关联失效。
2. 具体修复步骤
步骤1:移除自定义的Baggage配置类
不需要手动创建BaggageField和MDCScopeDecorator,Micrometer Tracing会根据YAML配置自动生成这些组件,并自动处理MDC同步逻辑。直接删除BaggageConfig类即可。
步骤2:改用Micrometer官方API操作Baggage
替换手动注入的Brave原生BaggageField,使用Micrometer提供的Tracer或BaggageManager来获取和更新字段:
方式一:通过Tracer操作
import io.micrometer.tracing.Tracer; import io.micrometer.tracing.Baggage; // 注入Tracer private final Tracer tracer; // 创建并更新USER_ID baggage Baggage userIdBaggage = tracer.createBaggage("USER_ID"); userIdBaggage.set(requestMetadataContext.getUserId());
方式二:通过BaggageManager获取原生BaggageField
如果需要使用Brave原生API,可通过BaggageManager获取托管的实例:
import io.micrometer.tracing.BaggageManager; import io.micrometer.tracing.brave.bridge.BraveBaggageField; import brave.baggage.BaggageField; // 注入BaggageManager private final BaggageManager baggageManager; // 获取托管的USER_ID字段 BaggageField userIdField = ((BraveBaggageField) baggageManager.getBaggageField("USER_ID")).delegate(); // 更新字段值 userIdField.updateValue(requestMetadataContext.getUserId());
步骤3:确保操作在活跃TraceContext上下文中执行
BaggageField.updateValue()需要在存在活跃TraceContext的线程中调用(如HTTP请求处理线程、被@Scheduled注解的定时任务线程等)。如果是在无TraceContext的线程中操作,需要手动创建上下文:
import brave.Tracing; import brave.propagation.TraceContext; import brave.propagation.CurrentTraceContext; // 手动创建TraceContext并绑定到当前线程 TraceContext traceContext = Tracing.current().tracer().newTrace().context(); try (CurrentTraceContext.Scope scope = Tracing.current().currentTraceContext().newScope(traceContext)) { userIdField.updateValue(requestMetadataContext.getUserId()); }
3. 验证
修复完成后,USER_ID的值会自动同步到MDC,日志中可通过%X{USER_ID}直接打印该字段。
内容的提问来源于stack exchange,提问作者Dfarrelly

