Add Spring WebFlux and WebClient tracing.#95
Conversation
| </dependency> | ||
| <dependency> | ||
| <groupId>com.github.tomakehurst</groupId> | ||
| <artifactId>wiremock-jre8</artifactId> |
There was a problem hiding this comment.
I had to replace MockRestServiceServer in the tests with something else (WireMock), because MockRestServiceServer does not support WebClient.
| <properties> | ||
| <maven.compiler.source>1.7</maven.compiler.source> | ||
| <maven.compiler.target>1.7</maven.compiler.target> | ||
| <maven.compiler.source>1.8</maven.compiler.source> |
There was a problem hiding this comment.
Spring Framework 5 requires JRE 8 so I believe this is safe to change.
There was a problem hiding this comment.
Note that this is not only SB, the web package can be used with old spring web apps.
There was a problem hiding this comment.
@pavolloffay Spring Framework 5+ requires JDK 8+. See here
pavolloffay
left a comment
There was a problem hiding this comment.
@csabakos thanks for the PR! It looks good.
I would like to see a test where a client is used to from multiple threads (assuming it supports concurrent processing) and creates requests to instrumented web endpoint (can be reactive too)
I have noticed that some files were taken from spring-cloud-sleuth. I think we should add their license (We already doing it for some files in spring-cloud repository)
| get automatically traced different set of technologies e.g. `spring-cloud-netflix`, JMS or even more then | ||
| use project [opentracing-spring-cloud](https://github.com/opentracing-contrib/java-spring-cloud) instead. | ||
|
|
||
| For reactive applications, it is especially recommended to use `reactor` tracing from |
There was a problem hiding this comment.
Is reactor supported in opentracing-spring-cloud?
There was a problem hiding this comment.
I'm planning to add Spring Boot auto-configuration for that in a separate pull request. I already have the code ready for it, but opentracing-reactor needs to be published to Maven central first. (See opentracing-contrib/java-reactor#1)
| Assert.assertEquals("GET", span.tags().get(Tags.HTTP_METHOD.getKey())); | ||
| Assert.assertEquals(TEST_REST_TEMPLATE.getRootUri() + "/", span.tags().get(Tags.HTTP_URL.getKey())); | ||
| Assert.assertEquals(200, span.tags().get(Tags.HTTP_STATUS.getKey())); | ||
| Assert.assertEquals("WebFlux/java-spring-web", span.tags().get(Tags.COMPONENT.getKey())); |
There was a problem hiding this comment.
Change java-spring-webflux to be consistent with other component names in this repo?
| <dependency> | ||
| <groupId>org.springframework</groupId> | ||
| <artifactId>spring-webflux</artifactId> | ||
| <scope>provided</scope> |
There was a problem hiding this comment.
I think this should be optional? We don't want users to depend on webflux
There was a problem hiding this comment.
Thanks, optional makes more sense than provided.
| */ | ||
| @Configuration | ||
| @ConditionalOnBean(Tracer.class) | ||
| @ConditionalOnClass(WebClient.class) |
There was a problem hiding this comment.
Should we also do conditional on reactive?
There was a problem hiding this comment.
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
There was a problem hiding this comment.
@ConditionalOnWebApplication refers to the server technology.
One could use the reactive WebClient in a Servlet-based server application, so I don't think that adding that conditional would be appropriate.
| } | ||
|
|
||
| @Override | ||
| public void onCancel(final ClientRequest httpRequest, final Span span) { |
There was a problem hiding this comment.
When does cancel happen?
There was a problem hiding this comment.
Excellent question! It looks like cancellation can happen in various circumstances:
- If the user of the WebClient "unsubscribes" from the request (for example because they have a timeout that they reached and they no longer wish to wait for the result). I think in this case I think it is correct to log an error on the span, since timeout can be considered an error.
- In various Reactor constructs,
cancel()is called even when theMono(successfully) emits an item. An example of this isFlux#next(). Since this is part of the normal (successful) behavior, I don't think we should log an error.
There does not seem to be a good way to differentiate between the above two cases in the tracing code, so I changed this to log a cancelled event instead of an error. It will be up to the user who is looking at the trace logs to determine if the cancellation indicates an error or not. (For example the user can infer this from the HTTP status code, etc.)
There was a problem hiding this comment.
If it is a part of normal execution flow and it happes often we can avoid adding meta-data at all.
There was a problem hiding this comment.
As an application developer, it is still valuable information that the subscription was cancelled. Cancellation does not happen in simple WebClient flows, only if you're doing something more complex (like retries, or firing off multiple requests and waiting for the fastest one to return).
I think it's worth have these events in the trace logs.
If other people find them bothersome, they can file an issue and we can make it optional, but I think that won't be the case.
@pavolloffay Thank you for the review!
I implemented the exact test that you linked to for WebClient: opentracing-spring-web/src/test/java/io/opentracing/contrib/spring/web/client/TracingWebClientTest.java. Is that sufficient or did you have something else in mind?
Conveniently their license is also Apache License 2.0, but I will gladly add it. Would you mind pointing me to an existing example of what exactly needs to be done? |
…ince we do not want to signal an error due to cancellation in those cases.
…error, since we do not want to signal an error due to cancellation in those cases." This reverts commit 72a441f.
I think just add the license to the files and then exclude them in pom https://github.com/opentracing-contrib/java-spring-cloud/blob/master/pom.xml#L380 |
pavolloffay
left a comment
There was a problem hiding this comment.
@geoand could you please review too?
| @AutoConfigureAfter(TracerAutoConfiguration.class) | ||
| @EnableConfigurationProperties(WebTracingProperties.class) | ||
| @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) | ||
| @ConditionalOnProperty(name = "opentracing.spring.web.enabled", havingValue = "true", matchIfMissing = true) |
There was a problem hiding this comment.
CONFIGURATION_PREFIX can be used
| } | ||
|
|
||
| @Override | ||
| public void onCancel(final ClientRequest httpRequest, final Span span) { |
There was a problem hiding this comment.
If it is a part of normal execution flow and it happes often we can avoid adding meta-data at all.
| final String requestUrl = url + i; | ||
|
|
||
| final Scope parentSpan = mockTracer.buildSpan("foo").startActive(false); | ||
| parentSpan.span().setTag("request-url", requestUrl); |
There was a problem hiding this comment.
Add tag on spanBuilder
| for (int i = 0; i < numberOfCalls; i++) { | ||
| final String requestUrl = url + i; | ||
|
|
||
| final Scope parentSpan = mockTracer.buildSpan("foo").startActive(false); |
There was a problem hiding this comment.
Create a span directly and remove cont. cont does not seems to be needed
I will do that tomorrow :) |
…nfigure license-maven-plugin, and update license headers.
Done. The pom did not have |
|
@csabakos Can you please resolve the conflict? Thanks |
|
That's up to @pavollofay to decide 😎 |
| @ConditionalOnClass(WebClient.class) | ||
| @ConditionalOnProperty(prefix = WebClientTracingProperties.CONFIGURATION_PREFIX, name = "enabled", matchIfMissing = true) | ||
| @AutoConfigureAfter(TracerAutoConfiguration.class) | ||
| @EnableConfigurationProperties(WebClientTracingProperties.class) |
There was a problem hiding this comment.
Should WebClientTracingProperties be renamed to ClientTracingProperties?
I mean the name is a little misleading since it's configuration for RestTemplate, AsyncRestTemplate and WebClient.
Also, the comments in WebClientTracingProperties should be updated to reflect this fact
There was a problem hiding this comment.
I don't have an opinion about renaming - I could see arguments both pro and con. I'll leave the decision up to you and @pavolloffay. (Because the class is public, it is in theory part of the public API, so that'd be one reason for not renaming it.)
I will update the comments though.
There was a problem hiding this comment.
It's true that it's public, public configuration classes would rarely be used directly in application code. I would assume that at least a minor version bump would be warranted even without the rename, so some minor breaking could probably be expected.
Let's leave it up to @pavolloffay to decide :)
| <dependency> | ||
| <groupId>org.springframework</groupId> | ||
| <artifactId>spring-webflux</artifactId> | ||
| <scope>compile</scope> |
There was a problem hiding this comment.
This is default scope, so perhaps best to omit it?
There was a problem hiding this comment.
Shouldn't this be optional?
There was a problem hiding this comment.
Nice catch! Looks like I only updated the POM in opentracing-spring-web-starter but not in opentracing-spring-web. Fixed now.
|
Looks good from a Spring perspective 👍 |
|
@geoand can this be merged? |
|
@pavolloffay yeah it LGTM. Should I merge and cut a release? |
|
👍 |
|
Thanks for the awesome work @csabakos! |
|
Thanks y'all for the prompt review and good comments! I'll work on adding the Spring Boot starter for |
|
Thanks again @csabakos! |
This adds Spring WebFlux and WebClient tracing.
I will also add auto-configuration for https://github.com/opentracing-contrib/java-reactor to
opentracing-spring-cloud, which will complement these changes with automatic activation of the span in handler functions.