WebClient instrumentation in spring sleuth - spring-cloud-sleuth

I'm wondering whether sleuth has reactive WebClient instrumentation supported.
I did't find it from the document:
Instruments common ingress and egress points from Spring applications (servlet filter, async endpoints, rest template, scheduled actions, message channels, Zuul filters, and Feign client).
My case:
I may use WebClient in either a WebFilter or my rest resource to produce Mono.
And I want:
A sub span auto created as child of root span
trace info propagated via headers
If the instrumentation is not supported at the moment, Am I supposed to manually get the span from context and do it by myself like this:
OpenTracing instrumentation on reactive WebClient
Thanks
Leon

Even though this is an old question this would help others...
WebClient instrumentation will only work if new instance is created via Spring as a Bean. Check Spring Cloud Sleuth reference guide.
You have to register WebClient as a bean so that the tracing instrumentation gets applied. If you create a WebClient instance with a new keyword, the instrumentation does NOT work.

If you go to Sleuth's documentation for the Finchley release train, and you do find and you search for WebClient you'll find it - https://cloud.spring.io/spring-cloud-static/Finchley.RC2/single/spring-cloud.html#__literal_webclient_literal . In other words we do support it out of the box.
UPDATE:
New link - https://docs.spring.io/spring-cloud-sleuth/docs/current/reference/html/integrations.html#sleuth-http-client-webclient-integration
let me paste the contents
3.2.2. WebClient
This feature is available for all tracer implementations.
We inject a ExchangeFilterFunction implementation that creates a span
and, through on-success and on-error callbacks, takes care of closing
client-side spans.
To block this feature, set spring.sleuth.web.client.enabled to false.
You have to register WebClient as a bean so that the tracing
instrumentation gets applied. If you create a WebClient instance with
a new keyword, the instrumentation does NOT work.

Related

ThreadLocal in spring web flux

I am new to spring webflux. I am trying to implement the ThreadLocal using spring webflux.
I have a requirement where I need to pass the header from one microservice to another microservice in webclient.
I do not want to pass the header from on service to another service carrying it manually and assigning it in each request.
So thought of using ThreadLocal when I can set it and can access that in webclient call.
I am try to find a sample application where I can refer ThreadLocal with in spring webflux.
You should not use ThreadLocal in reactive environment. Webflux (which based on Reactor) is a non blocking framework. It reuses threads so the steps of one reactive pipeline can run in different threads and also multiple requests can use the same thread concurrently - until one waits, another operation will be picked and executed. Imagine if your request puts something into threadlocal and waits - for example - on a db select, another request can override this value and the next pipeline stage of the original request will see that new value belongs to another request. Threadlocal is good for request-per-thread model.
For webflux, you can use contexts. For example put the value into the pipeline in a WebFilter, then you can retrieve it in any point of the reactive pipeline:
chain.filter(exchange).contextWrite(<your data>)
In the pipeline (in map/flatmap...)
Mono.deferContextual(...)
Here is the link for documentation.
Alternatively you can lift ThreadLocal's value on every operation using Hooks, but this is not a nice and bulletproof solution.

Sleuth traceId and spanId not logged in activeMQ Listener

I'm trying to configure a microservice with Sleuth and ActiveMQ.
When starting a request I can properly see appName, traceId and spanId in logs of producer, but after dequeuing the message in listener I find only appName, without traceId and spanId.
How can I get this fields filled?
Right now I'm working with spring.sleuth.messaging.jms.enabled=false to avoid this exception at startup:
Bean named 'connectionFactory' is expected to be of type 'org.apache.activemq.ActiveMQConnectionFactory' but was actually of type 'org.springframework.cloud.sleuth.instrument.messaging.LazyConnectionFactory'
My dependencies:
org.springframework.boot.spring-boot-starter-activemq 2.5.1
org.springframework.cloud.spring-cloud-sleuth 3.0.3
Thank you all!
My understanding is that the properties you're looking for are set on the JMS message when the message is sent and then retrieved from the message when it is consumed. Since you're setting spring.sleuth.messaging.jms.enabled=false you're disabling this functionality. See the documentation which states:
We instrument the JmsTemplate so that tracing headers get injected into the message. We also support #JmsListener annotated methods on the consumer side.
To block this feature, set spring.sleuth.messaging.jms.enabled to false.
You'll need to find an alternate solution for the connection factory problem if you want to use Sleuth with Spring JMS. If you're injecting org.apache.activemq.ActiveMQConnectionFactory somewhere then you should almost certainly be using javax.jms.ConnectionFactory instead. Using the concrete type is bad for portability and use-cases like this where wrapper implementations are used dynamically.

Sleuth annotations with Spring Webflux gives CglibAopProxy warnings

I have a reactive application using Spring Webflux. I have used sleuth annotations like #NewSpan to create spans, but I am getting warning like
CglibAopProxy|Unable to proxy interface-implementing method
[public final void reactor.core.publisher.Flux.subscribe(org.reactivestreams.Subscriber)]
because it is marked as final: Consider using interface-based JDK proxies instead!
I know Flux.subscribe is a final method so proxies are not generated correctly, but I can still see those spans on Zipkin.
I need to know what are the implications of this warning. And how can I avoid this?

Webflux WebClient retry and Spring Cloud Circuit Breaker Resilience4J Retry pattern walk into a bar

Would like to ask a question about two technologies.
We first started with an application that has to call other third parties rest API, hence, we used the Webflux WebClient in our SpringBoot Webflux project. So far so good, we had a successful app for a while.
Then the third party app (not ours) started to become flaky, sometimes will fail on our requests. We had to implement some kind of retry logic. After the implementation of the retry logic, such as WebClient reties, the business flow is now working fine.
We mainly took logics from the framework directly. For instance, a talk from #simon-baslé, Cancel, Retry and Timeouts at the recent SpringOne gave many working examples.
.retryWhen(backoff(5, Duration.ofMillis(10).maxbackOff(Duration.ofSeconds(1)).jitter(0.4)).timeout(Duration.ofSeconds(5)
On the other hand, lately, there are more and more apps moving towards Circuit Breaker pattern. The Spring Cloud Circuit Breaker project, backed by Resilience4J is a popular implementation using Resilience4J for patterns such as Circuit Breaker, Bulkhead, and of course Retry.
Hence, I am having a question, is there a benefit of using/combining both in terms of retry?
Any gain in terms of having the two together? Any drawbacks?
Or only one of the two is enough, in which case, which one please? And why?
Thank you
we (Resilience4j Team) have implemented custom Spring Reactor operators for CircuitBreaker, Retry and Timeout. Internally Retry and Timeout use operators from Spring Reactor, but Resilience4j adds functionality on top of it:
External configuration of Retry, Timeout and CircuitBreaker via config files
Spring Cloud Config support to dynamically adjust the configuration
Metrics, metrics, metrics ;)
Please see https://resilience4j.readme.io/docs/examples-1 and https://resilience4j.readme.io/docs/getting-started-3
You can even use Annotations to make it more simple:
#CircuitBreaker(name = BACKEND)
#RateLimiter(name = BACKEND)
#Retry(name = BACKEND)
#TimeLimiter(name = BACKEND, fallbackMethod = "fallback")
public Mono<String> method(String param1) {
return ...
}
private Mono<String> fallback(String param1, TimeoutException ex) {
return ...;
}
Please be aware that we are providing our own Spring Boot starter. I'm NOT talking about the Spring Cloud CircuitBreaker project.

Spring bean RequestScope with Webflux

Is there a pattern to use #RequestScope with Webflux? We used the approach suggested here (https://www.baeldung.com/spring-bean-scopes) but it gives below error.
No scope registered for scope name request
Request scope works on ThreadLocal which is not supported by Webflux because part of work can be delegated between threads and you cannot assume that request will be handled by one thread.
In such a case, you should take a look at Reactor Context which allows you to connect data with the request scope.