Sleuth tracer.currentSpan() 在 WebFlux WebFilter 中显示为空

Sleuth tracer.currentSpan() coming as empty in WebFlux WebFilter

如何在反应式 WebFlux 上下文中的响应 headers 中添加跟踪 ID?我尝试使用以下代码,但跨度始终为空。 Sleuth 依赖版本为 3.0.3,Spring 引导版本为 2.5.4

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

@Component
public class GatewaySleuthFilter implements WebFilter {

    @Autowired
    Tracer tracer;
    
    @Override
      public Mono<Void> filter(ServerWebExchange exchange,
                               WebFilterChain chain) {
        ServerHttpResponse response = exchange.getResponse();
        response.beforeCommit(() -> {
          Span span = tracer.currentSpan();
          if (span != null) {
            exchange.getResponse().getHeaders().add("trace-id", span.context().traceId());
            exchange.getResponse().getHeaders().add("span-id", span.context().spanId());
          }
          return Mono.empty();
        });
        return chain.filter(exchange);
      }

}

使用 WebFilter 是正确的方法,docs suggest something similar.
我不确定你为什么会得到这种行为(我猜 beforeCommit 可能不在上下文中),这是文档的建议,我会先尝试这个:

@Bean
WebFilter traceIdInResponseFilter(Tracer tracer) {
    return (exchange, chain) -> {
        Span span = tracer.currentSpan();
        if (span != null) {
            exchange.getResponse().getHeaders().add("trace-id", span.context().traceId());
            exchange.getResponse().getHeaders().add("span-id", span.context().spanId());
        }
        return chain.filter(exchange);
    };
}

以下是一些其他问题排查指南:

  • 请检查您的跨度是否被采样
  • 请检查 Span 是否已创建并且您是否在它的上下文中
  • 你能检查一下其他 instrumentation style 是否有效吗(我推荐 DECORATE_QUEUES)?

当前跨度是 null,因为网关中的默认检测选项是手动的。因此,您负责检索跨度。所以你有两个选择。

选项 1 是使用 WebFluxSleuthOperatorsServerWebExchange (https://github.com/spring-cloud/spring-cloud-sleuth/blob/v3.0.4/spring-cloud-sleuth-instrumentation/src/main/java/org/springframework/cloud/sleuth/instrument/web/WebFluxSleuthOperators.java) 中检索当前跟踪上下文,如下所示:

@Bean
WebFilter traceIdInResponseFilter() {
    return (exchange, chain) -> {
        Span span = 
WebFluxSleuthOperators.currentTraceContext(exchange);
        if (span != null) {
            exchange.getResponse().getHeaders().add("trace-id", span.context().traceId());
            exchange.getResponse().getHeaders().add("span-id", span.context().spanId());
        }
        return chain.filter(exchange);
    };
}

或选项 2 与 Jontan 提到的不同的 Sleuth Reactor 集成 https://docs.spring.io/spring-cloud-sleuth/docs/current/reference/htmlsingle/#sleuth-reactor-integration 如下:

spring:
  sleuth:
    reactor:
      # try decorate_queues and if that fails decorate_on_each
      # decorate_on_each can lead to dramatic performance degradation
      instrumentation-type: decorate_queues

下面的代码对我有用。

@Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        ServerHttpResponse response = exchange.getResponse();
        response.beforeCommit(() -> {
            Span span = exchange.getAttribute(Span.class.getName());
            if (span != null) {
                exchange.getResponse().getHeaders().add(TRACE_ID_HEADER, span.context().traceId());
                exchange.getResponse().getHeaders().add(SPAN_ID_HEADER, span.context().spanId());
            }
            return Mono.empty();
        });
        return chain.filter(exchange);
    }