Skip to content

Commit 39960c1

Browse files
committed
implement check before building interceptor if already exists
1 parent b51d20b commit 39960c1

File tree

7 files changed

+86
-30
lines changed

7 files changed

+86
-30
lines changed

instrumentation/spring/spring-boot-autoconfigure/src/main/javaSpring4/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/web/RestClientBeanPostProcessorSpring4.java

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.InstrumentationConfigUtil;
1111
import io.opentelemetry.instrumentation.spring.web.v3_1.SpringWebTelemetry;
1212
import io.opentelemetry.instrumentation.spring.web.v3_1.internal.WebTelemetryUtil;
13+
import java.util.List;
14+
import java.util.concurrent.atomic.AtomicBoolean;
1315
import org.springframework.beans.factory.ObjectProvider;
1416
import org.springframework.beans.factory.config.BeanPostProcessor;
1517
import org.springframework.http.client.ClientHttpRequestInterceptor;
@@ -40,18 +42,26 @@ private static RestClient addRestClientInterceptorIfNotPresent(
4042
RestClient restClient, OpenTelemetry openTelemetry, InstrumentationConfig config) {
4143
ClientHttpRequestInterceptor instrumentationInterceptor = getInterceptor(openTelemetry, config);
4244

43-
return restClient
44-
.mutate()
45-
.requestInterceptors(
46-
interceptors -> {
47-
if (interceptors.stream()
48-
.noneMatch(
49-
interceptor ->
50-
interceptor.getClass() == instrumentationInterceptor.getClass())) {
51-
interceptors.add(0, instrumentationInterceptor);
52-
}
53-
})
54-
.build();
45+
AtomicBoolean shouldAddInterceptor = new AtomicBoolean(false);
46+
RestClient.Builder result =
47+
restClient
48+
.mutate()
49+
.requestInterceptors(
50+
interceptors -> {
51+
if (isInterceptorNotPresent(interceptors, instrumentationInterceptor)) {
52+
interceptors.add(0, instrumentationInterceptor);
53+
shouldAddInterceptor.set(true);
54+
}
55+
});
56+
57+
return shouldAddInterceptor.get() ? result.build() : restClient;
58+
}
59+
60+
private static boolean isInterceptorNotPresent(
61+
List<ClientHttpRequestInterceptor> interceptors,
62+
ClientHttpRequestInterceptor instrumentationInterceptor) {
63+
return interceptors.stream()
64+
.noneMatch(interceptor -> interceptor.getClass() == instrumentationInterceptor.getClass());
5565
}
5666

5767
static ClientHttpRequestInterceptor getInterceptor(

instrumentation/spring/spring-boot-autoconfigure/src/testSpring3/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/web/RestClientInstrumentationAutoConfigurationTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55

66
package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.web;
77

8+
import io.opentelemetry.api.OpenTelemetry;
9+
import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig;
810
import io.opentelemetry.instrumentation.spring.autoconfigure.internal.AbstractRestClientInstrumentationAutoConfigurationTest;
911
import org.springframework.boot.autoconfigure.AutoConfigurations;
12+
import org.springframework.http.client.ClientHttpRequestInterceptor;
1013

1114
class RestClientInstrumentationAutoConfigurationTest
1215
extends AbstractRestClientInstrumentationAutoConfigurationTest {
@@ -20,4 +23,10 @@ protected AutoConfigurations autoConfigurations() {
2023
protected Class<?> postProcessorClass() {
2124
return RestClientBeanPostProcessor.class;
2225
}
26+
27+
@Override
28+
protected ClientHttpRequestInterceptor getInterceptor(
29+
OpenTelemetry openTelemetry, InstrumentationConfig config) {
30+
return RestClientBeanPostProcessorSpring4.getInterceptor(openTelemetry, config);
31+
}
2332
}

instrumentation/spring/spring-boot-autoconfigure/src/testSpring4/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/web/RestClientInstrumentationSpringBoot4AutoConfigurationTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55

66
package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.web;
77

8+
import io.opentelemetry.api.OpenTelemetry;
9+
import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig;
810
import io.opentelemetry.instrumentation.spring.autoconfigure.internal.AbstractRestClientInstrumentationAutoConfigurationTest;
911
import org.springframework.boot.autoconfigure.AutoConfigurations;
12+
import org.springframework.http.client.ClientHttpRequestInterceptor;
1013

1114
class RestClientInstrumentationSpringBoot4AutoConfigurationTest
1215
extends AbstractRestClientInstrumentationAutoConfigurationTest {
@@ -20,4 +23,10 @@ protected AutoConfigurations autoConfigurations() {
2023
protected Class<?> postProcessorClass() {
2124
return RestClientBeanPostProcessorSpring4.class;
2225
}
26+
27+
@Override
28+
protected ClientHttpRequestInterceptor getInterceptor(
29+
OpenTelemetry openTelemetry, InstrumentationConfig config) {
30+
return RestClientBeanPostProcessorSpring4.getInterceptor(openTelemetry, config);
31+
}
2332
}

instrumentation/spring/spring-boot-autoconfigure/testing/build.gradle.kts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,3 @@ dependencies {
1818
compileOnly("io.opentelemetry:opentelemetry-sdk-testing")
1919
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi")
2020
}
21-
22-
tasks {
23-
compileJava {
24-
// RestClient from spring-boot-restclient:4.0.0 uses Spring Framework 7.0.1
25-
// which has @Deprecated annotations with Java 9+ attributes (since, forRemoval)
26-
sourceCompatibility = "17"
27-
targetCompatibility = "17"
28-
options.release.set(17)
29-
}
30-
}

instrumentation/spring/spring-boot-autoconfigure/testing/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/AbstractRestClientInstrumentationAutoConfigurationTest.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313
import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.ConfigPropertiesBridge;
1414
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
1515
import org.junit.jupiter.api.Test;
16+
import org.springframework.beans.factory.config.BeanPostProcessor;
1617
import org.springframework.boot.autoconfigure.AutoConfigurations;
1718
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
19+
import org.springframework.http.client.ClientHttpRequestInterceptor;
1820
import org.springframework.web.client.RestClient;
1921

2022
public abstract class AbstractRestClientInstrumentationAutoConfigurationTest {
@@ -23,6 +25,9 @@ public abstract class AbstractRestClientInstrumentationAutoConfigurationTest {
2325

2426
protected abstract Class<?> postProcessorClass();
2527

28+
protected abstract ClientHttpRequestInterceptor getInterceptor(
29+
OpenTelemetry openTelemetry, InstrumentationConfig config);
30+
2631
private final ApplicationContextRunner contextRunner =
2732
new ApplicationContextRunner()
2833
.withBean(OpenTelemetry.class, OpenTelemetry::noop)
@@ -84,4 +89,45 @@ void defaultConfiguration() {
8489
assertThat(context.getBean("otelRestClientBeanPostProcessor", postProcessorClass()))
8590
.isNotNull());
8691
}
92+
93+
@Test
94+
void shouldNotCreateNewBeanWhenInterceptorAlreadyPresent() {
95+
contextRunner.run(
96+
context -> {
97+
Object beanPostProcessor =
98+
context.getBean("otelRestClientBeanPostProcessor", postProcessorClass());
99+
100+
RestClient restClientWithInterceptor =
101+
RestClient.builder()
102+
.requestInterceptor(
103+
getInterceptor(
104+
context.getBean(OpenTelemetry.class),
105+
context.getBean(InstrumentationConfig.class)))
106+
.build();
107+
108+
RestClient processed =
109+
(RestClient)
110+
((BeanPostProcessor) beanPostProcessor)
111+
.postProcessAfterInitialization(restClientWithInterceptor, "testBean");
112+
113+
// Should return the same instance when interceptor is already present
114+
assertThat(processed).isSameAs(restClientWithInterceptor);
115+
116+
// Verify only one interceptor exists
117+
processed
118+
.mutate()
119+
.requestInterceptors(
120+
interceptors -> {
121+
long count =
122+
interceptors.stream()
123+
.filter(
124+
rti ->
125+
rti.getClass()
126+
.getName()
127+
.startsWith("io.opentelemetry.instrumentation"))
128+
.count();
129+
assertThat(count).isEqualTo(1);
130+
});
131+
});
132+
}
87133
}

smoke-tests-otel-starter/spring-boot-4/src/test/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTest.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,6 @@ void restTemplateCall(String path) {
6161

6262
@Test
6363
void restClientBuilder() {
64-
testing.clearAllExportedData();
65-
6664
RestClient restClient = restClientBuilder.baseUrl("http://localhost:" + port).build();
6765
restClient.get().uri(OtelSpringStarterSmokeTestController.PING).retrieve().body(String.class);
6866

smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -294,8 +294,6 @@ private static boolean isFlightRecorderAvailable() {
294294

295295
@Test
296296
void databaseQuery() {
297-
testing.clearAllExportedData();
298-
299297
testing.runWithSpan(
300298
"server",
301299
() -> {
@@ -317,8 +315,6 @@ void databaseQuery() {
317315

318316
@Test
319317
void restTemplate() {
320-
testing.clearAllExportedData();
321-
322318
restTemplateCall(OtelSpringStarterSmokeTestController.PING);
323319

324320
testing.waitAndAssertTraces(
@@ -332,8 +328,6 @@ void restTemplate() {
332328

333329
@Test
334330
void shouldRedactSomeUrlParameters() {
335-
testing.clearAllExportedData();
336-
337331
restTemplateCall("/test?X-Goog-Signature=39Up9jzHkxhuIhFE9594DJxe7w6cIRCg0V6ICGS0");
338332

339333
testing.waitAndAssertTraces(

0 commit comments

Comments
 (0)