Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update webflux to Instrumenter API (and improvements/simplifications) #3798

Merged
merged 17 commits into from
Aug 13, 2021
Merged

Update webflux to Instrumenter API (and improvements/simplifications) #3798

merged 17 commits into from
Aug 13, 2021

Conversation

trask
Copy link
Member

@trask trask commented Aug 8, 2021

In addition to updating to Instrumenter API:

  • Handler span now maps to org.springframework.web.reactive.HandlerAdapter.handle() instead of org.springframework.web.reactive.DispatcherHandler.handle(), which more closely maps to the user handler. This aligns better with other handler spans, and the previous (strange to me) handler instrumentation placement was what motivated What is a "handler span"? #3144. Also, I think this change addresses the flaky problems that required Fix flaky spring webflux tests #3150 previously (without needing the fix from Fix flaky spring webflux tests #3150). @laurit I was not able to get any flakes following your notes to repro the flaky problem (increased request count to 300 for "Multiple GETs to delaying route" test and used spring boot 2.5.0), but would be great if you have time to give it a look/try also.

  • Removed spring-webflux.request.predicate experimental attribute because the handler span is not available yet when this is calculated. If anyone wants to keep this, I can either put it on the SERVER span, or propagate it down to where the handler span is started.

This reverts commit 9df4a14.
Comment on lines 96 to 109
if (handler instanceof HandlerMethod) {
// Special case for requests mapped with annotations
HandlerMethod handlerMethod = (HandlerMethod) handler;
spanName = SpanNames.fromMethod(handlerMethod.getMethod());
handlerType = handlerMethod.getMethod().getDeclaringClass().getName();
} else {
spanName = AdviceUtils.spanNameForHandler(handler);
handlerType = handler.getClass().getName();
}

span.updateName(spanName);
if (SpringWebfluxConfig.captureExperimentalSpanAttributes()) {
span.setAttribute("spring-webflux.handler.type", handlerType);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we move that code inside instrumenter.start() call?

AdviceUtils.finishSpanIfPresent(exchange, throwable);
@Advice.Return(readOnly = false) Mono<Void> mono) {
if (mono != null) {
// note: it seems like this code should go in HandleAdvice @OnMethodExit
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean Enter? This code seems to be in HandleAdvice.OnMethodExit right now

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh no, two different HandleAdvice classes, I fixed the comment 👍

Copy link
Contributor

@laurit laurit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@trask I couldn't reproduce it either, perhaps something else has changed that makes triggering this harder.

@@ -61,6 +61,7 @@ dependencies {
tasks.withType<Test>().configureEach {
// TODO run tests both with and without experimental span attributes
jvmArgs("-Dotel.instrumentation.spring-webflux.experimental-span-attributes=true")
// TODO(trask): try removing this if/when latest webflux instrumentations changes prove out
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried it, strict context check still fails. I believe we need to wait for netty request processing to complete before doing context leaks check. I'll create a pr for this.


public class AdviceUtils {

public static final String CONTEXT_ATTRIBUTE = AdviceUtils.class.getName() + ".Context";
public static final String ON_SPAN_END = AdviceUtils.class.getName() + ".Context";

public static String spanNameForHandler(Object handler) {
String className = ClassNames.simpleName(handler.getClass());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although this part wasn't changed in this pr getting a span name from an object is also used in other instrumentations so it would be nice if someone figured out how to do this properly. The problem here is that handler could be anything. For example SpringWebFluxTestApplication when you add

  @Component("greetingHandlerFunction")
  @Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
  static class GreetingHandlerFunction implements HandlerFunction<ServerResponse> {
    private final GreetingHandler greetingHandler

    GreetingHandlerFunction(GreetingHandler greetingHandler) {
      this.greetingHandler = greetingHandler
    }

    @Override
    Mono<ServerResponse> handle(ServerRequest request) {
      return greetingHandler.defaultGreet()
    }
  }

and change the start of greetRouterFunction to

  @Bean
  RouterFunction<ServerResponse> greetRouterFunction(GreetingHandler greetingHandler, HandlerFunction<ServerResponse> greetingHandlerFunction) {
    return route(GET("/greet"), greetingHandlerFunction

Then span name is
SpringWebFluxTestApplication$GreetingHandlerFunction$$EnhancerBySpringCGLIB$$d662c0c3.handle
When you change scope annotation to
@Scope(value = "prototype", proxyMode = ScopedProxyMode.INTERFACES)
then span name is
$Proxy119.handle
If we'd assume that handler is a spring bean we could try to unwrap it with something like spring-projects/spring-framework@efe3a35

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 I created issue for this #3813

HandlerMethod handlerMethod = (HandlerMethod) handler;
return handlerMethod.getMethod().getDeclaringClass().getName();
} else {
return handler.getClass().getName();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Handler could be a proxy so name could be SpringWebFluxTestApplication$GreetingHandlerFunction$$EnhancerBySpringCGLIB$$d662c0c3 or $Proxy119

…ava/io/opentelemetry/javaagent/instrumentation/spring/webflux/server/AdviceUtils.java

Co-authored-by: Mateusz Rzeszutek <mrzeszutek@splunk.com>
@trask
Copy link
Member Author

trask commented Aug 11, 2021

@HaloFour have you seen the cancellation issue that was fixed in #3150? I'm wondering if you have any thoughts whether that fix should be applied to the @WithSpan Mono handling? I'm trying to get a sense if it's a general issue that should be handled everywhere Monos are returned (regardless of whether we can reproduce the issue anymore that led to #3150).

@HaloFour
Copy link
Contributor

@trask

The Reactor instrumentation for Mono<T> and Flux<T> do handle cancellation, although using a different approach: https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/instrumentation/reactor-3.1/library/src/main/java/io/opentelemetry/instrumentation/reactor/ReactorAsyncOperationEndStrategy.java#L64

I also have another PR up which refactors the Reactor instrumentation to allow for multiple subscriptions and in that implementation I follow a similar approach to the PR you referenced: https://github.com/open-telemetry/opentelemetry-java-instrumentation/pull/3751/files#diff-0865720f5bd8562039a4e795c46fd7f745a94a5ba6852ff463ffa0d0424fa236R65

@trask
Copy link
Member Author

trask commented Aug 11, 2021

putting this PR on hold until #3816

@trask trask merged commit 84e9d18 into open-telemetry:main Aug 13, 2021
@trask trask deleted the update-webflux-to-instrumenter-api branch August 13, 2021 16:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants