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

将新Micrometer追踪上下文传递至Reactor Mono问题求助

问题分析

核心问题是线程本地的Trace Scope与Reactor反应式上下文不共享:

  • 通过tracer.currentTraceContext().newScope(tc)创建的线程本地Scope仅对当前线程的同步代码生效(即try块内的第一个LOGGER.info)。
  • Mono属于异步执行逻辑,代码会在订阅时的线程或其他线程运行,不会自动继承当前线程的Scope,因此内部日志和方法调用仍沿用原traceId1。
  • 你手动调用contextWrite(Context.of(TraceContext.class, tc))注入的上下文,未与追踪框架的上下文绑定,导致日志框架无法识别。
解决方案

1. 正确将TraceContext注入Reactor Context

以OpenTelemetry为例,需使用官方提供的Reactor工具类传递TraceContext(若用Spring Boot,通常已集成相关依赖):

依赖引入(Maven示例)

<dependency>
    <groupId>io.opentelemetry</groupId>
    <artifactId>opentelemetry-extension-reactor</artifactId>
</dependency>

代码调整

TraceContext tc = tracer.traceContextBuilder()
        .traceId(message.getTraceId()) // traceId0
        .spanId(tracer.currentTraceContext().context().spanId())
        .sampled(tracer.currentTraceContext().context().sampled())
        .parentId(tracer.currentTraceContext().context().parentId())
        .build();

// 用OpenTelemetry上下文传播工具包装Mono,确保TraceContext在反应式流中传递
return OpenTelemetry.contextPropagation()
        .wrap(Mono.deferContextual(contextView -> {
            LOGGER.info("tracing log -> test"); // 现在将使用traceId0
            return switch (message.getEvent()) {
                case ADD_EVENT -> add(message.get(), message.getTraceId());
                case REMOVE_EVENT -> remove(message.get(), message.getTraceId());
                default -> {
                    LOGGER.warn("not supported '{}' ", message);
                    yield Mono.just(true);
                }
            };
        }))
        .contextWrite(Context.of(ContextKey.named("otel.trace.context"), tc))
        .contextCapture();

2. 配置日志框架从Reactor Context读取Trace信息

若使用SLF4J+Logback,需确保MDC能从Reactor Context中读取Trace参数:

  • 启动时注册Reactor MDC钩子:
ReactorHooks.onEachOperator(MdcContextWrite.create());
  • 或手动在Mono中注入MDC上下文:
return OpenTelemetry.contextPropagation()
        .wrap(Mono.deferContextual(...))
        .contextWrite(MdcContextWrite.of(mdc -> {
            mdc.put("traceId", tc.traceId());
            mdc.put("spanId", tc.spanId());
            return mdc;
        }))
        .contextWrite(Context.of(ContextKey.named("otel.trace.context"), tc))
        .contextCapture();

3. 移除多余的线程本地Scope

原try (var sc = tracer.currentTraceContext().newScope(tc))仅对同步代码生效,对异步Mono无帮助,反而可能造成上下文混乱,建议直接移除。

简化后完整代码示例
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.ContextKey;
import io.opentelemetry.extension.reactor.OpenTelemetry;
import reactor.core.publisher.Mono;

// ...

public Mono<Boolean> handleMessage(Message message, Tracer tracer) {
    TraceContext tc = tracer.traceContextBuilder()
            .traceId(message.getTraceId()) // traceId0
            .spanId(tracer.currentTraceContext().context().spanId())
            .sampled(tracer.currentTraceContext().context().sampled())
            .parentId(tracer.currentTraceContext().context().parentId())
            .build();

    return OpenTelemetry.contextPropagation()
            .wrap(Mono.deferContextual(contextView -> {
                LOGGER.info("tracing log -> test"); // 使用traceId0
                return switch (message.getEvent()) {
                    case ADD_EVENT -> add(message.get(), message.getTraceId());
                    case REMOVE_EVENT -> remove(message.get(), message.getTraceId());
                    default -> {
                        LOGGER.warn("not supported '{}' ", message);
                        yield Mono.just(true);
                    }
                };
            }))
            .contextWrite(Context.of(ContextKey.named("otel.trace.context"), tc))
            .contextCapture();
}

关键说明

  • 反应式流上下文与线程本地变量相互隔离,必须通过Reactor的contextWrite+框架上下文传播工具传递Trace信息。
  • 日志框架需配置为从Reactor Context读取MDC参数,否则日志仍会显示旧traceId。
  • 若使用Spring Cloud Sleuth,无需手动构建TraceContext,直接用SleuthTracer的withTraceId方法包装Mono即可,实现更简洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 12:18:11