Skip to content

Commit da94b4a

Browse files
committed
Duplicate Spring Boot 3 files for Spring Boot 4 and some more
1 parent f5d6389 commit da94b4a

File tree

11 files changed

+402
-5
lines changed

11 files changed

+402
-5
lines changed

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

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,20 @@ sourceSets {
2323
setSrcDirs(listOf("src/main/javaSpring3"))
2424
}
2525
}
26+
create("javaSpring4") {
27+
java {
28+
setSrcDirs(listOf("src/main/javaSpring4"))
29+
}
30+
}
2631
}
2732

2833
configurations {
2934
named("javaSpring3CompileOnly") {
3035
extendsFrom(configurations["compileOnly"])
3136
}
37+
named("javaSpring4CompileOnly") {
38+
extendsFrom(configurations["compileOnly"])
39+
}
3240
}
3341

3442
dependencies {
@@ -106,6 +114,14 @@ dependencies {
106114
add("javaSpring3CompileOnly", "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
107115
add("javaSpring3CompileOnly", project(":instrumentation:spring:spring-web:spring-web-3.1:library"))
108116
add("javaSpring3CompileOnly", project(":instrumentation:spring:spring-webmvc:spring-webmvc-6.0:library"))
117+
118+
// give access to common classes, e.g. InstrumentationConfigUtil
119+
add("javaSpring4CompileOnly", files(sourceSets.main.get().output.classesDirs))
120+
add("javaSpring4CompileOnly", "org.springframework.boot:spring-boot-starter-web:4.0.0-M1")
121+
add("javaSpring4CompileOnly", "org.springframework.boot:spring-boot-starter-restclient:4.0.0-M1")
122+
add("javaSpring4CompileOnly", "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
123+
add("javaSpring4CompileOnly", project(":instrumentation:spring:spring-web:spring-web-3.1:library"))
124+
add("javaSpring4CompileOnly", project(":instrumentation:spring:spring-webmvc:spring-webmvc-6.0:library"))
109125
}
110126

111127
val latestDepTest = findProperty("testLatestDeps") as Boolean
@@ -119,6 +135,7 @@ if (latestDepTest) {
119135

120136
val testJavaVersion = gradle.startParameter.projectProperties["testJavaVersion"]?.let(JavaVersion::toVersion)
121137
val testSpring3 = (testJavaVersion == null || testJavaVersion.compareTo(JavaVersion.VERSION_17) >= 0)
138+
val testSpring4 = (testJavaVersion == null || testJavaVersion.compareTo(JavaVersion.VERSION_17) >= 0)
122139

123140
testing {
124141
suites {
@@ -173,6 +190,20 @@ testing {
173190
}
174191
}
175192
}
193+
194+
val testSpring4 by registering(JvmTestSuite::class) {
195+
dependencies {
196+
implementation(project())
197+
implementation("org.springframework.boot:spring-boot-starter-web:4.0.0-M1")
198+
implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
199+
implementation(project(":instrumentation:spring:spring-web:spring-web-3.1:library"))
200+
implementation(project(":instrumentation:spring:spring-webmvc:spring-webmvc-6.0:library"))
201+
implementation("jakarta.servlet:jakarta.servlet-api:5.0.0")
202+
implementation("org.springframework.boot:spring-boot-starter-test:4.0.0-M1") {
203+
exclude("org.junit.vintage", "junit-vintage-engine")
204+
}
205+
}
206+
}
176207
}
177208
}
178209

@@ -219,6 +250,30 @@ tasks {
219250
from(sourceSets["javaSpring3"].java)
220251
}
221252

253+
named<JavaCompile>("compileJavaSpring4Java") {
254+
sourceCompatibility = "17"
255+
targetCompatibility = "17"
256+
options.release.set(17)
257+
}
258+
259+
named<JavaCompile>("compileTestSpring4Java") {
260+
sourceCompatibility = "17"
261+
targetCompatibility = "17"
262+
options.release.set(17)
263+
}
264+
265+
named<Test>("testSpring4") {
266+
isEnabled = testSpring4
267+
}
268+
269+
named<Jar>("jar") {
270+
from(sourceSets["javaSpring4"].output)
271+
}
272+
273+
named<Jar>("sourcesJar") {
274+
from(sourceSets["javaSpring4"].java)
275+
}
276+
222277
val testStableSemconv by registering(Test::class) {
223278
jvmArgs("-Dotel.semconv-stability.opt-in=database")
224279
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.spring.autoconfigure.v4_0.internal.instrumentation.annotations;
7+
8+
import org.springframework.aot.hint.MemberCategory;
9+
import org.springframework.aot.hint.RuntimeHints;
10+
import org.springframework.aot.hint.RuntimeHintsRegistrar;
11+
import org.springframework.aot.hint.TypeReference;
12+
13+
class OpenTelemetryAnnotationsRuntimeHints implements RuntimeHintsRegistrar {
14+
15+
@Override
16+
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
17+
hints
18+
.reflection()
19+
.registerType(
20+
TypeReference.of(
21+
"io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.annotations.InstrumentationWithSpanAspect"),
22+
hint -> hint.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS))
23+
.registerType(
24+
TypeReference.of(
25+
"io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.scheduling.SpringSchedulingInstrumentationAspect"),
26+
hint -> hint.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS));
27+
}
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.spring.autoconfigure.v4_0.internal.instrumentation.runtimemetrics;
7+
8+
import io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.Java17RuntimeMetricsProvider;
9+
import org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter;
10+
import org.springframework.beans.factory.support.RegisteredBean;
11+
12+
/**
13+
* Configures runtime metrics collection for Java 17+.
14+
*
15+
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change
16+
* at any time.
17+
*/
18+
public class RuntimeMetricsBeanRegistrationExcludeFilter implements BeanRegistrationExcludeFilter {
19+
@Override
20+
public boolean isExcludedFromAotProcessing(RegisteredBean registeredBean) {
21+
// The JFR-based runtime metric code is excluded from the Spring AOT processing step.
22+
// That way, this code is not included in a Spring native image application.
23+
24+
return Java17RuntimeMetricsProvider.class.getName().equals(registeredBean.getBeanName());
25+
}
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.spring.autoconfigure.v4_0.internal.instrumentation.web;
7+
8+
import io.opentelemetry.api.OpenTelemetry;
9+
import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.InstrumentationConfigUtil;
10+
import io.opentelemetry.instrumentation.spring.web.v3_1.SpringWebTelemetry;
11+
import io.opentelemetry.instrumentation.spring.web.v3_1.internal.WebTelemetryUtil;
12+
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
13+
import org.springframework.beans.factory.ObjectProvider;
14+
import org.springframework.beans.factory.config.BeanPostProcessor;
15+
import org.springframework.http.client.ClientHttpRequestInterceptor;
16+
import org.springframework.web.client.RestClient;
17+
18+
final class RestClientBeanPostProcessor implements BeanPostProcessor {
19+
20+
private final ObjectProvider<OpenTelemetry> openTelemetryProvider;
21+
private final ObjectProvider<ConfigProperties> configPropertiesProvider;
22+
23+
public RestClientBeanPostProcessor(
24+
ObjectProvider<OpenTelemetry> openTelemetryProvider,
25+
ObjectProvider<ConfigProperties> configPropertiesProvider) {
26+
this.openTelemetryProvider = openTelemetryProvider;
27+
this.configPropertiesProvider = configPropertiesProvider;
28+
}
29+
30+
@Override
31+
public Object postProcessAfterInitialization(Object bean, String beanName) {
32+
if (bean instanceof RestClient restClient) {
33+
return addRestClientInterceptorIfNotPresent(
34+
restClient, openTelemetryProvider.getObject(), configPropertiesProvider.getObject());
35+
}
36+
return bean;
37+
}
38+
39+
private static RestClient addRestClientInterceptorIfNotPresent(
40+
RestClient restClient, OpenTelemetry openTelemetry, ConfigProperties config) {
41+
ClientHttpRequestInterceptor instrumentationInterceptor = getInterceptor(openTelemetry, config);
42+
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();
55+
}
56+
57+
static ClientHttpRequestInterceptor getInterceptor(
58+
OpenTelemetry openTelemetry, ConfigProperties config) {
59+
return InstrumentationConfigUtil.configureClientBuilder(
60+
config,
61+
SpringWebTelemetry.builder(openTelemetry),
62+
WebTelemetryUtil.getBuilderExtractor())
63+
.build()
64+
.newInterceptor();
65+
}
66+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.spring.autoconfigure.v4_0.internal.instrumentation.web;
7+
8+
import io.opentelemetry.api.OpenTelemetry;
9+
import io.opentelemetry.instrumentation.spring.autoconfigure.internal.ConditionalOnEnabledInstrumentation;
10+
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
11+
import org.springframework.beans.factory.ObjectProvider;
12+
import org.springframework.boot.autoconfigure.AutoConfiguration;
13+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
14+
import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration;
15+
import org.springframework.boot.restclient.RestClientCustomizer;
16+
import org.springframework.context.annotation.Bean;
17+
import org.springframework.context.annotation.Configuration;
18+
import org.springframework.web.client.RestClient;
19+
20+
/**
21+
* Configures {@link RestClient} for tracing.
22+
*
23+
* <p>Adds OpenTelemetry instrumentation to {@link RestClient} beans after initialization.
24+
*
25+
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change
26+
* at any time.
27+
*/
28+
@ConditionalOnEnabledInstrumentation(module = "spring-web")
29+
@ConditionalOnClass(RestClient.class)
30+
@AutoConfiguration(after = RestClientAutoConfiguration.class)
31+
@Configuration
32+
public class RestClientInstrumentationAutoConfiguration {
33+
34+
@Bean
35+
static RestClientBeanPostProcessor otelRestClientBeanPostProcessor(
36+
ObjectProvider<OpenTelemetry> openTelemetryProvider,
37+
ObjectProvider<ConfigProperties> configPropertiesProvider) {
38+
return new RestClientBeanPostProcessor(openTelemetryProvider, configPropertiesProvider);
39+
}
40+
41+
@Bean
42+
RestClientCustomizer otelRestClientCustomizer(
43+
ObjectProvider<OpenTelemetry> openTelemetryProvider,
44+
ObjectProvider<ConfigProperties> configPropertiesProvider) {
45+
return builder ->
46+
builder.requestInterceptor(
47+
RestClientBeanPostProcessor.getInterceptor(
48+
openTelemetryProvider.getObject(), configPropertiesProvider.getObject()));
49+
}
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.spring.autoconfigure.v4_0.internal.instrumentation.web;
7+
8+
import io.opentelemetry.api.OpenTelemetry;
9+
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
10+
import org.springframework.beans.factory.ObjectProvider;
11+
import org.springframework.beans.factory.config.BeanPostProcessor;
12+
import org.springframework.web.client.RestTemplate;
13+
14+
final class RestTemplateBeanPostProcessor implements BeanPostProcessor {
15+
16+
private final ObjectProvider<OpenTelemetry> openTelemetryProvider;
17+
18+
private final ObjectProvider<ConfigProperties> configPropertiesProvider;
19+
20+
RestTemplateBeanPostProcessor(
21+
ObjectProvider<OpenTelemetry> openTelemetryProvider,
22+
ObjectProvider<ConfigProperties> configPropertiesProvider) {
23+
this.openTelemetryProvider = openTelemetryProvider;
24+
this.configPropertiesProvider = configPropertiesProvider;
25+
}
26+
27+
@Override
28+
public Object postProcessAfterInitialization(Object bean, String beanName) {
29+
if (!(bean instanceof RestTemplate restTemplate)) {
30+
return bean;
31+
}
32+
33+
return RestTemplateInstrumentation.addIfNotPresent(
34+
restTemplate,
35+
openTelemetryProvider.getObject(),
36+
configPropertiesProvider.getObject());
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.spring.autoconfigure.v4_0.internal.instrumentation.web;
7+
8+
import com.google.errorprone.annotations.CanIgnoreReturnValue;
9+
import io.opentelemetry.api.OpenTelemetry;
10+
import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.InstrumentationConfigUtil;
11+
import io.opentelemetry.instrumentation.spring.web.v3_1.SpringWebTelemetry;
12+
import io.opentelemetry.instrumentation.spring.web.v3_1.internal.WebTelemetryUtil;
13+
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
14+
import org.springframework.http.client.ClientHttpRequestInterceptor;
15+
import org.springframework.web.client.RestTemplate;
16+
17+
import java.util.List;
18+
19+
class RestTemplateInstrumentation {
20+
21+
private RestTemplateInstrumentation() {}
22+
23+
@CanIgnoreReturnValue
24+
static RestTemplate addIfNotPresent(
25+
RestTemplate restTemplate, OpenTelemetry openTelemetry, ConfigProperties config) {
26+
27+
ClientHttpRequestInterceptor instrumentationInterceptor =
28+
InstrumentationConfigUtil.configureClientBuilder(
29+
config,
30+
SpringWebTelemetry.builder(openTelemetry),
31+
WebTelemetryUtil.getBuilderExtractor())
32+
.build()
33+
.newInterceptor();
34+
35+
List<ClientHttpRequestInterceptor> restTemplateInterceptors = restTemplate.getInterceptors();
36+
if (restTemplateInterceptors.stream()
37+
.noneMatch(
38+
interceptor -> interceptor.getClass() == instrumentationInterceptor.getClass())) {
39+
restTemplateInterceptors.add(0, instrumentationInterceptor);
40+
}
41+
return restTemplate;
42+
}
43+
}

0 commit comments

Comments
 (0)