Skip to content

Commit 79beda9

Browse files
committed
Split Webflux into client and server
1 parent 4af0dd5 commit 79beda9

File tree

10 files changed

+557
-37
lines changed

10 files changed

+557
-37
lines changed
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+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
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.DefaultHttpServerInstrumenterBuilder;
11+
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
12+
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
13+
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerAttributesExtractorBuilder;
14+
import io.opentelemetry.instrumentation.spring.webflux.v5_3.internal.Experimental;
15+
import io.opentelemetry.instrumentation.spring.webflux.v5_3.internal.SpringWebfluxBuilderUtil;
16+
import java.util.List;
17+
import java.util.Set;
18+
import java.util.function.Function;
19+
import org.springframework.web.server.ServerWebExchange;
20+
21+
/** A builder of {@link SpringWebfluxServerTelemetry}. */
22+
public final class SpringWebfluxServerTelemetryBuilder {
23+
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.spring-webflux-5.3";
24+
25+
private final DefaultHttpServerInstrumenterBuilder<ServerWebExchange, ServerWebExchange>
26+
serverBuilder;
27+
28+
static {
29+
SpringWebfluxBuilderUtil.setServerBuilderExtractor(
30+
SpringWebfluxServerTelemetryBuilder::getServerBuilder);
31+
}
32+
33+
SpringWebfluxServerTelemetryBuilder(OpenTelemetry openTelemetry) {
34+
serverBuilder =
35+
DefaultHttpServerInstrumenterBuilder.create(
36+
INSTRUMENTATION_NAME,
37+
openTelemetry,
38+
WebfluxServerHttpAttributesGetter.INSTANCE,
39+
WebfluxTextMapGetter.INSTANCE);
40+
}
41+
42+
/**
43+
* Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented
44+
* items.
45+
*/
46+
@CanIgnoreReturnValue
47+
public SpringWebfluxServerTelemetryBuilder addAttributesExtractor(
48+
AttributesExtractor<ServerWebExchange, ServerWebExchange> attributesExtractor) {
49+
serverBuilder.addAttributesExtractor(attributesExtractor);
50+
return this;
51+
}
52+
53+
/**
54+
* Configures the HTTP request headers that will be captured as span attributes from server
55+
* instrumentation.
56+
*
57+
* @param requestHeaders A list of HTTP header names.
58+
*/
59+
@CanIgnoreReturnValue
60+
public SpringWebfluxServerTelemetryBuilder setCapturedRequestHeaders(
61+
List<String> requestHeaders) {
62+
serverBuilder.setCapturedRequestHeaders(requestHeaders);
63+
return this;
64+
}
65+
66+
/**
67+
* Configures the HTTP response headers that will be captured as span attributes from server
68+
* instrumentation.
69+
*
70+
* @param responseHeaders A list of HTTP header names.
71+
*/
72+
@CanIgnoreReturnValue
73+
public SpringWebfluxServerTelemetryBuilder setCapturedResponseHeaders(
74+
List<String> responseHeaders) {
75+
serverBuilder.setCapturedResponseHeaders(responseHeaders);
76+
return this;
77+
}
78+
79+
/**
80+
* Configures the instrumentation to recognize an alternative set of HTTP request methods.
81+
*
82+
* <p>By default, this instrumentation defines "known" methods as the ones listed in <a
83+
* href="https://www.rfc-editor.org/rfc/rfc9110.html#name-methods">RFC9110</a> and the PATCH
84+
* method defined in <a href="https://www.rfc-editor.org/rfc/rfc5789.html">RFC5789</a>.
85+
*
86+
* <p>Note: calling this method <b>overrides</b> the default known method sets completely; it does
87+
* not supplement it.
88+
*
89+
* @param knownMethods A set of recognized HTTP request methods.
90+
* @see HttpServerAttributesExtractorBuilder#setKnownMethods(Set)
91+
*/
92+
@CanIgnoreReturnValue
93+
public SpringWebfluxServerTelemetryBuilder setKnownMethods(Set<String> knownMethods) {
94+
serverBuilder.setKnownMethods(knownMethods);
95+
return this;
96+
}
97+
98+
/**
99+
* Configures the instrumentation to emit experimental HTTP server metrics.
100+
*
101+
* @param emitExperimentalHttpServerTelemetry {@code true} if the experimental HTTP server metrics
102+
* are to be emitted.
103+
* @deprecated Use {@link
104+
* Experimental#setEmitExperimentalHttpServerMetrics(SpringWebfluxServerTelemetryBuilder,
105+
* boolean)} instead.
106+
*/
107+
@Deprecated
108+
@CanIgnoreReturnValue
109+
public SpringWebfluxServerTelemetryBuilder setEmitExperimentalHttpServerTelemetry(
110+
boolean emitExperimentalHttpServerTelemetry) {
111+
serverBuilder.setEmitExperimentalHttpServerMetrics(emitExperimentalHttpServerTelemetry);
112+
return this;
113+
}
114+
115+
/** Sets custom server {@link SpanNameExtractor} via transform function. */
116+
@CanIgnoreReturnValue
117+
public SpringWebfluxServerTelemetryBuilder setSpanNameExtractor(
118+
Function<
119+
SpanNameExtractor<? super ServerWebExchange>,
120+
? extends SpanNameExtractor<? super ServerWebExchange>>
121+
serverSpanNameExtractor) {
122+
serverBuilder.setSpanNameExtractor(serverSpanNameExtractor);
123+
return this;
124+
}
125+
126+
/**
127+
* Returns a new {@link SpringWebfluxTelemetry} with the settings of this {@link
128+
* SpringWebfluxServerTelemetryBuilder}.
129+
*/
130+
public SpringWebfluxServerTelemetry build() {
131+
return new SpringWebfluxServerTelemetry(serverBuilder.build());
132+
}
133+
134+
private DefaultHttpServerInstrumenterBuilder<ServerWebExchange, ServerWebExchange>
135+
getServerBuilder() {
136+
return serverBuilder;
137+
}
138+
}

0 commit comments

Comments
 (0)