Pass OpenTelemetry instance to WebFlux lib tracer
MODIFY
instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/httpclients/webclient/WebClientAutoConfiguration.java
instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/httpclients/webclient/WebClientAutoConfiguration.java
package io.opentelemetry.instrumentation.spring.autoconfigure.httpclients.webclient;
+import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.instrumentation.spring.autoconfigure.httpclients.HttpClientsProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -28,7 +29,7 @@ import org.springframework.web.reactive.function.client.WebClient;
public class WebClientAutoConfiguration {
@Bean
- public WebClientBeanPostProcessor otelWebClientBeanPostProcessor() {
- return new WebClientBeanPostProcessor();
+ public WebClientBeanPostProcessor otelWebClientBeanPostProcessor(OpenTelemetry openTelemetry) {
+ return new WebClientBeanPostProcessor(openTelemetry);
}
}

MODIFY
instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/httpclients/webclient/WebClientBeanPostProcessor.java
instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/httpclients/webclient/WebClientBeanPostProcessor.java
package io.opentelemetry.instrumentation.spring.autoconfigure.httpclients.webclient;
+import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.instrumentation.spring.webflux.client.WebClientTracingFilter;
import java.util.List;
import java.util.function.Consumer;
@@ -19,26 +20,34 @@ import org.springframework.web.reactive.function.client.WebClient;
*/
final class WebClientBeanPostProcessor implements BeanPostProcessor {
+ private final OpenTelemetry openTelemetry;
+
+ WebClientBeanPostProcessor(OpenTelemetry openTelemetry) {
+ this.openTelemetry = openTelemetry;
+ }
+
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof WebClient) {
WebClient webClient = (WebClient) bean;
- return wrapBuilder(webClient.mutate()).build();
+ return wrapBuilder(openTelemetry, webClient.mutate()).build();
} else if (bean instanceof WebClient.Builder) {
WebClient.Builder webClientBuilder = (WebClient.Builder) bean;
- return wrapBuilder(webClientBuilder);
+ return wrapBuilder(openTelemetry, webClientBuilder);
}
return bean;
}
- private WebClient.Builder wrapBuilder(WebClient.Builder webClientBuilder) {
- return webClientBuilder.filters(webClientFilterFunctionConsumer());
+ private WebClient.Builder wrapBuilder(
+ OpenTelemetry openTelemetry, WebClient.Builder webClientBuilder) {
+ return webClientBuilder.filters(webClientFilterFunctionConsumer(openTelemetry));
}
- private Consumer<List<ExchangeFilterFunction>> webClientFilterFunctionConsumer() {
+ private Consumer<List<ExchangeFilterFunction>> webClientFilterFunctionConsumer(
+ OpenTelemetry openTelemetry) {
return functions -> {
if (functions.stream().noneMatch(filter -> filter instanceof WebClientTracingFilter)) {
- WebClientTracingFilter.addFilter(functions);
+ WebClientTracingFilter.addFilter(openTelemetry, functions);
}
};
}

MODIFY
instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/httpclients/webclient/WebClientBeanPostProcessorTest.java
instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/httpclients/webclient/WebClientBeanPostProcessorTest.java
@@ -7,6 +7,7 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.httpclients.webcli
import static org.assertj.core.api.Assertions.assertThat;
+import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.instrumentation.spring.webflux.client.WebClientTracingFilter;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@@ -17,7 +18,8 @@ import org.springframework.web.reactive.function.client.WebClient;
@ExtendWith(MockitoExtension.class)
class WebClientBeanPostProcessorTest {
- WebClientBeanPostProcessor webClientBeanPostProcessor = new WebClientBeanPostProcessor();
+ WebClientBeanPostProcessor webClientBeanPostProcessor =
+ new WebClientBeanPostProcessor(OpenTelemetry.noop());
@Test
@DisplayName(

MODIFY
instrumentation/spring/spring-webflux-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/webflux/client/WebClientFilterAdvice.java
instrumentation/spring/spring-webflux-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/webflux/client/WebClientFilterAdvice.java
package io.opentelemetry.javaagent.instrumentation.spring.webflux.client;
-import io.opentelemetry.instrumentation.spring.webflux.client.WebClientTracingFilter;
import net.bytebuddy.asm.Advice;
import org.springframework.web.reactive.function.client.WebClient;
public class WebClientFilterAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
- public static void onBuild(@Advice.This WebClient.Builder thiz) {
- thiz.filters(WebClientTracingFilter::addFilter);
+ public static void onBuild(@Advice.This WebClient.Builder builder) {
+ builder.filters(WebClientHelper::addFilter);
}
}

ADD
instrumentation/spring/spring-webflux-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/webflux/client/WebClientHelper.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.spring.webflux.client;
+
+import io.opentelemetry.api.GlobalOpenTelemetry;
+import io.opentelemetry.instrumentation.spring.webflux.client.WebClientTracingFilter;
+import java.util.List;
+import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
+
+public class WebClientHelper {
+
+ public static void addFilter(List<ExchangeFilterFunction> exchangeFilterFunctions) {
+ WebClientTracingFilter.addFilter(GlobalOpenTelemetry.get(), exchangeFilterFunctions);
+ }
+}

MODIFY
instrumentation/spring/spring-webflux-5.0/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/client/HttpHeadersInjectAdapter.java
instrumentation/spring/spring-webflux-5.0/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/client/HttpHeadersInjectAdapter.java
@@ -10,7 +10,7 @@ import org.springframework.web.reactive.function.client.ClientRequest;
class HttpHeadersInjectAdapter implements TextMapSetter<ClientRequest.Builder> {
- public static final HttpHeadersInjectAdapter SETTER = new HttpHeadersInjectAdapter();
+ static final HttpHeadersInjectAdapter SETTER = new HttpHeadersInjectAdapter();
@Override
public void set(ClientRequest.Builder carrier, String key, String value) {

MODIFY
instrumentation/spring/spring-webflux-5.0/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/client/SpringWebfluxHttpClientTracer.java
instrumentation/spring/spring-webflux-5.0/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/client/SpringWebfluxHttpClientTracer.java
@@ -7,6 +7,7 @@ package io.opentelemetry.instrumentation.spring.webflux.client;
import static io.opentelemetry.instrumentation.spring.webflux.client.HttpHeadersInjectAdapter.SETTER;
+import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.TextMapSetter;
@@ -21,7 +22,7 @@ import java.util.List;
import org.springframework.web.reactive.function.client.ClientRequest;
import org.springframework.web.reactive.function.client.ClientResponse;
-public class SpringWebfluxHttpClientTracer
+class SpringWebfluxHttpClientTracer
extends HttpClientTracer<ClientRequest, ClientRequest.Builder, ClientResponse> {
private static final boolean CAPTURE_EXPERIMENTAL_SPAN_ATTRIBUTES =
@@ -29,19 +30,13 @@ public class SpringWebfluxHttpClientTracer
.getBooleanProperty(
"otel.instrumentation.spring-webflux.experimental-span-attributes", false);
- private static final SpringWebfluxHttpClientTracer TRACER = new SpringWebfluxHttpClientTracer();
-
- private SpringWebfluxHttpClientTracer() {
- super(new NetPeerAttributes());
- }
-
- public static SpringWebfluxHttpClientTracer tracer() {
- return TRACER;
+ SpringWebfluxHttpClientTracer(OpenTelemetry openTelemetry) {
+ super(openTelemetry, new NetPeerAttributes());
}
private static final MethodHandle RAW_STATUS_CODE = findRawStatusCode();
- public void onCancel(Context context) {
+ void onCancel(Context context) {
if (captureExperimentalSpanAttributes()) {
Span span = Span.fromContext(context);
span.setAttribute("spring-webflux.event", "cancelled");

MODIFY
instrumentation/spring/spring-webflux-5.0/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/client/TraceWebClientSubscriber.java
instrumentation/spring/spring-webflux-5.0/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/client/TraceWebClientSubscriber.java
package io.opentelemetry.instrumentation.spring.webflux.client;
-import static io.opentelemetry.instrumentation.spring.webflux.client.SpringWebfluxHttpClientTracer.tracer;
-
import io.opentelemetry.context.Scope;
import org.reactivestreams.Subscription;
import org.springframework.web.reactive.function.client.ClientResponse;
@@ -16,17 +14,21 @@ import reactor.core.CoreSubscriber;
* Based on Spring Sleuth's Reactor instrumentation.
* https://github.com/spring-cloud/spring-cloud-sleuth/blob/master/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientBeanPostProcessor.java
*/
-public final class TraceWebClientSubscriber implements CoreSubscriber<ClientResponse> {
+final class TraceWebClientSubscriber implements CoreSubscriber<ClientResponse> {
+
+ private final SpringWebfluxHttpClientTracer tracer;
- final CoreSubscriber<? super ClientResponse> actual;
+ private final CoreSubscriber<? super ClientResponse> actual;
- final reactor.util.context.Context context;
+ private final reactor.util.context.Context context;
private final io.opentelemetry.context.Context tracingContext;
- public TraceWebClientSubscriber(
+ TraceWebClientSubscriber(
+ SpringWebfluxHttpClientTracer tracer,
CoreSubscriber<? super ClientResponse> actual,
io.opentelemetry.context.Context tracingContext) {
+ this.tracer = tracer;
this.actual = actual;
this.tracingContext = tracingContext;
this.context = actual.currentContext();
@@ -42,7 +44,7 @@ public final class TraceWebClientSubscriber implements CoreSubscriber<ClientResp
try (Scope ignored = tracingContext.makeCurrent()) {
this.actual.onNext(response);
} finally {
- tracer().end(tracingContext, response);
+ tracer.end(tracingContext, response);
}
}
@@ -51,7 +53,7 @@ public final class TraceWebClientSubscriber implements CoreSubscriber<ClientResp
try (Scope ignored = tracingContext.makeCurrent()) {
this.actual.onError(t);
} finally {
- tracer().endExceptionally(tracingContext, t);
+ tracer.endExceptionally(tracingContext, t);
}
}

MODIFY
instrumentation/spring/spring-webflux-5.0/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/client/WebClientTracingFilter.java
instrumentation/spring/spring-webflux-5.0/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/client/WebClientTracingFilter.java
package io.opentelemetry.instrumentation.spring.webflux.client;
-import static io.opentelemetry.instrumentation.spring.webflux.client.SpringWebfluxHttpClientTracer.tracer;
-
+import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import java.util.List;
@@ -23,26 +22,37 @@ import reactor.core.publisher.Mono;
*/
public class WebClientTracingFilter implements ExchangeFilterFunction {
- public static void addFilter(List<ExchangeFilterFunction> exchangeFilterFunctions) {
+ private final SpringWebfluxHttpClientTracer tracer;
+
+ private WebClientTracingFilter(SpringWebfluxHttpClientTracer tracer) {
+ this.tracer = tracer;
+ }
+
+ public static void addFilter(
+ OpenTelemetry openTelemetry, List<ExchangeFilterFunction> exchangeFilterFunctions) {
for (ExchangeFilterFunction filterFunction : exchangeFilterFunctions) {
if (filterFunction instanceof WebClientTracingFilter) {
return;
}
}
- exchangeFilterFunctions.add(0, new WebClientTracingFilter());
+ exchangeFilterFunctions.add(
+ 0, new WebClientTracingFilter(new SpringWebfluxHttpClientTracer(openTelemetry)));
}
@Override
public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {
- return new MonoWebClientTrace(request, next);
+ return new MonoWebClientTrace(tracer, request, next);
}
- public static final class MonoWebClientTrace extends Mono<ClientResponse> {
+ private static final class MonoWebClientTrace extends Mono<ClientResponse> {
- final ExchangeFunction next;
- final ClientRequest request;
+ private final SpringWebfluxHttpClientTracer tracer;
+ private final ExchangeFunction next;
+ private final ClientRequest request;
- public MonoWebClientTrace(ClientRequest request, ExchangeFunction next) {
+ private MonoWebClientTrace(
+ SpringWebfluxHttpClientTracer tracer, ClientRequest request, ExchangeFunction next) {
+ this.tracer = tracer;
this.next = next;
this.request = request;
}
@@ -50,22 +60,22 @@ public class WebClientTracingFilter implements ExchangeFilterFunction {
@Override
public void subscribe(CoreSubscriber<? super ClientResponse> subscriber) {
Context parentContext = Context.current();
- if (!tracer().shouldStartSpan(parentContext)) {
+ if (!tracer.shouldStartSpan(parentContext)) {
next.exchange(request).subscribe(subscriber);
return;
}
ClientRequest.Builder builder = ClientRequest.from(request);
- Context context = tracer().startSpan(parentContext, request, builder);
+ Context context = tracer.startSpan(parentContext, request, builder);
try (Scope ignored = context.makeCurrent()) {
this.next
.exchange(builder.build())
.doOnCancel(
() -> {
- tracer().onCancel(context);
- tracer().end(context);
+ tracer.onCancel(context);
+ tracer.end(context);
})
- .subscribe(new TraceWebClientSubscriber(subscriber, context));
+ .subscribe(new TraceWebClientSubscriber(tracer, subscriber, context));
}
}
}

Pass OpenTelemetry instance to WebFlux lib tracer (#2730)