如何配置Spring Cloud Sleuth将自定义字段识别为traceId与spanId
没有原生配置可以直接让Sleuth把你日志pattern里写的newTraceIdPlaceholder、newSpanIdPlaceholder识别为内部原生的traceId、spanId字段语义,毕竟这套链路字段的识别逻辑是硬编码在Sleuth内部MDC组件里的,根本没预留反向映射的配置开关。但你实际要的“用自定义占位符输出链路ID值”的效果,有两种零踩坑的实现方式,完全不用动你现有的日志pattern配置。
方案一:纯配置实现,零代码
直接通过Sleuth的Baggage本地字段映射规则,让Sleuth把原生的traceId、spanId值,自动同步写入你自定义的两个MDC键就行,配置示例:
# (可选)关闭Sleuth默认写入的原生traceId、spanId MDC键,避免冗余 spring.sleuth.log.slf4j.mdc-context-injector.enabled=false # 配置本地字段映射,把原生链路值同步到自定义键 spring.sleuth.baggage.local-fields[0]=traceId:newTraceIdPlaceholder spring.sleuth.baggage.local-fields[1]=spanId:newSpanIdPlaceholder
配置完成后你原来的日志pattern不用改一行,就能正常输出链路字段值。
注意事项:如果你们的日志平台配置了自动解析traceId做链路关联,一定要同步把平台的解析规则改成读取你自定义的两个键名,不然会因为读不到默认键名导致链路关联失效。
方案二:扩展点适配,兼容原有逻辑
如果你不想动Sleuth默认的MDC写入逻辑,就用Sleuth提供的Span生命周期监听扩展,在Span启动、销毁的节点,手动把原生链路值复制到你自定义的MDC键上,示例代码:
@Bean public SpanListener customMdcKeySyncListener() { return new SpanListener() { @Override public void onSpanStarted(Span startedSpan) { // 当前Span启动时,把链路值写入自定义MDC键 MDC.put("newTraceIdPlaceholder", startedSpan.context().traceId()); MDC.put("newSpanIdPlaceholder", startedSpan.spanId()); } @Override public void onStopped(Span finishedSpan) { // 当前Span结束时清理自定义键,防止线程池复用导致上下文串扰 MDC.remove("newTraceIdPlaceholder"); MDC.remove("newSpanIdPlaceholder"); } }; }
这种方式不会影响Sleuth默认的traceId、spanId MDC键,既兼容现有所有日志采集规则,又能满足你自定义键名输出的需求。
逻辑澄清
别被“让Sleuth识别自定义键为原生链路字段”的思路绕进去,Sleuth从来不会反向扫描日志pattern里的占位符去对应内部字段,它只是主动往MDC里塞预定义好的链路键值对。你要的效果本质是让自定义的MDC键拿到链路ID的值,而不是反过来让Sleuth识别你的自定义键,思路转过来后实现非常简单。
内容的提问来源于stack exchange,提问作者user1800752

