Skip to content

Commit 15400e8

Browse files
committed
Split Webflux into client and server
1 parent 4af0dd5 commit 15400e8

File tree

13 files changed

+575
-61
lines changed

13 files changed

+575
-61
lines changed

instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webflux/SpringWebfluxInstrumentationAutoConfiguration.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ static WebClientBeanPostProcessor otelWebClientBeanPostProcessor(
4040

4141
@Bean
4242
WebFilter telemetryFilter(OpenTelemetry openTelemetry, ConfigProperties config) {
43-
return WebClientBeanPostProcessor.getWebfluxTelemetry(openTelemetry, config)
43+
return WebClientBeanPostProcessor.getWebfluxServerTelemetry(openTelemetry, config)
4444
.createWebFilterAndRegisterReactorHook();
4545
}
4646
}

instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webflux/WebClientBeanPostProcessor.java

+17-8
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77

88
import io.opentelemetry.api.OpenTelemetry;
99
import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.InstrumentationConfigUtil;
10-
import io.opentelemetry.instrumentation.spring.webflux.v5_3.SpringWebfluxTelemetry;
10+
import io.opentelemetry.instrumentation.spring.webflux.v5_3.SpringWebfluxClientTelemetry;
11+
import io.opentelemetry.instrumentation.spring.webflux.v5_3.SpringWebfluxServerTelemetry;
1112
import io.opentelemetry.instrumentation.spring.webflux.v5_3.internal.SpringWebfluxBuilderUtil;
1213
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
1314
import org.springframework.beans.factory.ObjectProvider;
@@ -31,12 +32,20 @@ final class WebClientBeanPostProcessor implements BeanPostProcessor {
3132
this.configPropertiesProvider = configPropertiesProvider;
3233
}
3334

34-
static SpringWebfluxTelemetry getWebfluxTelemetry(
35+
static SpringWebfluxClientTelemetry getWebfluxClientTelemetry(
3536
OpenTelemetry openTelemetry, ConfigProperties config) {
36-
return InstrumentationConfigUtil.configureClientAndServerBuilder(
37+
return InstrumentationConfigUtil.configureClientBuilder(
3738
config,
38-
SpringWebfluxTelemetry.builder(openTelemetry),
39-
SpringWebfluxBuilderUtil.getClientBuilderExtractor(),
39+
SpringWebfluxClientTelemetry.builder(openTelemetry),
40+
SpringWebfluxBuilderUtil.getClientBuilderExtractor())
41+
.build();
42+
}
43+
44+
static SpringWebfluxServerTelemetry getWebfluxServerTelemetry(
45+
OpenTelemetry openTelemetry, ConfigProperties config) {
46+
return InstrumentationConfigUtil.configureServerBuilder(
47+
config,
48+
SpringWebfluxServerTelemetry.builder(openTelemetry),
4049
SpringWebfluxBuilderUtil.getServerBuilderExtractor())
4150
.build();
4251
}
@@ -54,9 +63,9 @@ public Object postProcessAfterInitialization(Object bean, String beanName) {
5463
}
5564

5665
private WebClient.Builder wrapBuilder(WebClient.Builder webClientBuilder) {
57-
SpringWebfluxTelemetry instrumentation =
58-
getWebfluxTelemetry(
66+
SpringWebfluxClientTelemetry instrumentation =
67+
getWebfluxClientTelemetry(
5968
openTelemetryProvider.getObject(), configPropertiesProvider.getObject());
60-
return webClientBuilder.filters(instrumentation::addClientTracingFilter);
69+
return webClientBuilder.filters(instrumentation::addTracingFilter);
6170
}
6271
}

instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/InstrumentationConfigUtil.java

-15
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,6 @@
1919
public final class InstrumentationConfigUtil {
2020
private InstrumentationConfigUtil() {}
2121

22-
@CanIgnoreReturnValue
23-
public static <T, CLIENTREQUEST, CLIENTRESPONSE, SERVERREQUEST, SERVERRESPONSE>
24-
T configureClientAndServerBuilder(
25-
ConfigProperties config,
26-
T builder,
27-
Function<T, DefaultHttpClientInstrumenterBuilder<CLIENTREQUEST, CLIENTRESPONSE>>
28-
getClientBuilder,
29-
Function<T, DefaultHttpServerInstrumenterBuilder<SERVERREQUEST, SERVERRESPONSE>>
30-
getServerBuilder) {
31-
CommonConfig commonConfig = getConfig(config);
32-
getClientBuilder.apply(builder).configure(commonConfig);
33-
getServerBuilder.apply(builder).configure(commonConfig);
34-
return builder;
35-
}
36-
3722
@CanIgnoreReturnValue
3823
public static <T, REQUEST, RESPONSE> T configureClientBuilder(
3924
ConfigProperties config,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.spring.webflux.v5_3;
7+
8+
import io.opentelemetry.api.OpenTelemetry;
9+
import io.opentelemetry.context.propagation.ContextPropagators;
10+
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
11+
import io.opentelemetry.instrumentation.spring.webflux.v5_3.internal.WebClientTracingFilter;
12+
import java.util.List;
13+
import org.springframework.web.reactive.function.client.ClientRequest;
14+
import org.springframework.web.reactive.function.client.ClientResponse;
15+
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
16+
17+
/** Entrypoint for instrumenting Spring Webflux HTTP clients. */
18+
public final class SpringWebfluxClientTelemetry {
19+
20+
/**
21+
* Returns a new {@link SpringWebfluxClientTelemetry} configured with the given {@link
22+
* OpenTelemetry}.
23+
*/
24+
public static SpringWebfluxClientTelemetry create(OpenTelemetry openTelemetry) {
25+
return builder(openTelemetry).build();
26+
}
27+
28+
/**
29+
* Returns a new {@link SpringWebfluxClientTelemetryBuilder} configured with the given {@link
30+
* OpenTelemetry}.
31+
*/
32+
public static SpringWebfluxClientTelemetryBuilder builder(OpenTelemetry openTelemetry) {
33+
return new SpringWebfluxClientTelemetryBuilder(openTelemetry);
34+
}
35+
36+
private final Instrumenter<ClientRequest, ClientResponse> clientInstrumenter;
37+
private final ContextPropagators propagators;
38+
39+
SpringWebfluxClientTelemetry(
40+
Instrumenter<ClientRequest, ClientResponse> clientInstrumenter,
41+
ContextPropagators propagators) {
42+
this.clientInstrumenter = clientInstrumenter;
43+
this.propagators = propagators;
44+
}
45+
46+
public void addTracingFilter(List<ExchangeFilterFunction> exchangeFilterFunctions) {
47+
for (ExchangeFilterFunction filterFunction : exchangeFilterFunctions) {
48+
if (filterFunction instanceof WebClientTracingFilter) {
49+
return;
50+
}
51+
}
52+
exchangeFilterFunctions.add(new WebClientTracingFilter(clientInstrumenter, propagators));
53+
}
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.spring.webflux.v5_3;
7+
8+
import com.google.errorprone.annotations.CanIgnoreReturnValue;
9+
import io.opentelemetry.api.OpenTelemetry;
10+
import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder;
11+
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
12+
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
13+
import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractorBuilder;
14+
import io.opentelemetry.instrumentation.spring.webflux.v5_3.internal.SpringWebfluxBuilderUtil;
15+
import io.opentelemetry.instrumentation.spring.webflux.v5_3.internal.WebClientHttpAttributesGetter;
16+
import java.util.List;
17+
import java.util.Set;
18+
import java.util.function.Function;
19+
import org.springframework.web.reactive.function.client.ClientRequest;
20+
import org.springframework.web.reactive.function.client.ClientResponse;
21+
22+
/** A builder of {@link SpringWebfluxClientTelemetry}. */
23+
public final class SpringWebfluxClientTelemetryBuilder {
24+
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.spring-webflux-5.3";
25+
26+
private final DefaultHttpClientInstrumenterBuilder<ClientRequest, ClientResponse> builder;
27+
private final OpenTelemetry openTelemetry;
28+
29+
static {
30+
SpringWebfluxBuilderUtil.setClientBuilderExtractor(
31+
SpringWebfluxClientTelemetryBuilder::getBuilder);
32+
}
33+
34+
SpringWebfluxClientTelemetryBuilder(OpenTelemetry openTelemetry) {
35+
builder =
36+
DefaultHttpClientInstrumenterBuilder.create(
37+
INSTRUMENTATION_NAME, openTelemetry, WebClientHttpAttributesGetter.INSTANCE);
38+
this.openTelemetry = openTelemetry;
39+
}
40+
41+
/**
42+
* Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented
43+
* items for WebClient.
44+
*/
45+
@CanIgnoreReturnValue
46+
public SpringWebfluxClientTelemetryBuilder addAttributesExtractor(
47+
AttributesExtractor<ClientRequest, ClientResponse> attributesExtractor) {
48+
builder.addAttributeExtractor(attributesExtractor);
49+
return this;
50+
}
51+
52+
/**
53+
* Configures the HTTP WebClient request headers that will be captured as span attributes.
54+
*
55+
* @param requestHeaders A list of HTTP header names.
56+
*/
57+
@CanIgnoreReturnValue
58+
public SpringWebfluxClientTelemetryBuilder setCapturedRequestHeaders(
59+
List<String> requestHeaders) {
60+
builder.setCapturedRequestHeaders(requestHeaders);
61+
return this;
62+
}
63+
64+
/**
65+
* Configures the HTTP WebClient response headers that will be captured as span attributes.
66+
*
67+
* @param responseHeaders A list of HTTP header names.
68+
*/
69+
@CanIgnoreReturnValue
70+
public SpringWebfluxClientTelemetryBuilder setCapturedResponseHeaders(
71+
List<String> responseHeaders) {
72+
builder.setCapturedResponseHeaders(responseHeaders);
73+
return this;
74+
}
75+
76+
/**
77+
* Configures the instrumentation to recognize an alternative set of HTTP request methods.
78+
*
79+
* <p>By default, this instrumentation defines "known" methods as the ones listed in <a
80+
* href="https://www.rfc-editor.org/rfc/rfc9110.html#name-methods">RFC9110</a> and the PATCH
81+
* method defined in <a href="https://www.rfc-editor.org/rfc/rfc5789.html">RFC5789</a>.
82+
*
83+
* <p>Note: calling this method <b>overrides</b> the default known method sets completely; it does
84+
* not supplement it.
85+
*
86+
* @param knownMethods A set of recognized HTTP request methods.
87+
* @see HttpClientAttributesExtractorBuilder#setKnownMethods(Set)
88+
*/
89+
@CanIgnoreReturnValue
90+
public SpringWebfluxClientTelemetryBuilder setKnownMethods(Set<String> knownMethods) {
91+
builder.setKnownMethods(knownMethods);
92+
return this;
93+
}
94+
95+
/**
96+
* Configures the instrumentation to emit experimental HTTP client metrics.
97+
*
98+
* @param emitExperimentalHttpClientTelemetry {@code true} if the experimental HTTP client metrics
99+
* are to be emitted.
100+
*/
101+
@CanIgnoreReturnValue
102+
public SpringWebfluxClientTelemetryBuilder setEmitExperimentalHttpClientTelemetry(
103+
boolean emitExperimentalHttpClientTelemetry) {
104+
builder.setEmitExperimentalHttpClientMetrics(emitExperimentalHttpClientTelemetry);
105+
return this;
106+
}
107+
108+
/** Sets custom client {@link SpanNameExtractor} via transform function. */
109+
@CanIgnoreReturnValue
110+
public SpringWebfluxClientTelemetryBuilder setSpanNameExtractor(
111+
Function<
112+
SpanNameExtractor<? super ClientRequest>,
113+
? extends SpanNameExtractor<? super ClientRequest>>
114+
clientSpanNameExtractor) {
115+
builder.setSpanNameExtractor(clientSpanNameExtractor);
116+
return this;
117+
}
118+
119+
/**
120+
* Returns a new {@link SpringWebfluxTelemetry} with the settings of this {@link
121+
* SpringWebfluxClientTelemetryBuilder}.
122+
*/
123+
public SpringWebfluxClientTelemetry build() {
124+
return new SpringWebfluxClientTelemetry(builder.build(), openTelemetry.getPropagators());
125+
}
126+
127+
private DefaultHttpClientInstrumenterBuilder<ClientRequest, ClientResponse> getBuilder() {
128+
return builder;
129+
}
130+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.spring.webflux.v5_3;
7+
8+
import io.opentelemetry.api.OpenTelemetry;
9+
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
10+
import io.opentelemetry.instrumentation.reactor.v3_1.ContextPropagationOperator;
11+
import org.springframework.web.server.ServerWebExchange;
12+
import org.springframework.web.server.WebFilter;
13+
14+
/** Entrypoint for instrumenting Spring Webflux HTTP services. */
15+
public final class SpringWebfluxServerTelemetry {
16+
17+
/**
18+
* Returns a new {@link SpringWebfluxServerTelemetry} configured with the given {@link
19+
* OpenTelemetry}.
20+
*/
21+
public static SpringWebfluxServerTelemetry create(OpenTelemetry openTelemetry) {
22+
return builder(openTelemetry).build();
23+
}
24+
25+
/**
26+
* Returns a new {@link SpringWebfluxServerTelemetryBuilder} configured with the given {@link
27+
* OpenTelemetry}.
28+
*/
29+
public static SpringWebfluxServerTelemetryBuilder builder(OpenTelemetry openTelemetry) {
30+
return new SpringWebfluxServerTelemetryBuilder(openTelemetry);
31+
}
32+
33+
// We use ServerWebExchange (which holds both the request and response)
34+
// because we need it to get the HTTP route while instrumenting.
35+
private final Instrumenter<ServerWebExchange, ServerWebExchange> serverInstrumenter;
36+
37+
SpringWebfluxServerTelemetry(
38+
Instrumenter<ServerWebExchange, ServerWebExchange> serverInstrumenter) {
39+
this.serverInstrumenter = serverInstrumenter;
40+
}
41+
42+
public WebFilter createWebFilter() {
43+
return new TelemetryProducingWebFilter(serverInstrumenter);
44+
}
45+
46+
public WebFilter createWebFilterAndRegisterReactorHook() {
47+
registerReactorHook();
48+
return this.createWebFilter();
49+
}
50+
51+
private static void registerReactorHook() {
52+
ContextPropagationOperator.builder().build().registerOnEachOperator();
53+
}
54+
}

0 commit comments

Comments
 (0)