Skip to content

Commit 5b1236d

Browse files
committed
autoconfigure and smoke
1 parent 9ea03e9 commit 5b1236d

File tree

11 files changed

+637
-0
lines changed

11 files changed

+637
-0
lines changed

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

Lines changed: 52 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 {
@@ -110,6 +118,18 @@ dependencies {
110118
add("javaSpring3CompileOnly", project(":instrumentation:spring:spring-web:spring-web-3.1:library"))
111119
add("javaSpring3CompileOnly", project(":instrumentation:spring:spring-webmvc:spring-webmvc-6.0:library"))
112120

121+
// Spring Boot 4
122+
add("javaSpring4CompileOnly", files(sourceSets.main.get().output.classesDirs))
123+
add("javaSpring4CompileOnly", "org.springframework.boot:spring-boot-starter-web:4.0.0")
124+
add("javaSpring4CompileOnly", "org.springframework.boot:spring-boot-starter-data-jdbc:4.0.0")
125+
add("javaSpring4CompileOnly", "org.springframework.boot:spring-boot-starter-kafka:4.0.0")
126+
add("javaSpring4CompileOnly", "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
127+
add("javaSpring4CompileOnly", "jakarta.servlet:jakarta.servlet-api:6.1.0")
128+
add("javaSpring4CompileOnly", project(":instrumentation:spring:spring-web:spring-web-3.1:library"))
129+
add("javaSpring4CompileOnly", project(":instrumentation:spring:spring-webmvc:spring-webmvc-6.0:library"))
130+
add("javaSpring4CompileOnly", project(":instrumentation:kafka:kafka-clients:kafka-clients-2.6:library"))
131+
add("javaSpring4CompileOnly", project(":instrumentation:spring:spring-kafka-2.7:library"))
132+
113133
// tests don't work with spring boot 4 yet
114134
latestDepTestLibrary("org.springframework.boot:spring-boot-starter-test:3.+") // documented limitation
115135
latestDepTestLibrary("org.springframework.boot:spring-boot-starter-actuator:3.+") // documented limitation
@@ -186,6 +206,20 @@ testing {
186206
}
187207
}
188208

209+
val testSpring4 by registering(JvmTestSuite::class) {
210+
dependencies {
211+
implementation(project())
212+
implementation("org.springframework.boot:spring-boot-starter-web:4.0.0")
213+
implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
214+
implementation(project(":instrumentation:spring:spring-web:spring-web-3.1:library"))
215+
implementation(project(":instrumentation:spring:spring-webmvc:spring-webmvc-6.0:library"))
216+
implementation("jakarta.servlet:jakarta.servlet-api:6.1.0")
217+
implementation("org.springframework.boot:spring-boot-starter-test:4.0.0") {
218+
exclude("org.junit.vintage", "junit-vintage-engine")
219+
}
220+
}
221+
}
222+
189223
val testDeclarativeConfig by registering(JvmTestSuite::class) {
190224
dependencies {
191225
implementation(project())
@@ -234,12 +268,30 @@ tasks {
234268
isEnabled = testSpring3
235269
}
236270

271+
named<JavaCompile>("compileJavaSpring4Java") {
272+
sourceCompatibility = "17"
273+
targetCompatibility = "17"
274+
options.release.set(17)
275+
}
276+
277+
named<JavaCompile>("compileTestSpring4Java") {
278+
sourceCompatibility = "17"
279+
targetCompatibility = "17"
280+
options.release.set(17)
281+
}
282+
283+
named<Test>("testSpring4") {
284+
isEnabled = testSpring3 // same condition as Spring 3 (requires Java 17+)
285+
}
286+
237287
named<Jar>("jar") {
238288
from(sourceSets["javaSpring3"].output)
289+
from(sourceSets["javaSpring4"].output)
239290
}
240291

241292
named<Jar>("sourcesJar") {
242293
from(sourceSets["javaSpring3"].java)
294+
from(sourceSets["javaSpring4"].java)
243295
}
244296

245297
val testStableSemconv by registering(Test::class) {

instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/kafka/KafkaInstrumentationAutoConfiguration.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
ConcurrentKafkaListenerContainerFactory.class,
3030
DefaultKafkaProducerFactoryCustomizer.class
3131
})
32+
@org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass(
33+
"org.springframework.boot.kafka.autoconfigure.DefaultKafkaProducerFactoryCustomizer")
3234
@Configuration
3335
public class KafkaInstrumentationAutoConfiguration {
3436

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.kafka;
7+
8+
import io.opentelemetry.api.OpenTelemetry;
9+
import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig;
10+
import io.opentelemetry.instrumentation.kafkaclients.v2_6.KafkaTelemetry;
11+
import io.opentelemetry.instrumentation.spring.autoconfigure.internal.ConditionalOnEnabledInstrumentation;
12+
import io.opentelemetry.instrumentation.spring.kafka.v2_7.SpringKafkaTelemetry;
13+
import org.springframework.beans.factory.ObjectProvider;
14+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
15+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
16+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
17+
import org.springframework.boot.kafka.autoconfigure.DefaultKafkaProducerFactoryCustomizer;
18+
import org.springframework.context.annotation.Bean;
19+
import org.springframework.context.annotation.Configuration;
20+
import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
21+
import org.springframework.kafka.core.KafkaTemplate;
22+
23+
/**
24+
* Spring Boot 4+ specific Kafka instrumentation auto-configuration. This class is internal and is
25+
* hence not for public use. Its APIs are unstable and can change at any time.
26+
*/
27+
@ConditionalOnEnabledInstrumentation(module = "kafka")
28+
@ConditionalOnClass({
29+
KafkaTemplate.class,
30+
ConcurrentKafkaListenerContainerFactory.class,
31+
DefaultKafkaProducerFactoryCustomizer.class
32+
})
33+
@ConditionalOnMissingBean(name = "otelKafkaProducerFactoryCustomizer")
34+
@Configuration
35+
public class KafkaInstrumentationSpringBoot4AutoConfiguration {
36+
37+
@Bean
38+
DefaultKafkaProducerFactoryCustomizer otelKafkaProducerFactoryCustomizer(
39+
OpenTelemetry openTelemetry) {
40+
KafkaTelemetry kafkaTelemetry = KafkaTelemetry.create(openTelemetry);
41+
return producerFactory -> producerFactory.addPostProcessor(kafkaTelemetry::wrap);
42+
}
43+
44+
@Bean
45+
static SpringKafkaTelemetry getTelemetry(
46+
ObjectProvider<OpenTelemetry> openTelemetryProvider,
47+
ObjectProvider<InstrumentationConfig> configProvider) {
48+
return SpringKafkaTelemetry.builder(openTelemetryProvider.getObject())
49+
.setCaptureExperimentalSpanAttributes(
50+
configProvider
51+
.getObject()
52+
.getBoolean("otel.instrumentation.kafka.experimental-span-attributes", false))
53+
.build();
54+
}
55+
56+
// static to avoid "is not eligible for getting processed by all BeanPostProcessors" warning
57+
@Bean
58+
@ConditionalOnProperty(
59+
name = "otel.instrumentation.kafka.autoconfigure-interceptor",
60+
havingValue = "true",
61+
matchIfMissing = true)
62+
@ConditionalOnMissingBean
63+
static ConcurrentKafkaListenerContainerFactoryPostProcessor
64+
otelKafkaListenerContainerFactoryBeanPostProcessor(
65+
ObjectProvider<OpenTelemetry> openTelemetryProvider,
66+
ObjectProvider<InstrumentationConfig> configProvider) {
67+
return new ConcurrentKafkaListenerContainerFactoryPostProcessor(
68+
() -> getTelemetry(openTelemetryProvider, configProvider));
69+
}
70+
}

instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration
22
io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.annotations.InstrumentationAnnotationsAutoConfiguration
33
io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.kafka.KafkaInstrumentationAutoConfiguration
4+
io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.kafka.KafkaInstrumentationSpringBoot4AutoConfiguration
45
io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.mongo.MongoClientInstrumentationAutoConfiguration
56
io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.logging.OpenTelemetryAppenderAutoConfiguration
67
io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.jdbc.JdbcInstrumentationAutoConfiguration
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.webmvc;
7+
8+
import static org.assertj.core.api.Assertions.assertThat;
9+
10+
import io.opentelemetry.api.OpenTelemetry;
11+
import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig;
12+
import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.ConfigPropertiesBridge;
13+
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
14+
import jakarta.servlet.Filter;
15+
import java.util.Collections;
16+
import org.junit.jupiter.api.Test;
17+
import org.springframework.boot.autoconfigure.AutoConfigurations;
18+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
19+
20+
class SpringWebMvcInstrumentation7AutoConfigurationTest {
21+
22+
private final ApplicationContextRunner contextRunner =
23+
new ApplicationContextRunner()
24+
.withBean(OpenTelemetry.class, OpenTelemetry::noop)
25+
.withBean(
26+
InstrumentationConfig.class,
27+
() ->
28+
new ConfigPropertiesBridge(
29+
DefaultConfigProperties.createFromMap(Collections.emptyMap())))
30+
.withConfiguration(
31+
AutoConfigurations.of(SpringWebMvc7InstrumentationAutoConfiguration.class));
32+
33+
@Test
34+
void instrumentationEnabled() {
35+
this.contextRunner
36+
.withPropertyValues("otel.instrumentation.spring-webmvc.enabled=true")
37+
.run(context -> assertThat(context.getBean("otelWebMvcFilter", Filter.class)).isNotNull());
38+
}
39+
40+
@Test
41+
void instrumentationDisabled() {
42+
this.contextRunner
43+
.withPropertyValues("otel.instrumentation.spring-webmvc.enabled=false")
44+
.run(context -> assertThat(context.containsBean("otelWebMvcFilter")).isFalse());
45+
}
46+
47+
@Test
48+
void defaultConfiguration() {
49+
this.contextRunner.run(
50+
context -> assertThat(context.getBean("otelWebMvcFilter", Filter.class)).isNotNull());
51+
}
52+
}

settings.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ dependencyResolutionManagement {
4444
// spring boot 3.0 is not compatible with graalvm native image
4545
addSpringBootCatalog("springBoot31", "3.1.0", "3.+")
4646
addSpringBootCatalog("springBoot32", "3.2.0", "3.+")
47+
addSpringBootCatalog("springBoot40", "4.0.0", "4.+")
4748
}
4849
}
4950

@@ -161,6 +162,7 @@ include(":smoke-tests-otel-starter:spring-smoke-testing")
161162
include(":smoke-tests-otel-starter:spring-boot-2")
162163
include(":smoke-tests-otel-starter:spring-boot-3")
163164
include(":smoke-tests-otel-starter:spring-boot-3.2")
165+
include(":smoke-tests-otel-starter:spring-boot-4")
164166
include(":smoke-tests-otel-starter:spring-boot-common")
165167
include(":smoke-tests-otel-starter:spring-boot-reactive-2")
166168
include(":smoke-tests-otel-starter:spring-boot-reactive-3")
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
plugins {
2+
id("otel.java-conventions")
3+
alias(springBoot40.plugins.versions)
4+
}
5+
6+
description = "smoke-tests-otel-starter-spring-boot-4"
7+
8+
otelJava {
9+
minJavaVersionSupported.set(JavaVersion.VERSION_17)
10+
}
11+
12+
dependencies {
13+
implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))
14+
15+
implementation("org.springframework.boot:spring-boot-starter-web")
16+
implementation("org.springframework.boot:spring-boot-starter-data-jdbc")
17+
implementation("org.springframework.boot:spring-boot-starter-kafka")
18+
runtimeOnly("com.h2database:h2")
19+
20+
implementation(project(":smoke-tests-otel-starter:spring-boot-common"))
21+
testImplementation("org.springframework.boot:spring-boot-starter-test")
22+
testImplementation("org.springframework.boot:spring-boot-resttestclient")
23+
testImplementation("org.awaitility:awaitility")
24+
testImplementation(project(":instrumentation:spring:starters:spring-boot-starter"))
25+
testImplementation(project(":smoke-tests-otel-starter:spring-smoke-testing"))
26+
}
27+
28+
springBoot {
29+
mainClass = "io.opentelemetry.spring.smoketest.OtelSpringStarterSmokeTestApplication"
30+
}
31+
32+
// Disable -Werror for Spring Framework 7.0 compatibility
33+
tasks.withType<JavaCompile>().configureEach {
34+
options.compilerArgs.removeAll(listOf("-Werror"))
35+
}
36+
37+
tasks {
38+
test {
39+
usesService(gradle.sharedServices.registrations["testcontainersBuildService"].service)
40+
}
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.spring.smoketest;
7+
8+
import org.springframework.boot.SpringApplication;
9+
import org.springframework.boot.autoconfigure.SpringBootApplication;
10+
11+
@SpringBootApplication
12+
public class OtelSpringStarterSmokeTestApplication {
13+
14+
public OtelSpringStarterSmokeTestApplication() {}
15+
16+
public static void main(String[] args) {
17+
SpringApplication.run(OtelSpringStarterSmokeTestApplication.class);
18+
}
19+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
spring.application.name=otel-spring-starter-smoke-test

0 commit comments

Comments
 (0)