Search code examples
spring-cloudspring-cloud-sleuth

How do I access the current span and trace ids in a Spring Reactor context?


In my Spring Boot WebFlux application, I am using Reactor. I have set spring.sleuth.reactor.instrumentation-type=manual and am using @ContinueSpan on a service method. I see from the code that the span is created, started and ended appropriately in a reactive way.

Later, in the Flux I need to extract the trace information.

The code I am using injects Tracer and I use Tracer.currentSpan().context() to try to get to the trace context. I can successfully get the currentSpan() until I hit a call to an R2DBC repository method, after which the currentSpan is null. I can make the span "current" by annotating the repository method, but I do not want to do that unless it's necessary. I'd like to understand the underlying "problem".

I have also looked at CurrentTraceContext in the Reactor Subscription Context and see that it answers as Tracer does. Supporting both seems to be a threadlocal-ly supported trace context.

Oddly, if I look at TraceContext in the Subscriber context, the trace, parent, and span ids are there. It appears that WebFluxSleuthOperators.currentTraceContext(Context...) does this - so I have to believe that this is the appropriate vehicle for obtaining the trace context.

So, a few questions:

  1. Is WebFluxSleuthOperators.currentTraceContext(Context...) [TraceContext in the Reactor Subscription context] the proper way to get the up-to-date trace context?

  2. Looking at ReactorSleuthMethodInvocationProcessor, a reference to the current span and trace context are given to the SpanSubscriber which puts them in the Subscriber context. As mentioned earlier, subscribe() and next() are invoked within the context of that span. Why would a method such as a call to a r2dbc repository method effectively "erase" the tracer.currentSpan() but leave the trace context alone?

I'd love to understand this a bit more deeply and will look at the source more. But any insight right now is greatly appreciated. Thank you very much in advance.


Solution

  • To access the current span in a Reactor flow in Spring, use the Span or TraceContext found in the Subscriber Context.

    Mono.deferContextual(contextView -> Mono.just(contextView.get(TraceContext.class)))

    Or, better yet, use WebFluxSleuthOperators.currentTraceContext(Context.of(contextView)))

    Accessing the span through the Tracer bean may not produce the current span - as the current thread may be different than the one that originated the span and brought it into scope. This was confirmed through debugging.