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

Spring Boot 3 WebFlux追踪中配置Logbook correlationId问题求助

解决思路

1. 调整Netty Handler执行顺序

问题核心是LogbookServerHandler在Sleuth创建trace span的Netty Handler之前执行,导致请求阶段无法获取traceId。只需将Logbook的Handler添加到Sleuth的Handler之后即可:

@Configuration
@Slf4j
@AutoConfigureBefore(LogbookWebFluxAutoConfiguration.class)
public class LogbookConfig {

    @Bean
    NettyServerCustomizer nettyServerCustomizer(Logbook logbook) {
        return httpServer -> httpServer
                .doOnConnection(connection -> {
                    // 将Logbook Handler添加到Sleuth的TracingHandler之后
                    connection.addHandlerAfter(new LogbookServerHandler(logbook), TracingHandler.class);
                    // 若不清楚类名,可尝试用Sleuth Handler默认名称"tracingHandler"
                    // connection.addHandlerAfter(new LogbookServerHandler(logbook), "tracingHandler");
                });
    }

    @Bean
    @Primary
    public CorrelationId correlationId(Tracer tracer) {
        return request -> {
            Span currentSpan = tracer.currentSpan();
            if (currentSpan == null) {
                log.warn("当前Span为空,使用随机ID作为correlationId");
                return UUID.randomUUID().toString();
            }
            return currentSpan.context().traceId();
        };
    }
}

2. 从Reactor Context获取TraceId(适配WebFlux非阻塞场景)

WebFlux中Sleuth会将Span信息存入Reactor Context而非ThreadLocal,直接调用tracer.currentSpan()可能因线程切换返回null。可以通过Reactor Context获取traceId:

@Configuration
@Slf4j
@AutoConfigureBefore(LogbookWebFluxAutoConfiguration.class)
public class LogbookConfig {

    @Bean
    @Primary
    public CorrelationId correlationId() {
        return request -> {
            try {
                // 从Reactor Context中获取Span
                Span span = Mono.deferContextual(contextView -> 
                        Mono.justOrEmpty(contextView.getOrEmpty(Span.class))
                ).block(Duration.ofMillis(100));
                
                if (span != null) {
                    return span.context().traceId();
                }
            } catch (Exception e) {
                log.error("从Reactor Context获取traceId失败", e);
            }
            log.warn("无法获取traceId,使用随机correlationId");
            return UUID.randomUUID().toString();
        };
    }

    // 禁用自定义Netty Handler,改用Logbook默认WebFilter配置
    @Bean
    public Logbook logbook(LogbookFactory logbookFactory, CorrelationId correlationId) {
        return logbookFactory.create(correlationId);
    }
}

3. 改用Logbook WebFilter替代Netty Handler

放弃自定义Netty Handler,直接使用Logbook的WebFilter实现,确保它在Sleuth的Filter之后执行:

@Configuration
@Slf4j
@AutoConfigureAfter(TracingWebFluxAutoConfiguration.class) // 确保在Sleuth配置后加载
@AutoConfigureBefore(LogbookWebFluxAutoConfiguration.class)
public class LogbookConfig {

    @Bean
    @Primary
    public CorrelationId correlationId(Tracer tracer) {
        return request -> {
            Span currentSpan = tracer.currentSpan();
            return currentSpan != null ? currentSpan.context().traceId() : UUID.randomUUID().toString();
        };
    }

    @Bean
    public LogbookWebFilter logbookWebFilter(Logbook logbook, HttpMessageWriter<?> writer) {
        return new LogbookWebFilter(logbook, writer);
    }
}

此时WebFilter会在Sleuth创建好trace span后再执行,调用tracer.currentSpan()即可拿到正确的traceId。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 04:40:15