From 67087a93763a4a2dcfb958ee33c17232019fc505 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 19 Apr 2024 14:21:22 +0200 Subject: [PATCH 1/9] add spring starter r2dbc support --- .../r2dbc/v1_0/R2dbcTelemetryBuilder.java | 10 ++++ .../internal/R2dbcInstrumenterBuilder.java | 17 +++++- .../build.gradle.kts | 14 +++++ .../r2dbc/R2dbcAutoConfiguration.java | 36 ++++++++++++ .../R2dbcInstrumentingPostProcessor.java | 56 +++++++++++++++++++ ...itional-spring-configuration-metadata.json | 12 ++++ .../main/resources/META-INF/spring.factories | 1 + ...ot.autoconfigure.AutoConfiguration.imports | 1 + .../src/main/resources/application.yaml | 6 ++ .../src/main/resources/schema.sql | 1 + .../spring-boot-reactive-3/build.gradle.kts | 4 ++ ...actOtelReactiveSpringStarterSmokeTest.java | 17 +++++- ...ctiveSpringStarterSmokeTestController.java | 9 ++- .../spring/smoketest/Player.java | 34 +++++++++++ .../spring/smoketest/PlayerRepository.java | 10 ++++ 15 files changed, 224 insertions(+), 4 deletions(-) create mode 100644 instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcAutoConfiguration.java create mode 100644 instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcInstrumentingPostProcessor.java create mode 100644 smoke-tests-otel-starter/spring-boot-3-reactive/src/main/resources/application.yaml create mode 100644 smoke-tests-otel-starter/spring-boot-3-reactive/src/main/resources/schema.sql create mode 100644 smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/Player.java create mode 100644 smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/PlayerRepository.java diff --git a/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/R2dbcTelemetryBuilder.java b/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/R2dbcTelemetryBuilder.java index 16627220bb42..2a84222b8af2 100644 --- a/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/R2dbcTelemetryBuilder.java +++ b/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/R2dbcTelemetryBuilder.java @@ -39,6 +39,16 @@ public R2dbcTelemetryBuilder setStatementSanitizationEnabled(boolean enabled) { return this; } + /** + * Overrides the version of the instrumentation. If not set, the version is automatically + * detected. + */ + @CanIgnoreReturnValue + public R2dbcTelemetryBuilder setInstrumentationVersion(String instrumentationVersion) { + instrumenterBuilder.setInstrumentationVersion(instrumentationVersion); + return this; + } + /** * Returns a new {@link R2dbcTelemetry} with the settings of this {@link R2dbcTelemetryBuilder}. */ diff --git a/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/internal/R2dbcInstrumenterBuilder.java b/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/internal/R2dbcInstrumenterBuilder.java index dcd74d50cbbc..fe81b5d2f18a 100644 --- a/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/internal/R2dbcInstrumenterBuilder.java +++ b/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/internal/R2dbcInstrumenterBuilder.java @@ -11,10 +11,12 @@ import io.opentelemetry.instrumentation.api.incubator.semconv.db.SqlClientAttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder; import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor; import io.opentelemetry.instrumentation.api.semconv.network.ServerAttributesExtractor; import java.util.ArrayList; import java.util.List; +import java.util.Optional; /** * This class is internal and is hence not for public use. Its APIs are unstable and can change at @@ -29,6 +31,8 @@ public final class R2dbcInstrumenterBuilder { private final List> additionalExtractors = new ArrayList<>(); + private Optional instrumentationVersion = Optional.empty(); + public R2dbcInstrumenterBuilder(OpenTelemetry openTelemetry) { this.openTelemetry = openTelemetry; } @@ -40,12 +44,21 @@ public R2dbcInstrumenterBuilder addAttributeExtractor( return this; } + @CanIgnoreReturnValue + public R2dbcInstrumenterBuilder setInstrumentationVersion(String instrumentationVersion) { + this.instrumentationVersion = Optional.of(instrumentationVersion); + return this; + } + public Instrumenter build(boolean statementSanitizationEnabled) { - return Instrumenter.builder( + InstrumenterBuilder builder = + Instrumenter.builder( openTelemetry, INSTRUMENTATION_NAME, - DbClientSpanNameExtractor.create(R2dbcSqlAttributesGetter.INSTANCE)) + DbClientSpanNameExtractor.create(R2dbcSqlAttributesGetter.INSTANCE)); + instrumentationVersion.ifPresent(builder::setInstrumentationVersion); + return builder .addAttributesExtractor( SqlClientAttributesExtractor.builder(R2dbcSqlAttributesGetter.INSTANCE) .setStatementSanitizationEnabled(statementSanitizationEnabled) diff --git a/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts b/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts index e03ad557abdf..7191cd4e8e04 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts +++ b/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts @@ -9,6 +9,18 @@ group = "io.opentelemetry.instrumentation" val versions: Map by project val springBootVersion = versions["org.springframework.boot"] +// R2DBC is shadowed to prevent org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration +// from being loaded by Spring Boot - even if the user doesn't want to use R2DBC. +sourceSets { + main { + val shadedDep = project(":instrumentation:r2dbc-1.0:library-instrumentation-shaded") + output.dir( + shadedDep.file("build/extracted/shadow"), + "builtBy" to ":instrumentation:r2dbc-1.0:library-instrumentation-shaded:extractShadowJar", + ) + } +} + dependencies { implementation("org.springframework.boot:spring-boot-autoconfigure:$springBootVersion") annotationProcessor("org.springframework.boot:spring-boot-autoconfigure-processor:$springBootVersion") @@ -17,6 +29,7 @@ dependencies { implementation(project(":instrumentation-annotations-support")) implementation(project(":instrumentation:kafka:kafka-clients:kafka-clients-2.6:library")) + compileOnly(project(path = ":instrumentation:r2dbc-1.0:library-instrumentation-shaded", configuration = "shadow")) implementation(project(":instrumentation:spring:spring-kafka-2.7:library")) implementation(project(":instrumentation:spring:spring-web:spring-web-3.1:library")) implementation(project(":instrumentation:spring:spring-webmvc:spring-webmvc-5.3:library")) @@ -36,6 +49,7 @@ dependencies { 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") + library("org.springframework.boot:spring-boot-starter-data-r2dbc:$springBootVersion") implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") implementation(project(":sdk-autoconfigure-support")) diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcAutoConfiguration.java new file mode 100644 index 000000000000..867844fd39f0 --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcAutoConfiguration.java @@ -0,0 +1,36 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.r2dbc; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.spring.autoconfigure.internal.SdkEnabled; +import io.r2dbc.spi.ConnectionFactory; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; + +@ConditionalOnBean(OpenTelemetry.class) +@ConditionalOnClass(ConnectionFactory.class) +@ConditionalOnProperty(name = "otel.instrumentation.r2dbc.enabled", matchIfMissing = true) +@Conditional(SdkEnabled.class) +@Configuration(proxyBeanMethods = false) +public class R2dbcAutoConfiguration { + + public R2dbcAutoConfiguration() {} + + @Bean + static R2dbcInstrumentingPostProcessor r2dbcInstrumentingPostProcessor( + ObjectProvider openTelemetryProvider, + @Value("${otel.instrumentation.mongo.statement-sanitizer.enabled:true}") + boolean statementSanitizationEnabled) { + return new R2dbcInstrumentingPostProcessor(openTelemetryProvider, statementSanitizationEnabled); + } +} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcInstrumentingPostProcessor.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcInstrumentingPostProcessor.java new file mode 100644 index 000000000000..74eee9984b70 --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcInstrumentingPostProcessor.java @@ -0,0 +1,56 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.r2dbc; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.internal.EmbeddedInstrumentationProperties; +import io.opentelemetry.instrumentation.r2dbc.v1_0.R2dbcTelemetry; +import io.r2dbc.spi.ConnectionFactory; +import io.r2dbc.spi.ConnectionFactoryOptions; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.boot.r2dbc.OptionsCapableConnectionFactory; + +class R2dbcInstrumentingPostProcessor implements BeanPostProcessor { + + private final ObjectProvider openTelemetryProvider; + private final boolean statementSanitizationEnabled; + + R2dbcInstrumentingPostProcessor( + ObjectProvider openTelemetryProvider, boolean statementSanitizationEnabled) { + this.openTelemetryProvider = openTelemetryProvider; + this.statementSanitizationEnabled = statementSanitizationEnabled; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) { + if (!(bean instanceof ConnectionFactory)) { + return bean; + } + ConnectionFactory connectionFactory = (ConnectionFactory) bean; + return R2dbcTelemetry.builder(openTelemetryProvider.getObject()) + .setStatementSanitizationEnabled(statementSanitizationEnabled) + // the instrumentation is embedded, so we have to use the version of this library + .setInstrumentationVersion( + EmbeddedInstrumentationProperties.findVersion( + "io.opentelemetry.spring-boot-autoconfigure")) + .build() + .wrapConnectionFactory(connectionFactory, getConnectionFactoryOptions(connectionFactory)); + } + + private static ConnectionFactoryOptions getConnectionFactoryOptions( + ConnectionFactory connectionFactory) { + OptionsCapableConnectionFactory optionsCapableConnectionFactory = + OptionsCapableConnectionFactory.unwrapFrom(connectionFactory); + if (optionsCapableConnectionFactory != null) { + return optionsCapableConnectionFactory.getOptions(); + } else { + // in practice should never happen + // fall back to empty options; or reconstruct them from the R2dbcProperties + return ConnectionFactoryOptions.builder().build(); + } + } +} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 4f05380a1bf0..0c42e391be62 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -273,6 +273,12 @@ "description": "Enable the @WithSpan annotation.", "defaultValue": true }, + { + "name": "otel.instrumentation.common.db-statement-sanitizer.enabled", + "type": "java.lang.Boolean", + "description": "Enables the DB statement sanitization for R2DBC.", + "defaultValue": true + }, { "name": "otel.instrumentation.kafka.enabled", "type": "java.lang.Boolean", @@ -332,6 +338,12 @@ "description": "Enable the Micrometer instrumentation.", "defaultValue": false }, + { + "name": "otel.instrumentation.r2dbc.enabled", + "type": "java.lang.Boolean", + "description": "Enable the R2DBC (reactive JDBC) instrumentation. Also see otel.instrumentation.common.db-statement-sanitizer.enabled.", + "defaultValue": true + }, { "name": "otel.instrumentation.spring-web.enabled", "type": "java.lang.Boolean", diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index d000fc37d823..0d95d1e0ce53 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -5,6 +5,7 @@ io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.kafka.Kafk io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.logging.OpenTelemetryAppenderAutoConfiguration,\ io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.jdbc.JdbcInstrumentationAutoConfiguration,\ io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.micrometer.MicrometerBridgeAutoConfiguration,\ +io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.r2dbc.R2dbcAutoConfiguration,\ io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.web.SpringWebInstrumentationAutoConfiguration,\ io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.webflux.SpringWebfluxInstrumentationAutoConfiguration,\ io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.webmvc.SpringWebMvc5InstrumentationAutoConfiguration 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 c717baf43107..c2d6a6daae64 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 @@ -4,6 +4,7 @@ io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.kafka.Kafk io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.logging.OpenTelemetryAppenderAutoConfiguration io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.jdbc.JdbcInstrumentationAutoConfiguration io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.micrometer.MicrometerBridgeAutoConfiguration +io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.r2dbc.R2dbcAutoConfiguration io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.web.SpringWebInstrumentationAutoConfiguration io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.webflux.SpringWebfluxInstrumentationAutoConfiguration io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.webmvc.SpringWebMvc6InstrumentationAutoConfiguration diff --git a/smoke-tests-otel-starter/spring-boot-3-reactive/src/main/resources/application.yaml b/smoke-tests-otel-starter/spring-boot-3-reactive/src/main/resources/application.yaml new file mode 100644 index 000000000000..c82c0a205a2f --- /dev/null +++ b/smoke-tests-otel-starter/spring-boot-3-reactive/src/main/resources/application.yaml @@ -0,0 +1,6 @@ +spring: + r2dbc: + url: r2dbc:h2:mem:///testdb + jpa: + hibernate: + ddl-auto: create diff --git a/smoke-tests-otel-starter/spring-boot-3-reactive/src/main/resources/schema.sql b/smoke-tests-otel-starter/spring-boot-3-reactive/src/main/resources/schema.sql new file mode 100644 index 000000000000..3700951f3c81 --- /dev/null +++ b/smoke-tests-otel-starter/spring-boot-3-reactive/src/main/resources/schema.sql @@ -0,0 +1 @@ +CREATE TABLE IF NOT EXISTS player(id INT NOT NULL AUTO_INCREMENT, name VARCHAR(255), age INT, PRIMARY KEY (id)); diff --git a/smoke-tests-otel-starter/spring-boot-reactive-3/build.gradle.kts b/smoke-tests-otel-starter/spring-boot-reactive-3/build.gradle.kts index de68e0a7d3a4..2e2585920ced 100644 --- a/smoke-tests-otel-starter/spring-boot-reactive-3/build.gradle.kts +++ b/smoke-tests-otel-starter/spring-boot-reactive-3/build.gradle.kts @@ -16,6 +16,10 @@ dependencies { implementation(project(":smoke-tests-otel-starter:spring-boot-reactive-common")) implementation("org.springframework.boot:spring-boot-starter-webflux") + implementation("org.springframework.boot:spring-boot-starter-data-r2dbc") + + runtimeOnly("com.h2database:h2") + runtimeOnly("io.r2dbc:r2dbc-h2") testImplementation("org.springframework.boot:spring-boot-starter-test") testImplementation("io.projectreactor:reactor-test") diff --git a/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelReactiveSpringStarterSmokeTest.java b/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelReactiveSpringStarterSmokeTest.java index 218ec884bbff..90a687528c3a 100644 --- a/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelReactiveSpringStarterSmokeTest.java +++ b/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelReactiveSpringStarterSmokeTest.java @@ -10,6 +10,11 @@ import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.semconv.HttpAttributes; import io.opentelemetry.semconv.UrlAttributes; +import io.opentelemetry.spring.smoketest.AbstractSpringStarterSmokeTest; +import io.opentelemetry.semconv.incubating.DbIncubatingAttributes; +import io.opentelemetry.spring.smoketest.OtelReactiveSpringStarterSmokeTestApplication; +import io.opentelemetry.spring.smoketest.OtelReactiveSpringStarterSmokeTestController; +import io.opentelemetry.spring.smoketest.SpringSmokeOtelConfiguration; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -57,6 +62,16 @@ void webClientAndWebFluxAndR2dbc() { .hasName("GET /webflux") .hasAttribute(HttpAttributes.HTTP_REQUEST_METHOD, "GET") .hasAttribute(HttpAttributes.HTTP_RESPONSE_STATUS_CODE, 200L) - .hasAttribute(HttpAttributes.HTTP_ROUTE, "/webflux"))); + .hasAttribute(HttpAttributes.HTTP_ROUTE, "/webflux"), + span -> + span.hasKind(SpanKind.CLIENT) + .hasName("SELECT testdb.PLAYER") + .hasAttribute(DbIncubatingAttributes.DB_NAME, "testdb") + .hasAttribute(DbIncubatingAttributes.DB_SQL_TABLE, "PLAYER") + .hasAttribute(DbIncubatingAttributes.DB_OPERATION, "SELECT") + .hasAttribute( + DbIncubatingAttributes.DB_STATEMENT, + "SELECT PLAYER.* FROM PLAYER WHERE PLAYER.ID = $? LIMIT ?") + .hasAttribute(DbIncubatingAttributes.DB_SYSTEM, "h2"))); } } diff --git a/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/OtelReactiveSpringStarterSmokeTestController.java b/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/OtelReactiveSpringStarterSmokeTestController.java index cff7796af178..2eebba8d6bb8 100644 --- a/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/OtelReactiveSpringStarterSmokeTestController.java +++ b/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/OtelReactiveSpringStarterSmokeTestController.java @@ -13,9 +13,16 @@ public class OtelReactiveSpringStarterSmokeTestController { public static final String WEBFLUX = "/webflux"; + private final PlayerRepository playerRepository; + + public OtelReactiveSpringStarterSmokeTestController(PlayerRepository playerRepository) { + this.playerRepository = playerRepository; + } @GetMapping(WEBFLUX) public Mono webflux() { - return Mono.just("webflux"); + return playerRepository + .findById(1) + .map(player -> "Player: " + player.getName() + " Age: " + player.getAge()); } } diff --git a/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/Player.java b/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/Player.java new file mode 100644 index 000000000000..7d14fcf5537b --- /dev/null +++ b/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/Player.java @@ -0,0 +1,34 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.spring.smoketest; + +import org.springframework.data.annotation.Id; + +public class Player { + @Id Integer id; + String name; + Integer age; + + public Player() {} + + public Player(Integer id, String name, Integer age) { + this.id = id; + this.name = name; + this.age = age; + } + + public Integer getId() { + return id; + } + + public String getName() { + return name; + } + + public Integer getAge() { + return age; + } +} diff --git a/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/PlayerRepository.java b/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/PlayerRepository.java new file mode 100644 index 000000000000..65af6a0503e1 --- /dev/null +++ b/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/PlayerRepository.java @@ -0,0 +1,10 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.spring.smoketest; + +import org.springframework.data.repository.reactive.ReactiveCrudRepository; + +public interface PlayerRepository extends ReactiveCrudRepository {} From f83082af80aa373e9c38b4f3d8528bf4d9b3e429 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 29 Apr 2024 19:44:51 +0200 Subject: [PATCH 2/9] fix test for native --- .../smoketest/AbstractOtelReactiveSpringStarterSmokeTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelReactiveSpringStarterSmokeTest.java b/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelReactiveSpringStarterSmokeTest.java index 90a687528c3a..6031bc35866f 100644 --- a/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelReactiveSpringStarterSmokeTest.java +++ b/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelReactiveSpringStarterSmokeTest.java @@ -50,6 +50,8 @@ void webClientAndWebFluxAndR2dbc() { .blockLast(); testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly(span -> span.hasName("CREATE TABLE testdb.player")), trace -> trace.hasSpansSatisfyingExactly( span -> From 4472d9cfe3575712807588e4ecaaadede01277a9 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 30 Apr 2024 15:35:29 +0200 Subject: [PATCH 3/9] fix flag name --- .../instrumentation/r2dbc/R2dbcAutoConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcAutoConfiguration.java index 867844fd39f0..cb6b88e0340f 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcAutoConfiguration.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcAutoConfiguration.java @@ -29,7 +29,7 @@ public R2dbcAutoConfiguration() {} @Bean static R2dbcInstrumentingPostProcessor r2dbcInstrumentingPostProcessor( ObjectProvider openTelemetryProvider, - @Value("${otel.instrumentation.mongo.statement-sanitizer.enabled:true}") + @Value("${otel.instrumentation.common.db-statement-sanitizer.enabled:true}") boolean statementSanitizationEnabled) { return new R2dbcInstrumentingPostProcessor(openTelemetryProvider, statementSanitizationEnabled); } From aa9662a7b9a41746d5f51896593dbc970669929d Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 30 Apr 2024 16:16:05 +0200 Subject: [PATCH 4/9] spotless --- .../smoketest/AbstractOtelReactiveSpringStarterSmokeTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelReactiveSpringStarterSmokeTest.java b/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelReactiveSpringStarterSmokeTest.java index 6031bc35866f..b0ad69f99a29 100644 --- a/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelReactiveSpringStarterSmokeTest.java +++ b/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelReactiveSpringStarterSmokeTest.java @@ -10,8 +10,8 @@ import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.semconv.HttpAttributes; import io.opentelemetry.semconv.UrlAttributes; -import io.opentelemetry.spring.smoketest.AbstractSpringStarterSmokeTest; import io.opentelemetry.semconv.incubating.DbIncubatingAttributes; +import io.opentelemetry.spring.smoketest.AbstractSpringStarterSmokeTest; import io.opentelemetry.spring.smoketest.OtelReactiveSpringStarterSmokeTestApplication; import io.opentelemetry.spring.smoketest.OtelReactiveSpringStarterSmokeTestController; import io.opentelemetry.spring.smoketest.SpringSmokeOtelConfiguration; From 4faae4d4ae9f488590a03291a07acc0881b6a3cf Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 2 May 2024 08:49:36 +0200 Subject: [PATCH 5/9] Update instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcAutoConfiguration.java Co-authored-by: Jean Bisutti --- .../instrumentation/r2dbc/R2dbcAutoConfiguration.java | 1 + 1 file changed, 1 insertion(+) diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcAutoConfiguration.java index cb6b88e0340f..c468d500eff3 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcAutoConfiguration.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcAutoConfiguration.java @@ -27,6 +27,7 @@ public class R2dbcAutoConfiguration { public R2dbcAutoConfiguration() {} @Bean + // static to avoid "is not eligible for getting processed by all BeanPostProcessors" warning static R2dbcInstrumentingPostProcessor r2dbcInstrumentingPostProcessor( ObjectProvider openTelemetryProvider, @Value("${otel.instrumentation.common.db-statement-sanitizer.enabled:true}") From 7f81caea82158cbfbad0861c30bae3fc21dd0b32 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 2 May 2024 12:38:13 +0200 Subject: [PATCH 6/9] address review comments --- .../build.gradle.kts | 4 +-- .../R2dbcInstrumentingPostProcessor.java | 23 ++++++++-------- ...ctiveSpringStarterSmokeTestController.java | 2 +- .../spring/smoketest/Player.java | 26 +++---------------- 4 files changed, 18 insertions(+), 37 deletions(-) diff --git a/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts b/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts index 7191cd4e8e04..bef2dd6d6737 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts +++ b/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts @@ -9,8 +9,8 @@ group = "io.opentelemetry.instrumentation" val versions: Map by project val springBootVersion = versions["org.springframework.boot"] -// R2DBC is shadowed to prevent org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration -// from being loaded by Spring Boot - even if the user doesn't want to use R2DBC. +// r2dbc-proxy is shadowed to prevent org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration +// from being loaded by Spring Boot (by the presence of META-INF/services/io.r2dbc.spi.ConnectionFactoryProvider) - even if the user doesn't want to use R2DBC. sourceSets { main { val shadedDep = project(":instrumentation:r2dbc-1.0:library-instrumentation-shaded") diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcInstrumentingPostProcessor.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcInstrumentingPostProcessor.java index 74eee9984b70..655fdcf974af 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcInstrumentingPostProcessor.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcInstrumentingPostProcessor.java @@ -10,6 +10,7 @@ import io.opentelemetry.instrumentation.r2dbc.v1_0.R2dbcTelemetry; import io.r2dbc.spi.ConnectionFactory; import io.r2dbc.spi.ConnectionFactoryOptions; +import org.springframework.aop.scope.ScopedProxyUtils; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.r2dbc.OptionsCapableConnectionFactory; @@ -27,18 +28,18 @@ class R2dbcInstrumentingPostProcessor implements BeanPostProcessor { @Override public Object postProcessAfterInitialization(Object bean, String beanName) { - if (!(bean instanceof ConnectionFactory)) { - return bean; + if (bean instanceof ConnectionFactory && !ScopedProxyUtils.isScopedTarget(beanName)) { + ConnectionFactory connectionFactory = (ConnectionFactory) bean; + return R2dbcTelemetry.builder(openTelemetryProvider.getObject()) + .setStatementSanitizationEnabled(statementSanitizationEnabled) + // the instrumentation is embedded, so we have to use the version of this library + .setInstrumentationVersion( + EmbeddedInstrumentationProperties.findVersion( + "io.opentelemetry.spring-boot-autoconfigure")) + .build() + .wrapConnectionFactory(connectionFactory, getConnectionFactoryOptions(connectionFactory)); } - ConnectionFactory connectionFactory = (ConnectionFactory) bean; - return R2dbcTelemetry.builder(openTelemetryProvider.getObject()) - .setStatementSanitizationEnabled(statementSanitizationEnabled) - // the instrumentation is embedded, so we have to use the version of this library - .setInstrumentationVersion( - EmbeddedInstrumentationProperties.findVersion( - "io.opentelemetry.spring-boot-autoconfigure")) - .build() - .wrapConnectionFactory(connectionFactory, getConnectionFactoryOptions(connectionFactory)); + return bean; } private static ConnectionFactoryOptions getConnectionFactoryOptions( diff --git a/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/OtelReactiveSpringStarterSmokeTestController.java b/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/OtelReactiveSpringStarterSmokeTestController.java index 2eebba8d6bb8..d2cbd9e90dd9 100644 --- a/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/OtelReactiveSpringStarterSmokeTestController.java +++ b/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/OtelReactiveSpringStarterSmokeTestController.java @@ -23,6 +23,6 @@ public OtelReactiveSpringStarterSmokeTestController(PlayerRepository playerRepos public Mono webflux() { return playerRepository .findById(1) - .map(player -> "Player: " + player.getName() + " Age: " + player.getAge()); + .map(player -> "Player: " + player.name() + " Age: " + player.age()); } } diff --git a/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/Player.java b/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/Player.java index 7d14fcf5537b..fef7611b931b 100644 --- a/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/Player.java +++ b/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/Player.java @@ -7,28 +7,8 @@ import org.springframework.data.annotation.Id; -public class Player { - @Id Integer id; - String name; - Integer age; - - public Player() {} - - public Player(Integer id, String name, Integer age) { - this.id = id; - this.name = name; - this.age = age; - } - - public Integer getId() { - return id; - } - - public String getName() { - return name; - } - - public Integer getAge() { - return age; +public record Player(@Id Integer id, String name, Integer age) { + public Player() { + this(null, null, 0); } } From c391ee919d9a2d0936e00f26cda90c96ec7b57a8 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Fri, 3 May 2024 13:33:37 +0300 Subject: [PATCH 7/9] don't exclude instrumentation version properties file --- .../build.gradle.kts | 6 ++++-- .../r2dbc/v1_0/R2dbcTelemetryBuilder.java | 10 ---------- .../internal/R2dbcInstrumenterBuilder.java | 18 ++---------------- .../r2dbc/R2dbcInstrumentingPostProcessor.java | 5 ----- .../AbstractSpringStarterSmokeTest.java | 8 ++++++++ 5 files changed, 14 insertions(+), 33 deletions(-) diff --git a/instrumentation/r2dbc-1.0/library-instrumentation-shaded/build.gradle.kts b/instrumentation/r2dbc-1.0/library-instrumentation-shaded/build.gradle.kts index d943196ba003..a12743c767ae 100644 --- a/instrumentation/r2dbc-1.0/library-instrumentation-shaded/build.gradle.kts +++ b/instrumentation/r2dbc-1.0/library-instrumentation-shaded/build.gradle.kts @@ -12,7 +12,9 @@ dependencies { tasks { shadowJar { - exclude("META-INF/**/*") + exclude { + it.path.startsWith("META-INF") && !it.path.startsWith("META-INF/io/opentelemetry/instrumentation/") + } dependencies { // including only :r2dbc-1.0:library excludes its transitive dependencies @@ -21,7 +23,7 @@ tasks { } relocate( "io.r2dbc.proxy", - "io.opentelemetry.javaagent.instrumentation.r2dbc.v1_0.shaded.io.r2dbc.proxy" + "io.opentelemetry.instrumentation.r2dbc.v1_0.shaded.io.r2dbc.proxy" ) } diff --git a/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/R2dbcTelemetryBuilder.java b/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/R2dbcTelemetryBuilder.java index 2a84222b8af2..16627220bb42 100644 --- a/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/R2dbcTelemetryBuilder.java +++ b/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/R2dbcTelemetryBuilder.java @@ -39,16 +39,6 @@ public R2dbcTelemetryBuilder setStatementSanitizationEnabled(boolean enabled) { return this; } - /** - * Overrides the version of the instrumentation. If not set, the version is automatically - * detected. - */ - @CanIgnoreReturnValue - public R2dbcTelemetryBuilder setInstrumentationVersion(String instrumentationVersion) { - instrumenterBuilder.setInstrumentationVersion(instrumentationVersion); - return this; - } - /** * Returns a new {@link R2dbcTelemetry} with the settings of this {@link R2dbcTelemetryBuilder}. */ diff --git a/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/internal/R2dbcInstrumenterBuilder.java b/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/internal/R2dbcInstrumenterBuilder.java index fe81b5d2f18a..c24a1e9230b1 100644 --- a/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/internal/R2dbcInstrumenterBuilder.java +++ b/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/internal/R2dbcInstrumenterBuilder.java @@ -11,12 +11,10 @@ import io.opentelemetry.instrumentation.api.incubator.semconv.db.SqlClientAttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; -import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder; import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor; import io.opentelemetry.instrumentation.api.semconv.network.ServerAttributesExtractor; import java.util.ArrayList; import java.util.List; -import java.util.Optional; /** * This class is internal and is hence not for public use. Its APIs are unstable and can change at @@ -31,8 +29,6 @@ public final class R2dbcInstrumenterBuilder { private final List> additionalExtractors = new ArrayList<>(); - private Optional instrumentationVersion = Optional.empty(); - public R2dbcInstrumenterBuilder(OpenTelemetry openTelemetry) { this.openTelemetry = openTelemetry; } @@ -44,21 +40,11 @@ public R2dbcInstrumenterBuilder addAttributeExtractor( return this; } - @CanIgnoreReturnValue - public R2dbcInstrumenterBuilder setInstrumentationVersion(String instrumentationVersion) { - this.instrumentationVersion = Optional.of(instrumentationVersion); - return this; - } - public Instrumenter build(boolean statementSanitizationEnabled) { - - InstrumenterBuilder builder = - Instrumenter.builder( + return Instrumenter.builder( openTelemetry, INSTRUMENTATION_NAME, - DbClientSpanNameExtractor.create(R2dbcSqlAttributesGetter.INSTANCE)); - instrumentationVersion.ifPresent(builder::setInstrumentationVersion); - return builder + DbClientSpanNameExtractor.create(R2dbcSqlAttributesGetter.INSTANCE)) .addAttributesExtractor( SqlClientAttributesExtractor.builder(R2dbcSqlAttributesGetter.INSTANCE) .setStatementSanitizationEnabled(statementSanitizationEnabled) diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcInstrumentingPostProcessor.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcInstrumentingPostProcessor.java index 655fdcf974af..38b19a3a4b85 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcInstrumentingPostProcessor.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/instrumentation/r2dbc/R2dbcInstrumentingPostProcessor.java @@ -6,7 +6,6 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.r2dbc; import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.instrumentation.api.internal.EmbeddedInstrumentationProperties; import io.opentelemetry.instrumentation.r2dbc.v1_0.R2dbcTelemetry; import io.r2dbc.spi.ConnectionFactory; import io.r2dbc.spi.ConnectionFactoryOptions; @@ -32,10 +31,6 @@ public Object postProcessAfterInitialization(Object bean, String beanName) { ConnectionFactory connectionFactory = (ConnectionFactory) bean; return R2dbcTelemetry.builder(openTelemetryProvider.getObject()) .setStatementSanitizationEnabled(statementSanitizationEnabled) - // the instrumentation is embedded, so we have to use the version of this library - .setInstrumentationVersion( - EmbeddedInstrumentationProperties.findVersion( - "io.opentelemetry.spring-boot-autoconfigure")) .build() .wrapConnectionFactory(connectionFactory, getConnectionFactoryOptions(connectionFactory)); } diff --git a/smoke-tests-otel-starter/spring-smoke-testing/src/main/java/io/opentelemetry/spring/smoketest/AbstractSpringStarterSmokeTest.java b/smoke-tests-otel-starter/spring-smoke-testing/src/main/java/io/opentelemetry/spring/smoketest/AbstractSpringStarterSmokeTest.java index 65e4c7ce61f9..c9f823099320 100644 --- a/smoke-tests-otel-starter/spring-smoke-testing/src/main/java/io/opentelemetry/spring/smoketest/AbstractSpringStarterSmokeTest.java +++ b/smoke-tests-otel-starter/spring-smoke-testing/src/main/java/io/opentelemetry/spring/smoketest/AbstractSpringStarterSmokeTest.java @@ -34,7 +34,15 @@ void checkSpringLogs(CapturedOutput output) { // only look for WARN and ERROR log level, e.g. [Test worker] WARN .doesNotContain("] WARN") .doesNotContain("] ERROR") + .satisfies( + s -> { + if (!s.toString() + .contains( + "Unable to load io.netty.resolver.dns.macos.MacOSDnsServerAddressStreamProvider")) { + assertThat(s).doesNotContain("] ERROR") // not a warning in Spring Boot 2 .doesNotContain("is not eligible for getting processed by all BeanPostProcessors"); + } + }); } } From 4cc2b904746c4c495b0323901d05cb91f3ef6887 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Fri, 3 May 2024 14:42:24 +0300 Subject: [PATCH 8/9] extract shadow jar for spring and javaagent separately --- .../library-instrumentation-shaded/build.gradle.kts | 7 +++++++ .../spring/spring-boot-autoconfigure/build.gradle.kts | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/instrumentation/r2dbc-1.0/library-instrumentation-shaded/build.gradle.kts b/instrumentation/r2dbc-1.0/library-instrumentation-shaded/build.gradle.kts index a12743c767ae..7551f9c0cf68 100644 --- a/instrumentation/r2dbc-1.0/library-instrumentation-shaded/build.gradle.kts +++ b/instrumentation/r2dbc-1.0/library-instrumentation-shaded/build.gradle.kts @@ -30,6 +30,13 @@ tasks { val extractShadowJar by registering(Copy::class) { dependsOn(shadowJar) from(zipTree(shadowJar.get().archiveFile)) + exclude("META-INF/**") into("build/extracted/shadow") } + + val extractShadowJarSpring by registering(Copy::class) { + dependsOn(shadowJar) + from(zipTree(shadowJar.get().archiveFile)) + into("build/extracted/shadow-spring") + } } diff --git a/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts b/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts index bef2dd6d6737..38199861d7a9 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts +++ b/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts @@ -15,8 +15,8 @@ sourceSets { main { val shadedDep = project(":instrumentation:r2dbc-1.0:library-instrumentation-shaded") output.dir( - shadedDep.file("build/extracted/shadow"), - "builtBy" to ":instrumentation:r2dbc-1.0:library-instrumentation-shaded:extractShadowJar", + shadedDep.file("build/extracted/shadow-spring"), + "builtBy" to ":instrumentation:r2dbc-1.0:library-instrumentation-shaded:extractShadowJarSpring", ) } } From 5ae374eef7ba1e248de422889d319b428a2d334b Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 10 May 2024 13:18:58 +0200 Subject: [PATCH 9/9] fix r2dbc test --- .../spring-boot-reactive-2/build.gradle.kts | 4 +++ .../build.gradle.kts | 1 + ...actOtelReactiveSpringStarterSmokeTest.java | 22 +++++++++------- ...ctiveSpringStarterSmokeTestController.java | 2 +- .../spring/smoketest/Player.java | 26 ++++++++++++++++--- .../src/main/resources/application.yaml | 0 .../src/main/resources/schema.sql | 0 .../AbstractSpringStarterSmokeTest.java | 7 +++-- 8 files changed, 45 insertions(+), 17 deletions(-) rename smoke-tests-otel-starter/{spring-boot-3-reactive => spring-boot-reactive-common}/src/main/resources/application.yaml (100%) rename smoke-tests-otel-starter/{spring-boot-3-reactive => spring-boot-reactive-common}/src/main/resources/schema.sql (100%) diff --git a/smoke-tests-otel-starter/spring-boot-reactive-2/build.gradle.kts b/smoke-tests-otel-starter/spring-boot-reactive-2/build.gradle.kts index 315c1f77694e..7d026d937396 100644 --- a/smoke-tests-otel-starter/spring-boot-reactive-2/build.gradle.kts +++ b/smoke-tests-otel-starter/spring-boot-reactive-2/build.gradle.kts @@ -11,6 +11,10 @@ dependencies { implementation(project(":smoke-tests-otel-starter:spring-boot-reactive-common")) implementation("org.springframework.boot:spring-boot-starter-webflux") + implementation("org.springframework.boot:spring-boot-starter-data-r2dbc") + + runtimeOnly("com.h2database:h2") + runtimeOnly("io.r2dbc:r2dbc-h2") testImplementation("org.springframework.boot:spring-boot-starter-test") testImplementation("io.projectreactor:reactor-test") diff --git a/smoke-tests-otel-starter/spring-boot-reactive-common/build.gradle.kts b/smoke-tests-otel-starter/spring-boot-reactive-common/build.gradle.kts index 2bfc4d850c28..ecd694186b28 100644 --- a/smoke-tests-otel-starter/spring-boot-reactive-common/build.gradle.kts +++ b/smoke-tests-otel-starter/spring-boot-reactive-common/build.gradle.kts @@ -13,6 +13,7 @@ dependencies { compileOnly("org.springframework.boot:spring-boot-starter-web") compileOnly("org.springframework.boot:spring-boot-starter-webflux") compileOnly("org.springframework.boot:spring-boot-starter-test") + compileOnly("org.springframework.boot:spring-boot-starter-data-r2dbc") api(project(":smoke-tests-otel-starter:spring-smoke-testing")) } diff --git a/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelReactiveSpringStarterSmokeTest.java b/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelReactiveSpringStarterSmokeTest.java index b0ad69f99a29..27a427ef02a4 100644 --- a/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelReactiveSpringStarterSmokeTest.java +++ b/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelReactiveSpringStarterSmokeTest.java @@ -11,10 +11,6 @@ import io.opentelemetry.semconv.HttpAttributes; import io.opentelemetry.semconv.UrlAttributes; import io.opentelemetry.semconv.incubating.DbIncubatingAttributes; -import io.opentelemetry.spring.smoketest.AbstractSpringStarterSmokeTest; -import io.opentelemetry.spring.smoketest.OtelReactiveSpringStarterSmokeTestApplication; -import io.opentelemetry.spring.smoketest.OtelReactiveSpringStarterSmokeTestController; -import io.opentelemetry.spring.smoketest.SpringSmokeOtelConfiguration; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -67,13 +63,21 @@ void webClientAndWebFluxAndR2dbc() { .hasAttribute(HttpAttributes.HTTP_ROUTE, "/webflux"), span -> span.hasKind(SpanKind.CLIENT) - .hasName("SELECT testdb.PLAYER") + .satisfies( + s -> + assertThat(s.getName()) + .isEqualToIgnoringCase("SELECT testdb.PLAYER")) .hasAttribute(DbIncubatingAttributes.DB_NAME, "testdb") - .hasAttribute(DbIncubatingAttributes.DB_SQL_TABLE, "PLAYER") + .hasAttributesSatisfying( + a -> + assertThat(a.get(DbIncubatingAttributes.DB_SQL_TABLE)) + .isEqualToIgnoringCase("PLAYER")) .hasAttribute(DbIncubatingAttributes.DB_OPERATION, "SELECT") - .hasAttribute( - DbIncubatingAttributes.DB_STATEMENT, - "SELECT PLAYER.* FROM PLAYER WHERE PLAYER.ID = $? LIMIT ?") + .hasAttributesSatisfying( + a -> + assertThat(a.get(DbIncubatingAttributes.DB_STATEMENT)) + .isEqualToIgnoringCase( + "SELECT PLAYER.* FROM PLAYER WHERE PLAYER.ID = $? LIMIT ?")) .hasAttribute(DbIncubatingAttributes.DB_SYSTEM, "h2"))); } } diff --git a/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/OtelReactiveSpringStarterSmokeTestController.java b/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/OtelReactiveSpringStarterSmokeTestController.java index d2cbd9e90dd9..2eebba8d6bb8 100644 --- a/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/OtelReactiveSpringStarterSmokeTestController.java +++ b/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/OtelReactiveSpringStarterSmokeTestController.java @@ -23,6 +23,6 @@ public OtelReactiveSpringStarterSmokeTestController(PlayerRepository playerRepos public Mono webflux() { return playerRepository .findById(1) - .map(player -> "Player: " + player.name() + " Age: " + player.age()); + .map(player -> "Player: " + player.getName() + " Age: " + player.getAge()); } } diff --git a/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/Player.java b/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/Player.java index fef7611b931b..7d14fcf5537b 100644 --- a/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/Player.java +++ b/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/java/io/opentelemetry/spring/smoketest/Player.java @@ -7,8 +7,28 @@ import org.springframework.data.annotation.Id; -public record Player(@Id Integer id, String name, Integer age) { - public Player() { - this(null, null, 0); +public class Player { + @Id Integer id; + String name; + Integer age; + + public Player() {} + + public Player(Integer id, String name, Integer age) { + this.id = id; + this.name = name; + this.age = age; + } + + public Integer getId() { + return id; + } + + public String getName() { + return name; + } + + public Integer getAge() { + return age; } } diff --git a/smoke-tests-otel-starter/spring-boot-3-reactive/src/main/resources/application.yaml b/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/resources/application.yaml similarity index 100% rename from smoke-tests-otel-starter/spring-boot-3-reactive/src/main/resources/application.yaml rename to smoke-tests-otel-starter/spring-boot-reactive-common/src/main/resources/application.yaml diff --git a/smoke-tests-otel-starter/spring-boot-3-reactive/src/main/resources/schema.sql b/smoke-tests-otel-starter/spring-boot-reactive-common/src/main/resources/schema.sql similarity index 100% rename from smoke-tests-otel-starter/spring-boot-3-reactive/src/main/resources/schema.sql rename to smoke-tests-otel-starter/spring-boot-reactive-common/src/main/resources/schema.sql diff --git a/smoke-tests-otel-starter/spring-smoke-testing/src/main/java/io/opentelemetry/spring/smoketest/AbstractSpringStarterSmokeTest.java b/smoke-tests-otel-starter/spring-smoke-testing/src/main/java/io/opentelemetry/spring/smoketest/AbstractSpringStarterSmokeTest.java index c9f823099320..378d402e785b 100644 --- a/smoke-tests-otel-starter/spring-smoke-testing/src/main/java/io/opentelemetry/spring/smoketest/AbstractSpringStarterSmokeTest.java +++ b/smoke-tests-otel-starter/spring-smoke-testing/src/main/java/io/opentelemetry/spring/smoketest/AbstractSpringStarterSmokeTest.java @@ -31,17 +31,16 @@ void setUpTesting() { void checkSpringLogs(CapturedOutput output) { // warnings are emitted if the auto-configuration have non-fatal problems assertThat(output) + // not a warning in Spring Boot 2 + .doesNotContain("is not eligible for getting processed by all BeanPostProcessors") // only look for WARN and ERROR log level, e.g. [Test worker] WARN .doesNotContain("] WARN") - .doesNotContain("] ERROR") .satisfies( s -> { if (!s.toString() .contains( "Unable to load io.netty.resolver.dns.macos.MacOSDnsServerAddressStreamProvider")) { - assertThat(s).doesNotContain("] ERROR") - // not a warning in Spring Boot 2 - .doesNotContain("is not eligible for getting processed by all BeanPostProcessors"); + assertThat(s).doesNotContain("] ERROR"); } }); }