Home > Software engineering >  Sleuth tracer.currentSpan() coming as empty in WebFlux WebFilter
Sleuth tracer.currentSpan() coming as empty in WebFlux WebFilter

Time:11-03

How Can I add Trace Id in the response headers in reactive WebFlux context ? I have tried with the below code but the span is always coming as null. Sleuth dependency version is 3.0.3 and Spring Boot version is 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);
      }

}

CodePudding user response:

Using a WebFilter would be the right way to do this, the docs suggest something similar.
I'm not sure why exactly do you get this behavior (I guess beforeCommit might not be in the context), this is what the docs suggest, I would try this first:

@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);
    };
}

Here are a few other pointers for troubleshooting:

  • Please check if your spans are sampled
  • Please check if a Span was created and you are in the context of it
  • Could you please check if any other instrumentation style works (I recommend DECORATE_QUEUES)?

CodePudding user response:

The current span is null because the default instrumentation option in the Gateway is manual. So you're responsible for retrieving the spans. So you have two options.

Option no 1 is to use WebFluxSleuthOperators to retrieve the current trace context from the ServerWebExchange (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) as follows:

@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);
    };
}

or option number 2 go with the different Sleuth Reactor integration as Jontan mentioned https://docs.spring.io/spring-cloud-sleuth/docs/current/reference/htmlsingle/#sleuth-reactor-integration as follows:

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
  • Related