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

WebClient链路追踪上下文丢失:如何让日志包含traceId与spanId?

SpringBoot 3.5.10中WebClient异步回调日志丢失traceId/spanId的解决方法

问题原因

WebClient的subscribe回调属于异步执行,默认情况下追踪上下文不会自动传递到回调线程,导致日志无法获取traceId和spanId。

解决步骤

1. 确认WebClient的观测配置正确性

确保WebClient.Builder已正确注入ObservationRegistry并启用观测支持,示例代码:

@Bean
public WebClient webClient(ObservationRegistry observationRegistry) {
    return WebClient.builder()
            .observationRegistry(observationRegistry)
            .build();
}

如果使用自动配置的WebClient.Builder,可通过以下方式扩展:

@Bean
public WebClient customWebClient(WebClient.Builder builder, ObservationRegistry observationRegistry) {
    return builder.observationRegistry(observationRegistry).build();
}

2. 手动传递追踪上下文到异步回调

方式一:使用Micrometer的ContextSnapshot

通过ContextSnapshotFactory捕获当前上下文,在回调中恢复:

@Autowired
private ContextSnapshotFactory contextSnapshotFactory;

// 业务方法中调用WebClient
public void fetchDepartment() {
    ContextSnapshot snapshot = contextSnapshotFactory.captureAll();
    webClient.get().uri("/api/department")
            .retrieve()
            .bodyToMono(Department.class)
            .subscribe(dept -> {
                try (ContextSnapshot.Scope scope = snapshot.setThreadContext()) {
                    // 此处日志将包含traceId和spanId
                    log.info("获取部门信息: {}", dept.getName());
                }
            });
}

方式二:使用Brave的Tracer

直接捕获当前Span上下文,在回调中恢复:

@Autowired
private Tracer tracer;

// 业务方法中调用WebClient
public void fetchDepartment() {
    Span currentSpan = tracer.currentSpan();
    webClient.get().uri("/api/department")
            .retrieve()
            .bodyToMono(Department.class)
            .subscribe(dept -> {
                try (Tracer.SpanInScope scope = tracer.withSpanInScope(currentSpan)) {
                    // 此处日志将包含traceId和spanId
                    log.info("获取部门信息: {}", dept.getName());
                }
            });
}

3. 验证日志格式配置

确保日志框架已配置traceId和spanId的输出占位符:

  • Logback配置示例:
<encoder>
    <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%X{traceId},%X{spanId}] - %msg%n</pattern>
</encoder>
  • Log4j2配置示例:
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%X{traceId},%X{spanId}] - %msg%n"/>

注意事项

如果使用block()同步调用WebClient,追踪上下文会自动传递,无需手动处理;仅异步场景(如subscribe)需要手动传递上下文。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.11 13:03:22