From 2cbfec8ac2f4cb9b058459be0b521c9eecc419dd Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Tue, 14 Mar 2023 13:39:58 +0200 Subject: [PATCH] Fix spring boot 3 webmvc autoconfiguration (#8051) Related to https://github.com/open-telemetry/opentelemetry-java-instrumentation/pull/8028#issuecomment-1466496896 spring boot 3 uses `jakarta.servlet` so we need to use `WebMvcFilterAutoConfigurationSpring6 ` instead of `WebMvcFilterAutoConfiguration` --- .../build.gradle.kts | 31 ++++++---- ...ot.autoconfigure.AutoConfiguration.imports | 2 +- .../kafka/KafkaIntegrationTest.java | 6 +- ...MvcFilterAutoConfigurationSpring6Test.java | 62 +++++++++++++++++++ .../WebMvcFilterAutoConfigurationTest.java | 7 +++ 5 files changed, 94 insertions(+), 14 deletions(-) create mode 100644 instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/webmvc/WebMvcFilterAutoConfigurationSpring6Test.java diff --git a/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts b/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts index 3dbcf8da3d79..7bb99d5cb67c 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts +++ b/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts @@ -20,15 +20,16 @@ dependencies { implementation(project(":instrumentation:spring:spring-web:spring-web-3.1:library")) implementation(project(":instrumentation:spring:spring-webmvc:spring-webmvc-5.3:library")) implementation(project(":instrumentation:spring:spring-webmvc:spring-webmvc-6.0:library")) + compileOnly("javax.servlet:javax.servlet-api:3.1.0") compileOnly("jakarta.servlet:jakarta.servlet-api:5.0.0") implementation(project(":instrumentation:spring:spring-webflux:spring-webflux-5.3:library")) implementation(project(":instrumentation:micrometer:micrometer-1.5:library")) - compileOnly("org.springframework.kafka:spring-kafka:2.9.0") - compileOnly("org.springframework.boot:spring-boot-starter-actuator:$springBootVersion") - compileOnly("org.springframework.boot:spring-boot-starter-aop:$springBootVersion") - compileOnly("org.springframework.boot:spring-boot-starter-web:$springBootVersion") - compileOnly("org.springframework.boot:spring-boot-starter-webflux:$springBootVersion") + library("org.springframework.kafka:spring-kafka:2.9.0") + library("org.springframework.boot:spring-boot-starter-actuator:$springBootVersion") + library("org.springframework.boot:spring-boot-starter-aop:$springBootVersion") + library("org.springframework.boot:spring-boot-starter-web:$springBootVersion") + library("org.springframework.boot:spring-boot-starter-webflux:$springBootVersion") compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi") compileOnly("io.opentelemetry:opentelemetry-extension-annotations") @@ -44,15 +45,12 @@ dependencies { annotationProcessor("com.google.auto.service:auto-service") compileOnly("com.google.auto.service:auto-service-annotations") - testImplementation("org.springframework.kafka:spring-kafka:2.9.0") - testImplementation("org.springframework.boot:spring-boot-starter-actuator:$springBootVersion") - testImplementation("org.springframework.boot:spring-boot-starter-aop:$springBootVersion") - testImplementation("org.springframework.boot:spring-boot-starter-webflux:$springBootVersion") - testImplementation("org.springframework.boot:spring-boot-starter-web:$springBootVersion") - testImplementation("org.springframework.boot:spring-boot-starter-test:$springBootVersion") { + testLibrary("org.springframework.boot:spring-boot-starter-test:$springBootVersion") { exclude("org.junit.vintage", "junit-vintage-engine") } testImplementation("org.testcontainers:kafka") + testImplementation("javax.servlet:javax.servlet-api:3.1.0") + testImplementation("jakarta.servlet:jakarta.servlet-api:5.0.0") testImplementation(project(":testing-common")) testImplementation("io.opentelemetry:opentelemetry-sdk") @@ -69,11 +67,22 @@ dependencies { testImplementation(project(":instrumentation-annotations")) } +val latestDepTest = findProperty("testLatestDeps") as Boolean + +// spring 6 (spring boot 3) requires java 17 +if (latestDepTest) { + otelJava { + minJavaVersionSupported.set(JavaVersion.VERSION_17) + } +} + tasks.compileTestJava { options.compilerArgs.add("-parameters") } tasks.withType().configureEach { + systemProperty("testLatestDeps", latestDepTest) + // required on jdk17 jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED") jvmArgs("-XX:+IgnoreUnrecognizedVMOptions") diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 08675fa8d72a..a14ed6c7e206 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -11,4 +11,4 @@ io.opentelemetry.instrumentation.spring.autoconfigure.kafka.KafkaInstrumentation io.opentelemetry.instrumentation.spring.autoconfigure.metrics.MicrometerShimAutoConfiguration io.opentelemetry.instrumentation.spring.autoconfigure.propagators.PropagationAutoConfiguration io.opentelemetry.instrumentation.spring.autoconfigure.resources.OtelResourceAutoConfiguration -io.opentelemetry.instrumentation.spring.autoconfigure.webmvc.WebMvcFilterAutoConfiguration +io.opentelemetry.instrumentation.spring.autoconfigure.webmvc.WebMvcFilterAutoConfigurationSpring6 diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/kafka/KafkaIntegrationTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/kafka/KafkaIntegrationTest.java index 26f83b24e6c7..b8a366656e91 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/kafka/KafkaIntegrationTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/kafka/KafkaIntegrationTest.java @@ -81,7 +81,9 @@ void shouldInstrumentProducerAndConsumer() { contextRunner.run(KafkaIntegrationTest::runShouldInstrumentProducerAndConsumer); } - @SuppressWarnings("unchecked") + // In kafka 2 ops.send is deprecated. We are using it to avoid reflection because kafka 3 also has + // ops.send, although with different return type. + @SuppressWarnings({"unchecked", "deprecation"}) private static void runShouldInstrumentProducerAndConsumer( ConfigurableApplicationContext applicationContext) { KafkaTemplate kafkaTemplate = applicationContext.getBean(KafkaTemplate.class); @@ -91,7 +93,7 @@ private static void runShouldInstrumentProducerAndConsumer( () -> { kafkaTemplate.executeInTransaction( ops -> { - ops.usingCompletableFuture().send("testTopic", "10", "testSpan"); + ops.send("testTopic", "10", "testSpan"); return 0; }); }); diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/webmvc/WebMvcFilterAutoConfigurationSpring6Test.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/webmvc/WebMvcFilterAutoConfigurationSpring6Test.java new file mode 100644 index 000000000000..43a283d69145 --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/webmvc/WebMvcFilterAutoConfigurationSpring6Test.java @@ -0,0 +1,62 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.autoconfigure.webmvc; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration; +import jakarta.servlet.Filter; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; + +/** Spring Boot auto configuration test for {@link WebMvcFilterAutoConfigurationSpring6}. */ +class WebMvcFilterAutoConfigurationSpring6Test { + private final ApplicationContextRunner contextRunner = + new ApplicationContextRunner() + .withConfiguration( + AutoConfigurations.of( + OpenTelemetryAutoConfiguration.class, + WebMvcFilterAutoConfigurationSpring6.class)); + + @BeforeAll + static void setUp() { + assumeTrue(Boolean.getBoolean("testLatestDeps")); + } + + @Test + @DisplayName("when web is ENABLED should initialize WebMvcTracingFilter bean") + void webEnabled() { + this.contextRunner + .withPropertyValues("otel.springboot.web.enabled=true") + .run( + context -> + assertThat(context.getBean("otelWebMvcInstrumentationFilter", Filter.class)) + .isNotNull()); + } + + @Test + @DisplayName("when web is DISABLED should NOT initialize WebMvcTracingFilter bean") + void disabledProperty() { + this.contextRunner + .withPropertyValues("otel.springboot.web.enabled=false") + .run( + context -> + assertThat(context.containsBean("otelWebMvcInstrumentationFilter")).isFalse()); + } + + @Test + @DisplayName("when web property is MISSING should initialize WebMvcTracingFilter bean") + void noProperty() { + this.contextRunner.run( + context -> + assertThat(context.getBean("otelWebMvcInstrumentationFilter", Filter.class)) + .isNotNull()); + } +} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/webmvc/WebMvcFilterAutoConfigurationTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/webmvc/WebMvcFilterAutoConfigurationTest.java index 302ae77c9ca8..0d0e9133125c 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/webmvc/WebMvcFilterAutoConfigurationTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/webmvc/WebMvcFilterAutoConfigurationTest.java @@ -6,9 +6,11 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.webmvc; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assumptions.assumeFalse; import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration; import javax.servlet.Filter; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -22,6 +24,11 @@ class WebMvcFilterAutoConfigurationTest { AutoConfigurations.of( OpenTelemetryAutoConfiguration.class, WebMvcFilterAutoConfiguration.class)); + @BeforeAll + static void setUp() { + assumeFalse(Boolean.getBoolean("testLatestDeps")); + } + @Test @DisplayName("when web is ENABLED should initialize WebMvcTracingFilter bean") void webEnabled() {