From 77ed62e6aad09b519118921859a255c6a6b4d1b0 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Fri, 23 May 2025 14:52:15 +0300 Subject: [PATCH 1/3] Add instrumentation for vertx-sql-client 5.0 --- .../javaagent/build.gradle.kts | 2 +- .../v4_0/sql/VertxSqlClientSingletons.java | 132 ------ .../javaagent/build.gradle.kts | 12 +- .../vertx/v4_0/sql/HandlerWrapper.java | 0 .../vertx/v4_0/sql/PoolInstrumentation.java | 20 +- .../sql/QueryExecutorInstrumentation.java | 6 +- .../QueryResultBuilderInstrumentation.java | 7 +- .../sql/SqlClientBaseInstrumentation.java | 14 +- .../sql/TransactionImplInstrumentation.java | 0 .../VertxSqlClientInstrumentationModule.java | 8 + .../v4_0/sql/VertxSqlClientSingletons.java | 50 ++ .../vertx/v4_0/sql/VertxSqlClientTest.java | 0 .../javaagent/build.gradle.kts | 39 ++ .../vertx/v5_0/sql/CompletableWrapper.java | 35 ++ .../vertx/v5_0/sql/PoolInstrumentation.java | 106 +++++ .../sql/QueryExecutorInstrumentation.java | 124 +++++ .../QueryResultBuilderInstrumentation.java | 48 ++ .../sql/SqlClientBaseInstrumentation.java | 76 +++ .../sql/TransactionImplInstrumentation.java | 39 ++ .../VertxSqlClientInstrumentationModule.java | 52 ++ .../v5_0/sql/VertxSqlClientSingletons.java | 50 ++ .../vertx/v5_0/sql/VertxSqlClientTest.java | 445 ++++++++++++++++++ .../javaagent/build.gradle.kts | 8 + .../sql/VertxSqlClientAttributesGetter.java | 4 +- .../VertxSqlClientNetAttributesGetter.java | 5 +- .../vertx}/sql/VertxSqlClientRequest.java | 2 +- .../vertx/sql/VertxSqlClientUtil.java | 91 ++++ .../sql/VertxSqlInstrumenterFactory.java | 47 ++ .../sqlclient/impl/QueryExecutorUtil.java | 0 settings.gradle.kts | 4 +- 30 files changed, 1256 insertions(+), 170 deletions(-) delete mode 100644 instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientSingletons.java rename instrumentation/vertx/{ => vertx-sql-client}/vertx-sql-client-4.0/javaagent/build.gradle.kts (63%) rename instrumentation/vertx/{ => vertx-sql-client}/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/HandlerWrapper.java (100%) rename instrumentation/vertx/{ => vertx-sql-client}/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/PoolInstrumentation.java (83%) rename instrumentation/vertx/{ => vertx-sql-client}/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/QueryExecutorInstrumentation.java (92%) rename instrumentation/vertx/{ => vertx-sql-client}/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/QueryResultBuilderInstrumentation.java (89%) rename instrumentation/vertx/{ => vertx-sql-client}/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/SqlClientBaseInstrumentation.java (80%) rename instrumentation/vertx/{ => vertx-sql-client}/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/TransactionImplInstrumentation.java (100%) rename instrumentation/vertx/{ => vertx-sql-client}/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientInstrumentationModule.java (82%) create mode 100644 instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientSingletons.java rename instrumentation/vertx/{ => vertx-sql-client}/vertx-sql-client-4.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientTest.java (100%) create mode 100644 instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/build.gradle.kts create mode 100644 instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/CompletableWrapper.java create mode 100644 instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/PoolInstrumentation.java create mode 100644 instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/QueryExecutorInstrumentation.java create mode 100644 instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/QueryResultBuilderInstrumentation.java create mode 100644 instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/SqlClientBaseInstrumentation.java create mode 100644 instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/TransactionImplInstrumentation.java create mode 100644 instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/VertxSqlClientInstrumentationModule.java create mode 100644 instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/VertxSqlClientSingletons.java create mode 100644 instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/VertxSqlClientTest.java create mode 100644 instrumentation/vertx/vertx-sql-client/vertx-sql-client-common/javaagent/build.gradle.kts rename instrumentation/vertx/{vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0 => vertx-sql-client/vertx-sql-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx}/sql/VertxSqlClientAttributesGetter.java (96%) rename instrumentation/vertx/{vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0 => vertx-sql-client/vertx-sql-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx}/sql/VertxSqlClientNetAttributesGetter.java (72%) rename instrumentation/vertx/{vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0 => vertx-sql-client/vertx-sql-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx}/sql/VertxSqlClientRequest.java (93%) create mode 100644 instrumentation/vertx/vertx-sql-client/vertx-sql-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/sql/VertxSqlClientUtil.java create mode 100644 instrumentation/vertx/vertx-sql-client/vertx-sql-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/sql/VertxSqlInstrumenterFactory.java rename instrumentation/vertx/{vertx-sql-client-4.0 => vertx-sql-client/vertx-sql-client-common}/javaagent/src/main/java/io/vertx/sqlclient/impl/QueryExecutorUtil.java (100%) diff --git a/instrumentation/hibernate/hibernate-reactive-1.0/javaagent/build.gradle.kts b/instrumentation/hibernate/hibernate-reactive-1.0/javaagent/build.gradle.kts index 6f4ee50c78d7..21d9621fb450 100644 --- a/instrumentation/hibernate/hibernate-reactive-1.0/javaagent/build.gradle.kts +++ b/instrumentation/hibernate/hibernate-reactive-1.0/javaagent/build.gradle.kts @@ -15,7 +15,7 @@ dependencies { compileOnly("org.hibernate.reactive:hibernate-reactive-core:1.0.0.Final") testInstrumentation(project(":instrumentation:netty:netty-4.1:javaagent")) - testInstrumentation(project(":instrumentation:vertx:vertx-sql-client-4.0:javaagent")) + testInstrumentation(project(":instrumentation:vertx:vertx-sql-client:vertx-sql-client-4.0:javaagent")) library("io.vertx:vertx-sql-client:4.4.2") compileOnly("io.vertx:vertx-codegen:4.4.2") diff --git a/instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientSingletons.java b/instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientSingletons.java deleted file mode 100644 index 071a27b768c3..000000000000 --- a/instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientSingletons.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql; - -import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.context.Context; -import io.opentelemetry.context.Scope; -import io.opentelemetry.instrumentation.api.incubator.semconv.db.DbClientMetrics; -import io.opentelemetry.instrumentation.api.incubator.semconv.db.DbClientSpanNameExtractor; -import io.opentelemetry.instrumentation.api.incubator.semconv.db.SqlClientAttributesExtractor; -import io.opentelemetry.instrumentation.api.incubator.semconv.net.PeerServiceAttributesExtractor; -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.instrumenter.SpanNameExtractor; -import io.opentelemetry.instrumentation.api.semconv.network.ServerAttributesExtractor; -import io.opentelemetry.instrumentation.api.util.VirtualField; -import io.opentelemetry.javaagent.bootstrap.internal.AgentCommonConfig; -import io.vertx.core.Future; -import io.vertx.core.Promise; -import io.vertx.sqlclient.SqlConnectOptions; -import io.vertx.sqlclient.SqlConnection; -import io.vertx.sqlclient.impl.SqlClientBase; -import java.util.concurrent.CompletableFuture; - -public final class VertxSqlClientSingletons { - private static final String INSTRUMENTATION_NAME = "io.opentelemetry.vertx-sql-client-4.0"; - private static final Instrumenter INSTRUMENTER; - private static final ThreadLocal connectOptions = new ThreadLocal<>(); - - static { - SpanNameExtractor spanNameExtractor = - DbClientSpanNameExtractor.create(VertxSqlClientAttributesGetter.INSTANCE); - - InstrumenterBuilder builder = - Instrumenter.builder( - GlobalOpenTelemetry.get(), INSTRUMENTATION_NAME, spanNameExtractor) - .addAttributesExtractor( - SqlClientAttributesExtractor.builder(VertxSqlClientAttributesGetter.INSTANCE) - .setStatementSanitizationEnabled( - AgentCommonConfig.get().isStatementSanitizationEnabled()) - .build()) - .addAttributesExtractor( - ServerAttributesExtractor.create(VertxSqlClientNetAttributesGetter.INSTANCE)) - .addAttributesExtractor( - PeerServiceAttributesExtractor.create( - VertxSqlClientNetAttributesGetter.INSTANCE, - AgentCommonConfig.get().getPeerServiceResolver())) - .addOperationMetrics(DbClientMetrics.get()); - - INSTRUMENTER = builder.buildInstrumenter(SpanKindExtractor.alwaysClient()); - } - - public static Instrumenter instrumenter() { - return INSTRUMENTER; - } - - public static void setSqlConnectOptions(SqlConnectOptions sqlConnectOptions) { - connectOptions.set(sqlConnectOptions); - } - - public static SqlConnectOptions getSqlConnectOptions() { - return connectOptions.get(); - } - - private static final VirtualField, RequestData> requestDataField = - VirtualField.find(Promise.class, RequestData.class); - - public static void attachRequest( - Promise promise, VertxSqlClientRequest request, Context context, Context parentContext) { - requestDataField.set(promise, new RequestData(request, context, parentContext)); - } - - public static Scope endQuerySpan(Promise promise, Throwable throwable) { - RequestData requestData = requestDataField.get(promise); - if (requestData == null) { - return null; - } - instrumenter().end(requestData.context, requestData.request, null, throwable); - return requestData.parentContext.makeCurrent(); - } - - static class RequestData { - final VertxSqlClientRequest request; - final Context context; - final Context parentContext; - - RequestData(VertxSqlClientRequest request, Context context, Context parentContext) { - this.request = request; - this.context = context; - this.parentContext = parentContext; - } - } - - // this virtual field is also used in SqlClientBase instrumentation - private static final VirtualField, SqlConnectOptions> connectOptionsField = - VirtualField.find(SqlClientBase.class, SqlConnectOptions.class); - - public static Future attachConnectOptions( - Future future, SqlConnectOptions connectOptions) { - return future.map( - sqlConnection -> { - if (sqlConnection instanceof SqlClientBase) { - connectOptionsField.set((SqlClientBase) sqlConnection, connectOptions); - } - return sqlConnection; - }); - } - - public static Future wrapContext(Future future) { - Context context = Context.current(); - CompletableFuture result = new CompletableFuture<>(); - future - .toCompletionStage() - .whenComplete( - (value, throwable) -> { - try (Scope ignore = context.makeCurrent()) { - if (throwable != null) { - result.completeExceptionally(throwable); - } else { - result.complete(value); - } - } - }); - return Future.fromCompletionStage(result); - } - - private VertxSqlClientSingletons() {} -} diff --git a/instrumentation/vertx/vertx-sql-client-4.0/javaagent/build.gradle.kts b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/build.gradle.kts similarity index 63% rename from instrumentation/vertx/vertx-sql-client-4.0/javaagent/build.gradle.kts rename to instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/build.gradle.kts index 569e1b214fa8..88a1a3773624 100644 --- a/instrumentation/vertx/vertx-sql-client-4.0/javaagent/build.gradle.kts +++ b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/build.gradle.kts @@ -14,16 +14,18 @@ muzzle { dependencies { val version = "4.0.0" library("io.vertx:vertx-sql-client:$version") - compileOnly("io.vertx:vertx-codegen:$version") + library("io.vertx:vertx-codegen:$version") + + implementation(project(":instrumentation:vertx:vertx-sql-client:vertx-sql-client-common:javaagent")) testInstrumentation(project(":instrumentation:netty:netty-4.1:javaagent")) + testInstrumentation(project(":instrumentation:vertx:vertx-sql-client:vertx-sql-client-5.0:javaagent")) testLibrary("io.vertx:vertx-pg-client:$version") - testLibrary("io.vertx:vertx-codegen:$version") - latestDepTestLibrary("io.vertx:vertx-sql-client:4.+") // documented limitation, 5.x not supported yet - latestDepTestLibrary("io.vertx:vertx-pg-client:4.+") // documented limitation, 5.x not supported yet - latestDepTestLibrary("io.vertx:vertx-codegen:4.+") // documented limitation, 5.x not supported yet + latestDepTestLibrary("io.vertx:vertx-sql-client:4.+") // see vertx-sql-client-5.0 module + latestDepTestLibrary("io.vertx:vertx-pg-client:4.+") // see vertx-sql-client-5.0 module + latestDepTestLibrary("io.vertx:vertx-codegen:4.+") // see vertx-sql-client-5.0 module } tasks { diff --git a/instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/HandlerWrapper.java b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/HandlerWrapper.java similarity index 100% rename from instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/HandlerWrapper.java rename to instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/HandlerWrapper.java diff --git a/instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/PoolInstrumentation.java b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/PoolInstrumentation.java similarity index 83% rename from instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/PoolInstrumentation.java rename to instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/PoolInstrumentation.java index 5513b743215d..1a1f62f52a29 100644 --- a/instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/PoolInstrumentation.java +++ b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/PoolInstrumentation.java @@ -7,7 +7,11 @@ import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; -import static io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql.VertxSqlClientSingletons.setSqlConnectOptions; +import static io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientUtil.getPoolSqlConnectOptions; +import static io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientUtil.setPoolConnectOptions; +import static io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientUtil.setSqlConnectOptions; +import static io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientUtil.wrapContext; +import static io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql.VertxSqlClientSingletons.attachConnectOptions; import static net.bytebuddy.matcher.ElementMatchers.isStatic; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.returns; @@ -15,7 +19,6 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import static net.bytebuddy.matcher.ElementMatchers.takesNoArguments; -import io.opentelemetry.instrumentation.api.util.VirtualField; import io.opentelemetry.javaagent.bootstrap.CallDepth; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; @@ -78,10 +81,7 @@ public static void onExit( return; } - VirtualField virtualField = - VirtualField.find(Pool.class, SqlConnectOptions.class); - virtualField.set(pool, sqlConnectOptions); - + setPoolConnectOptions(pool, sqlConnectOptions); setSqlConnectOptions(null); } } @@ -92,12 +92,10 @@ public static class GetConnectionAdvice { public static void onExit( @Advice.This Pool pool, @Advice.Return(readOnly = false) Future future) { // copy connect options stored on pool to new connection - VirtualField virtualField = - VirtualField.find(Pool.class, SqlConnectOptions.class); - SqlConnectOptions sqlConnectOptions = virtualField.get(pool); + SqlConnectOptions sqlConnectOptions = getPoolSqlConnectOptions(pool); - future = VertxSqlClientSingletons.attachConnectOptions(future, sqlConnectOptions); - future = VertxSqlClientSingletons.wrapContext(future); + future = attachConnectOptions(future, sqlConnectOptions); + future = wrapContext(future); } } } diff --git a/instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/QueryExecutorInstrumentation.java b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/QueryExecutorInstrumentation.java similarity index 92% rename from instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/QueryExecutorInstrumentation.java rename to instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/QueryExecutorInstrumentation.java index 0264f925cac3..c724abbe1192 100644 --- a/instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/QueryExecutorInstrumentation.java +++ b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/QueryExecutorInstrumentation.java @@ -6,7 +6,7 @@ package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql; import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext; -import static io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql.VertxSqlClientSingletons.getSqlConnectOptions; +import static io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientUtil.getSqlConnectOptions; import static io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql.VertxSqlClientSingletons.instrumenter; import static net.bytebuddy.matcher.ElementMatchers.isConstructor; import static net.bytebuddy.matcher.ElementMatchers.named; @@ -17,6 +17,8 @@ import io.opentelemetry.javaagent.bootstrap.CallDepth; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientRequest; +import io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientUtil; import io.vertx.core.impl.future.PromiseInternal; import io.vertx.sqlclient.impl.PreparedStatement; import io.vertx.sqlclient.impl.QueryExecutorUtil; @@ -95,7 +97,7 @@ public static void onEnter( context = instrumenter().start(parentContext, otelRequest); scope = context.makeCurrent(); - VertxSqlClientSingletons.attachRequest(promiseInternal, otelRequest, context, parentContext); + VertxSqlClientUtil.attachRequest(promiseInternal, otelRequest, context, parentContext); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) diff --git a/instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/QueryResultBuilderInstrumentation.java b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/QueryResultBuilderInstrumentation.java similarity index 89% rename from instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/QueryResultBuilderInstrumentation.java rename to instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/QueryResultBuilderInstrumentation.java index a364cf873d2f..d4705a86a739 100644 --- a/instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/QueryResultBuilderInstrumentation.java +++ b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/QueryResultBuilderInstrumentation.java @@ -5,7 +5,8 @@ package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql; -import static io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql.VertxSqlClientSingletons.endQuerySpan; +import static io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientUtil.endQuerySpan; +import static io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql.VertxSqlClientSingletons.instrumenter; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; @@ -38,7 +39,7 @@ public void transform(TypeTransformer transformer) { public static class CompleteAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) public static Scope onEnter(@Advice.FieldValue("handler") Promise promise) { - return endQuerySpan(promise, null); + return endQuerySpan(instrumenter(), promise, null); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) @@ -54,7 +55,7 @@ public static class FailAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) public static Scope onEnter( @Advice.Argument(0) Throwable throwable, @Advice.FieldValue("handler") Promise promise) { - return endQuerySpan(promise, throwable); + return endQuerySpan(instrumenter(), promise, throwable); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) diff --git a/instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/SqlClientBaseInstrumentation.java b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/SqlClientBaseInstrumentation.java similarity index 80% rename from instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/SqlClientBaseInstrumentation.java rename to instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/SqlClientBaseInstrumentation.java index 07cfb16bb56a..af80451e7800 100644 --- a/instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/SqlClientBaseInstrumentation.java +++ b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/SqlClientBaseInstrumentation.java @@ -5,13 +5,14 @@ package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql; +import static io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientUtil.getSqlConnectOptions; +import static io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientUtil.setSqlConnectOptions; +import static io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql.VertxSqlClientSingletons.attachConnectOptions; import static io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql.VertxSqlClientSingletons.getSqlConnectOptions; -import static io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql.VertxSqlClientSingletons.setSqlConnectOptions; import static net.bytebuddy.matcher.ElementMatchers.isConstructor; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; -import io.opentelemetry.instrumentation.api.util.VirtualField; import io.opentelemetry.javaagent.bootstrap.CallDepth; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; @@ -42,10 +43,7 @@ public static class ConstructorAdvice { @Advice.OnMethodExit(suppress = Throwable.class) public static void onExit(@Advice.This SqlClientBase sqlClientBase) { // copy connection options from ThreadLocal to VirtualField - // this virtual field is also set in VertxSqlClientSingletons.attachConnectOptions - VirtualField, SqlConnectOptions> virtualField = - VirtualField.find(SqlClientBase.class, SqlConnectOptions.class); - virtualField.set(sqlClientBase, getSqlConnectOptions()); + attachConnectOptions(sqlClientBase, getSqlConnectOptions()); } } @@ -61,9 +59,7 @@ public static void onEnter( } // set connection options to ThreadLocal, they will be read in QueryExecutor constructor - VirtualField, SqlConnectOptions> virtualField = - VirtualField.find(SqlClientBase.class, SqlConnectOptions.class); - SqlConnectOptions sqlConnectOptions = virtualField.get(sqlClientBase); + SqlConnectOptions sqlConnectOptions = getSqlConnectOptions(sqlClientBase); setSqlConnectOptions(sqlConnectOptions); } diff --git a/instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/TransactionImplInstrumentation.java b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/TransactionImplInstrumentation.java similarity index 100% rename from instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/TransactionImplInstrumentation.java rename to instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/TransactionImplInstrumentation.java diff --git a/instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientInstrumentationModule.java b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientInstrumentationModule.java similarity index 82% rename from instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientInstrumentationModule.java rename to instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientInstrumentationModule.java index 448cff225ac4..00523bba06cc 100644 --- a/instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientInstrumentationModule.java +++ b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientInstrumentationModule.java @@ -5,6 +5,7 @@ package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql; +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; @@ -13,6 +14,7 @@ import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule; import java.util.List; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(InstrumentationModule.class) public class VertxSqlClientInstrumentationModule extends InstrumentationModule @@ -22,6 +24,12 @@ public VertxSqlClientInstrumentationModule() { super("vertx-sql-client", "vertx-sql-client-4.0", "vertx"); } + @Override + public ElementMatcher.Junction classLoaderMatcher() { + // removed in 5.0 + return hasClassesNamed("io.vertx.sqlclient.impl.SqlClientBase"); + } + @Override public boolean isHelperClass(String className) { return "io.vertx.sqlclient.impl.QueryExecutorUtil".equals(className); diff --git a/instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientSingletons.java b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientSingletons.java new file mode 100644 index 000000000000..49016a4e6676 --- /dev/null +++ b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientSingletons.java @@ -0,0 +1,50 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql; + +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.api.util.VirtualField; +import io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientRequest; +import io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlInstrumenterFactory; +import io.vertx.core.Future; +import io.vertx.sqlclient.SqlConnectOptions; +import io.vertx.sqlclient.SqlConnection; +import io.vertx.sqlclient.impl.SqlClientBase; + +public final class VertxSqlClientSingletons { + private static final String INSTRUMENTATION_NAME = "io.opentelemetry.vertx-sql-client-4.0"; + private static final Instrumenter INSTRUMENTER = + VertxSqlInstrumenterFactory.createInstrumenter(INSTRUMENTATION_NAME); + + public static Instrumenter instrumenter() { + return INSTRUMENTER; + } + + private static final VirtualField, SqlConnectOptions> connectOptionsField = + VirtualField.find(SqlClientBase.class, SqlConnectOptions.class); + + public static SqlConnectOptions getSqlConnectOptions(SqlClientBase sqlClientBase) { + return connectOptionsField.get(sqlClientBase); + } + + public static void attachConnectOptions( + SqlClientBase sqlClientBase, SqlConnectOptions connectOptions) { + connectOptionsField.set(sqlClientBase, connectOptions); + } + + public static Future attachConnectOptions( + Future future, SqlConnectOptions connectOptions) { + return future.map( + sqlConnection -> { + if (sqlConnection instanceof SqlClientBase) { + connectOptionsField.set((SqlClientBase) sqlConnection, connectOptions); + } + return sqlConnection; + }); + } + + private VertxSqlClientSingletons() {} +} diff --git a/instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientTest.java b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientTest.java similarity index 100% rename from instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientTest.java rename to instrumentation/vertx/vertx-sql-client/vertx-sql-client-4.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientTest.java diff --git a/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/build.gradle.kts b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/build.gradle.kts new file mode 100644 index 000000000000..012878cf49da --- /dev/null +++ b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/build.gradle.kts @@ -0,0 +1,39 @@ +plugins { + id("otel.javaagent-instrumentation") +} + +muzzle { + pass { + group.set("io.vertx") + module.set("vertx-sql-client") + versions.set("[5.0.0,)") + assertInverse.set(true) + } +} + +dependencies { + val version = "5.0.0" + library("io.vertx:vertx-sql-client:$version") + library("io.vertx:vertx-codegen:$version") + + implementation(project(":instrumentation:vertx:vertx-sql-client:vertx-sql-client-common:javaagent")) + + testInstrumentation(project(":instrumentation:netty:netty-4.1:javaagent")) + testInstrumentation(project(":instrumentation:vertx:vertx-sql-client:vertx-sql-client-4.0:javaagent")) + + testLibrary("io.vertx:vertx-pg-client:$version") +} + +tasks { + withType().configureEach { + usesService(gradle.sharedServices.registrations["testcontainersBuildService"].service) + } + + val testStableSemconv by registering(Test::class) { + jvmArgs("-Dotel.semconv-stability.opt-in=database") + } + + check { + dependsOn(testStableSemconv) + } +} diff --git a/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/CompletableWrapper.java b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/CompletableWrapper.java new file mode 100644 index 000000000000..46843e9e8bc5 --- /dev/null +++ b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/CompletableWrapper.java @@ -0,0 +1,35 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.vertx.v5_0.sql; + +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.vertx.core.Completable; + +public class CompletableWrapper implements Completable { + private final Completable delegate; + private final Context context; + + private CompletableWrapper(Completable delegate, Context context) { + this.delegate = delegate; + this.context = context; + } + + public static Completable wrap(Completable handler) { + Context current = Context.current(); + if (handler != null && !(handler instanceof CompletableWrapper) && current != Context.root()) { + handler = new CompletableWrapper<>(handler, current); + } + return handler; + } + + @Override + public void complete(T t, Throwable error) { + try (Scope ignore = context.makeCurrent()) { + delegate.complete(t, error); + } + } +} diff --git a/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/PoolInstrumentation.java b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/PoolInstrumentation.java new file mode 100644 index 000000000000..4ff4b22b259d --- /dev/null +++ b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/PoolInstrumentation.java @@ -0,0 +1,106 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.vertx.v5_0.sql; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; +import static io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientUtil.getPoolSqlConnectOptions; +import static io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientUtil.setPoolConnectOptions; +import static io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientUtil.setSqlConnectOptions; +import static io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientUtil.wrapContext; +import static io.opentelemetry.javaagent.instrumentation.vertx.v5_0.sql.VertxSqlClientSingletons.attachConnectOptions; +import static net.bytebuddy.matcher.ElementMatchers.isStatic; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.returns; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; +import static net.bytebuddy.matcher.ElementMatchers.takesNoArguments; + +import io.opentelemetry.instrumentation.api.util.VirtualField; +import io.opentelemetry.javaagent.bootstrap.CallDepth; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.vertx.core.Future; +import io.vertx.sqlclient.Pool; +import io.vertx.sqlclient.SqlConnectOptions; +import io.vertx.sqlclient.SqlConnection; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public class PoolInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher classLoaderOptimization() { + return hasClassesNamed("io.vertx.sqlclient.Pool"); + } + + @Override + public ElementMatcher typeMatcher() { + return implementsInterface(named("io.vertx.sqlclient.Pool")); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("pool") + .and(isStatic()) + .and(takesArguments(3)) + .and(takesArgument(1, named("io.vertx.sqlclient.SqlConnectOptions"))) + .and(returns(named("io.vertx.sqlclient.Pool"))), + PoolInstrumentation.class.getName() + "$PoolAdvice"); + + transformer.applyAdviceToMethod( + named("getConnection").and(takesNoArguments()).and(returns(named("io.vertx.core.Future"))), + PoolInstrumentation.class.getName() + "$GetConnectionAdvice"); + } + + @SuppressWarnings("unused") + public static class PoolAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Argument(1) SqlConnectOptions sqlConnectOptions, + @Advice.Local("otelCallDepth") CallDepth callDepth) { + callDepth = CallDepth.forClass(Pool.class); + if (callDepth.getAndIncrement() > 0) { + return; + } + + // set connection options to ThreadLocal, they will be read in SqlClientBase constructor + setSqlConnectOptions(sqlConnectOptions); + } + + @Advice.OnMethodExit(suppress = Throwable.class) + public static void onExit( + @Advice.Return Pool pool, + @Advice.Argument(1) SqlConnectOptions sqlConnectOptions, + @Advice.Local("otelCallDepth") CallDepth callDepth) { + if (callDepth.decrementAndGet() > 0) { + return; + } + + VirtualField virtualField = + VirtualField.find(Pool.class, SqlConnectOptions.class); + virtualField.set(pool, sqlConnectOptions); + + setPoolConnectOptions(pool, sqlConnectOptions); + setSqlConnectOptions(null); + } + } + + @SuppressWarnings("unused") + public static class GetConnectionAdvice { + @Advice.OnMethodExit(suppress = Throwable.class) + public static void onExit( + @Advice.This Pool pool, @Advice.Return(readOnly = false) Future future) { + // copy connect options stored on pool to new connection + SqlConnectOptions sqlConnectOptions = getPoolSqlConnectOptions(pool); + + future = attachConnectOptions(future, sqlConnectOptions); + future = wrapContext(future); + } + } +} diff --git a/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/QueryExecutorInstrumentation.java b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/QueryExecutorInstrumentation.java new file mode 100644 index 000000000000..0e78cb8e099f --- /dev/null +++ b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/QueryExecutorInstrumentation.java @@ -0,0 +1,124 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.vertx.v5_0.sql; + +import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext; +import static io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientUtil.getSqlConnectOptions; +import static io.opentelemetry.javaagent.instrumentation.vertx.v5_0.sql.VertxSqlClientSingletons.instrumenter; +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; + +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.javaagent.bootstrap.CallDepth; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientRequest; +import io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientUtil; +import io.vertx.core.internal.PromiseInternal; +import io.vertx.sqlclient.impl.QueryExecutorUtil; +import io.vertx.sqlclient.internal.PreparedStatement; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public class QueryExecutorInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("io.vertx.sqlclient.impl.QueryExecutor"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isConstructor(), QueryExecutorInstrumentation.class.getName() + "$ConstructorAdvice"); + transformer.applyAdviceToMethod( + namedOneOf("executeSimpleQuery", "executeExtendedQuery", "executeBatchQuery"), + QueryExecutorInstrumentation.class.getName() + "$QueryAdvice"); + } + + @SuppressWarnings("unused") + public static class ConstructorAdvice { + + @Advice.OnMethodExit(suppress = Throwable.class) + public static void onExit(@Advice.This Object queryExecutor) { + // copy connection options from ThreadLocal to VirtualField + QueryExecutorUtil.setConnectOptions(queryExecutor, getSqlConnectOptions()); + } + } + + @SuppressWarnings("unused") + public static class QueryAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.This Object queryExecutor, + @Advice.AllArguments Object[] arguments, + @Advice.Local("otelCallDepth") CallDepth callDepth, + @Advice.Local("otelRequest") VertxSqlClientRequest otelRequest, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + callDepth = CallDepth.forClass(queryExecutor.getClass()); + if (callDepth.getAndIncrement() > 0) { + return; + } + + // The parameter we need are in different positions, we are not going to have separate + // advices for all of them. The method gets the statement either as String or + // PreparedStatement, use the first argument that is either of these. PromiseInternal is + // always at the end of the argument list. + String sql = null; + PromiseInternal promiseInternal = null; + for (Object argument : arguments) { + if (sql == null) { + if (argument instanceof String) { + sql = (String) argument; + } else if (argument instanceof PreparedStatement) { + sql = ((PreparedStatement) argument).sql(); + } + } else if (argument instanceof PromiseInternal) { + promiseInternal = (PromiseInternal) argument; + } + } + if (sql == null || promiseInternal == null) { + return; + } + + otelRequest = + new VertxSqlClientRequest(sql, QueryExecutorUtil.getConnectOptions(queryExecutor)); + Context parentContext = currentContext(); + if (!instrumenter().shouldStart(parentContext, otelRequest)) { + return; + } + + context = instrumenter().start(parentContext, otelRequest); + scope = context.makeCurrent(); + VertxSqlClientUtil.attachRequest(promiseInternal, otelRequest, context, parentContext); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void onExit( + @Advice.Thrown Throwable throwable, + @Advice.Local("otelCallDepth") CallDepth callDepth, + @Advice.Local("otelRequest") VertxSqlClientRequest otelRequest, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + if (callDepth.decrementAndGet() > 0) { + return; + } + if (scope == null) { + return; + } + + scope.close(); + if (throwable != null) { + instrumenter().end(context, otelRequest, null, throwable); + } + // span will be ended in QueryResultBuilderInstrumentation + } + } +} diff --git a/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/QueryResultBuilderInstrumentation.java b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/QueryResultBuilderInstrumentation.java new file mode 100644 index 000000000000..18b8bf722a76 --- /dev/null +++ b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/QueryResultBuilderInstrumentation.java @@ -0,0 +1,48 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.vertx.v5_0.sql; + +import static io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientUtil.endQuerySpan; +import static io.opentelemetry.javaagent.instrumentation.vertx.v5_0.sql.VertxSqlClientSingletons.instrumenter; +import static net.bytebuddy.matcher.ElementMatchers.named; + +import io.opentelemetry.context.Scope; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.vertx.core.Promise; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public class QueryResultBuilderInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("io.vertx.sqlclient.impl.QueryResultBuilder"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("complete"), QueryResultBuilderInstrumentation.class.getName() + "$CompleteAdvice"); + } + + @SuppressWarnings("unused") + public static class CompleteAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static Scope onEnter( + @Advice.Argument(1) Throwable throwable, @Advice.FieldValue("handler") Promise promise) { + return endQuerySpan(instrumenter(), promise, throwable); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void onExit(@Advice.Enter Scope scope) { + if (scope != null) { + scope.close(); + } + } + } +} diff --git a/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/SqlClientBaseInstrumentation.java b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/SqlClientBaseInstrumentation.java new file mode 100644 index 000000000000..894d1ba10e67 --- /dev/null +++ b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/SqlClientBaseInstrumentation.java @@ -0,0 +1,76 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.vertx.v5_0.sql; + +import static io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientUtil.getSqlConnectOptions; +import static io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientUtil.setSqlConnectOptions; +import static io.opentelemetry.javaagent.instrumentation.vertx.v5_0.sql.VertxSqlClientSingletons.attachConnectOptions; +import static io.opentelemetry.javaagent.instrumentation.vertx.v5_0.sql.VertxSqlClientSingletons.getSqlConnectOptions; +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; + +import io.opentelemetry.javaagent.bootstrap.CallDepth; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.vertx.sqlclient.SqlConnectOptions; +import io.vertx.sqlclient.internal.SqlClientBase; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public class SqlClientBaseInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("io.vertx.sqlclient.internal.SqlClientBase"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isConstructor(), SqlClientBaseInstrumentation.class.getName() + "$ConstructorAdvice"); + transformer.applyAdviceToMethod( + namedOneOf("query", "preparedQuery"), + SqlClientBaseInstrumentation.class.getName() + "$QueryAdvice"); + } + + @SuppressWarnings("unused") + public static class ConstructorAdvice { + @Advice.OnMethodExit(suppress = Throwable.class) + public static void onExit(@Advice.This SqlClientBase sqlClientBase) { + // copy connection options from ThreadLocal to VirtualField + attachConnectOptions(sqlClientBase, getSqlConnectOptions()); + } + } + + @SuppressWarnings("unused") + public static class QueryAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.This SqlClientBase sqlClientBase, + @Advice.Local("otelCallDepth") CallDepth callDepth) { + callDepth = CallDepth.forClass(SqlClientBase.class); + if (callDepth.getAndIncrement() > 0) { + return; + } + + // set connection options to ThreadLocal, they will be read in QueryExecutor constructor + SqlConnectOptions sqlConnectOptions = getSqlConnectOptions(sqlClientBase); + setSqlConnectOptions(sqlConnectOptions); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void onExit( + @Advice.Thrown Throwable throwable, @Advice.Local("otelCallDepth") CallDepth callDepth) { + if (callDepth.decrementAndGet() > 0) { + return; + } + + setSqlConnectOptions(null); + } + } +} diff --git a/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/TransactionImplInstrumentation.java b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/TransactionImplInstrumentation.java new file mode 100644 index 000000000000..627e58f4420f --- /dev/null +++ b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/TransactionImplInstrumentation.java @@ -0,0 +1,39 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.vertx.v5_0.sql; + +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.returns; + +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.vertx.core.Completable; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public class TransactionImplInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("io.vertx.sqlclient.impl.TransactionImpl"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("wrap").and(returns(named("io.vertx.core.Completable"))), + TransactionImplInstrumentation.class.getName() + "$WrapHandlerAdvice"); + } + + @SuppressWarnings("unused") + public static class WrapHandlerAdvice { + @Advice.OnMethodExit(suppress = Throwable.class) + public static void wrapHandler(@Advice.Return(readOnly = false) Completable handler) { + handler = CompletableWrapper.wrap(handler); + } + } +} diff --git a/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/VertxSqlClientInstrumentationModule.java b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/VertxSqlClientInstrumentationModule.java new file mode 100644 index 000000000000..5f02f9522e6d --- /dev/null +++ b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/VertxSqlClientInstrumentationModule.java @@ -0,0 +1,52 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.vertx.v5_0.sql; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; + +import com.google.auto.service.AutoService; +import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule; +import java.util.List; +import net.bytebuddy.matcher.ElementMatcher; + +@AutoService(InstrumentationModule.class) +public class VertxSqlClientInstrumentationModule extends InstrumentationModule + implements ExperimentalInstrumentationModule { + + public VertxSqlClientInstrumentationModule() { + super("vertx-sql-client", "vertx-sql-client-5.0", "vertx"); + } + + @Override + public ElementMatcher.Junction classLoaderMatcher() { + // added in 5.0 + return hasClassesNamed("io.vertx.sqlclient.internal.SqlClientBase"); + } + + @Override + public boolean isHelperClass(String className) { + return "io.vertx.sqlclient.impl.QueryExecutorUtil".equals(className); + } + + @Override + public List injectedClassNames() { + return singletonList("io.vertx.sqlclient.impl.QueryExecutorUtil"); + } + + @Override + public List typeInstrumentations() { + return asList( + new PoolInstrumentation(), + new SqlClientBaseInstrumentation(), + new QueryExecutorInstrumentation(), + new QueryResultBuilderInstrumentation(), + new TransactionImplInstrumentation()); + } +} diff --git a/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/VertxSqlClientSingletons.java b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/VertxSqlClientSingletons.java new file mode 100644 index 000000000000..ba3ffec19dfe --- /dev/null +++ b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/VertxSqlClientSingletons.java @@ -0,0 +1,50 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.vertx.v5_0.sql; + +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.api.util.VirtualField; +import io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlClientRequest; +import io.opentelemetry.javaagent.instrumentation.vertx.sql.VertxSqlInstrumenterFactory; +import io.vertx.core.Future; +import io.vertx.sqlclient.SqlConnectOptions; +import io.vertx.sqlclient.SqlConnection; +import io.vertx.sqlclient.internal.SqlClientBase; + +public final class VertxSqlClientSingletons { + private static final String INSTRUMENTATION_NAME = "io.opentelemetry.vertx-sql-client-5.0"; + private static final Instrumenter INSTRUMENTER = + VertxSqlInstrumenterFactory.createInstrumenter(INSTRUMENTATION_NAME); + + public static Instrumenter instrumenter() { + return INSTRUMENTER; + } + + private static final VirtualField connectOptionsField = + VirtualField.find(SqlClientBase.class, SqlConnectOptions.class); + + public static SqlConnectOptions getSqlConnectOptions(SqlClientBase sqlClientBase) { + return connectOptionsField.get(sqlClientBase); + } + + public static void attachConnectOptions( + SqlClientBase sqlClientBase, SqlConnectOptions connectOptions) { + connectOptionsField.set(sqlClientBase, connectOptions); + } + + public static Future attachConnectOptions( + Future future, SqlConnectOptions connectOptions) { + return future.map( + sqlConnection -> { + if (sqlConnection instanceof SqlClientBase) { + connectOptionsField.set((SqlClientBase) sqlConnection, connectOptions); + } + return sqlConnection; + }); + } + + private VertxSqlClientSingletons() {} +} diff --git a/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/VertxSqlClientTest.java b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/VertxSqlClientTest.java new file mode 100644 index 000000000000..afaf9e7d6319 --- /dev/null +++ b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/vertx/v5_0/sql/VertxSqlClientTest.java @@ -0,0 +1,445 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.vertx.v5_0.sql; + +import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitStableDatabaseSemconv; +import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStable; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; +import static io.opentelemetry.semconv.ErrorAttributes.ERROR_TYPE; +import static io.opentelemetry.semconv.ExceptionAttributes.EXCEPTION_MESSAGE; +import static io.opentelemetry.semconv.ExceptionAttributes.EXCEPTION_STACKTRACE; +import static io.opentelemetry.semconv.ExceptionAttributes.EXCEPTION_TYPE; +import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS; +import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT; +import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_NAME; +import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_OPERATION; +import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_RESPONSE_STATUS_CODE; +import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SQL_TABLE; +import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_STATEMENT; +import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_USER; + +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.instrumentation.api.internal.SemconvStability; +import io.opentelemetry.instrumentation.testing.internal.AutoCleanupExtension; +import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.sdk.testing.assertj.AttributeAssertion; +import io.opentelemetry.sdk.testing.assertj.TraceAssert; +import io.opentelemetry.sdk.trace.data.StatusData; +import io.vertx.core.Vertx; +import io.vertx.pgclient.PgConnectOptions; +import io.vertx.pgclient.PgException; +import io.vertx.sqlclient.Pool; +import io.vertx.sqlclient.PoolOptions; +import io.vertx.sqlclient.Tuple; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.output.Slf4jLogConsumer; + +@SuppressWarnings("deprecation") // using deprecated semconv +class VertxSqlClientTest { + private static final Logger logger = LoggerFactory.getLogger(VertxSqlClientTest.class); + + private static final String USER_DB = "SA"; + private static final String PW_DB = "password123"; + private static final String DB = "tempdb"; + + @RegisterExtension + private static final InstrumentationExtension testing = AgentInstrumentationExtension.create(); + + @RegisterExtension + private static final AutoCleanupExtension cleanup = AutoCleanupExtension.create(); + + private static GenericContainer container; + private static Vertx vertx; + private static Pool pool; + private static String host; + private static int port; + + @BeforeAll + static void setUp() throws Exception { + container = + new GenericContainer<>("postgres:9.6.8") + .withEnv("POSTGRES_USER", USER_DB) + .withEnv("POSTGRES_PASSWORD", PW_DB) + .withEnv("POSTGRES_DB", DB) + .withExposedPorts(5432) + .withLogConsumer(new Slf4jLogConsumer(logger)) + .withStartupTimeout(Duration.ofMinutes(2)); + container.start(); + vertx = Vertx.vertx(); + host = container.getHost(); + port = container.getMappedPort(5432); + PgConnectOptions options = + new PgConnectOptions() + .setPort(port) + .setHost(host) + .setDatabase(DB) + .setUser(USER_DB) + .setPassword(PW_DB); + pool = Pool.pool(vertx, options, new PoolOptions().setMaxSize(4)); + pool.query("create table test(id int primary key, name varchar(255))") + .execute() + .compose( + r -> + // insert some test data + pool.query("insert into test values (1, 'Hello'), (2, 'World')").execute()) + .toCompletionStage() + .toCompletableFuture() + .get(30, TimeUnit.SECONDS); + } + + @AfterAll + static void cleanUp() { + pool.close(); + vertx.close(); + container.stop(); + } + + @Test + void testSimpleSelect() throws Exception { + CompletableFuture future = new CompletableFuture<>(); + CompletableFuture result = + future.whenComplete((rows, throwable) -> testing.runWithSpan("callback", () -> {})); + testing.runWithSpan( + "parent", + () -> + pool.query("select * from test") + .execute() + .onComplete( + rowSetAsyncResult -> { + if (rowSetAsyncResult.succeeded()) { + future.complete(rowSetAsyncResult.result()); + } else { + future.completeExceptionally(rowSetAsyncResult.cause()); + } + })); + result.get(30, TimeUnit.SECONDS); + + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> span.hasName("parent").hasKind(SpanKind.INTERNAL), + span -> + span.hasName("SELECT tempdb.test") + .hasKind(SpanKind.CLIENT) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + equalTo(maybeStable(DB_NAME), DB), + equalTo(DB_USER, emitStableDatabaseSemconv() ? null : USER_DB), + equalTo(maybeStable(DB_STATEMENT), "select * from test"), + equalTo(maybeStable(DB_OPERATION), "SELECT"), + equalTo(maybeStable(DB_SQL_TABLE), "test"), + equalTo(SERVER_ADDRESS, host), + equalTo(SERVER_PORT, port)), + span -> + span.hasName("callback") + .hasKind(SpanKind.INTERNAL) + .hasParent(trace.getSpan(0)))); + } + + @Test + void testInvalidQuery() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + CompletableFuture result = new CompletableFuture<>(); + result.whenComplete((rows, throwable) -> testing.runWithSpan("callback", latch::countDown)); + testing.runWithSpan( + "parent", + () -> + pool.query("invalid") + .execute() + .onComplete( + rowSetAsyncResult -> { + if (rowSetAsyncResult.succeeded()) { + result.complete(rowSetAsyncResult.result()); + } else { + result.completeExceptionally(rowSetAsyncResult.cause()); + } + })); + + latch.await(30, TimeUnit.SECONDS); + + List assertions = + new ArrayList<>( + Arrays.asList( + equalTo(maybeStable(DB_NAME), DB), + equalTo(DB_USER, emitStableDatabaseSemconv() ? null : USER_DB), + equalTo(maybeStable(DB_STATEMENT), "invalid"), + equalTo(SERVER_ADDRESS, host), + equalTo(SERVER_PORT, port))); + + if (SemconvStability.emitStableDatabaseSemconv()) { + assertions.add(equalTo(DB_RESPONSE_STATUS_CODE, "42601")); + assertions.add(equalTo(ERROR_TYPE, "io.vertx.pgclient.PgException")); + } + + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> span.hasName("parent").hasKind(SpanKind.INTERNAL), + span -> + span.hasName("tempdb") + .hasKind(SpanKind.CLIENT) + .hasParent(trace.getSpan(0)) + .hasStatus(StatusData.error()) + .hasEventsSatisfyingExactly( + event -> + event + .hasName("exception") + .hasAttributesSatisfyingExactly( + equalTo(EXCEPTION_TYPE, PgException.class.getName()), + satisfies( + EXCEPTION_MESSAGE, + val -> val.contains("syntax error at or near")), + satisfies( + EXCEPTION_STACKTRACE, + val -> val.isInstanceOf(String.class)))) + .hasAttributesSatisfyingExactly(assertions), + span -> + span.hasName("callback") + .hasKind(SpanKind.INTERNAL) + .hasParent(trace.getSpan(0)))); + } + + @Test + void testPreparedSelect() throws Exception { + testing + .runWithSpan( + "parent", + () -> pool.preparedQuery("select * from test where id = $1").execute(Tuple.of(1))) + .toCompletionStage() + .toCompletableFuture() + .get(30, TimeUnit.SECONDS); + + assertPreparedSelect(); + } + + private static void assertPreparedSelect() { + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> span.hasName("parent").hasKind(SpanKind.INTERNAL), + span -> + span.hasName("SELECT tempdb.test") + .hasKind(SpanKind.CLIENT) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + equalTo(maybeStable(DB_NAME), DB), + equalTo(DB_USER, emitStableDatabaseSemconv() ? null : USER_DB), + equalTo(maybeStable(DB_STATEMENT), "select * from test where id = $1"), + equalTo(maybeStable(DB_OPERATION), "SELECT"), + equalTo(maybeStable(DB_SQL_TABLE), "test"), + equalTo(SERVER_ADDRESS, host), + equalTo(SERVER_PORT, port)))); + } + + @Test + void testBatch() throws Exception { + testing + .runWithSpan( + "parent", + () -> + pool.preparedQuery("insert into test values ($1, $2) returning *") + .executeBatch(Arrays.asList(Tuple.of(3, "Three"), Tuple.of(4, "Four")))) + .toCompletionStage() + .toCompletableFuture() + .get(30, TimeUnit.SECONDS); + + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> span.hasName("parent").hasKind(SpanKind.INTERNAL), + span -> + span.hasName("INSERT tempdb.test") + .hasKind(SpanKind.CLIENT) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + equalTo(maybeStable(DB_NAME), DB), + equalTo(DB_USER, emitStableDatabaseSemconv() ? null : USER_DB), + equalTo( + maybeStable(DB_STATEMENT), + "insert into test values ($1, $2) returning *"), + equalTo(maybeStable(DB_OPERATION), "INSERT"), + equalTo(maybeStable(DB_SQL_TABLE), "test"), + equalTo(SERVER_ADDRESS, host), + equalTo(SERVER_PORT, port)))); + } + + @Test + void testWithTransaction() throws Exception { + testing + .runWithSpan( + "parent", + () -> + pool.withTransaction( + conn -> + conn.preparedQuery("select * from test where id = $1") + .execute(Tuple.of(1)))) + .toCompletionStage() + .toCompletableFuture() + .get(30, TimeUnit.SECONDS); + + assertPreparedSelect(); + } + + @Test + void testWithConnection() throws Exception { + testing + .runWithSpan( + "parent", + () -> + pool.withConnection( + conn -> + conn.preparedQuery("select * from test where id = $1") + .execute(Tuple.of(1)))) + .toCompletionStage() + .toCompletableFuture() + .get(30, TimeUnit.SECONDS); + + assertPreparedSelect(); + } + + @Test + void testManyQueries() throws Exception { + int count = 50; + CountDownLatch latch = new CountDownLatch(count); + List> futureList = new ArrayList<>(); + List> resultList = new ArrayList<>(); + for (int i = 0; i < count; i++) { + CompletableFuture future = new CompletableFuture<>(); + futureList.add(future); + resultList.add( + future.whenComplete((rows, throwable) -> testing.runWithSpan("callback", () -> {}))); + } + for (CompletableFuture future : futureList) { + testing.runWithSpan( + "parent", + () -> + pool.query("select * from test") + .execute() + .onComplete( + rowSetAsyncResult -> { + if (rowSetAsyncResult.succeeded()) { + future.complete(rowSetAsyncResult.result()); + } else { + future.completeExceptionally(rowSetAsyncResult.cause()); + } + latch.countDown(); + })); + } + latch.await(30, TimeUnit.SECONDS); + for (CompletableFuture result : resultList) { + result.get(10, TimeUnit.SECONDS); + } + + List> assertions = + Collections.nCopies( + count, + trace -> + trace.hasSpansSatisfyingExactly( + span -> span.hasName("parent").hasKind(SpanKind.INTERNAL), + span -> + span.hasName("SELECT tempdb.test") + .hasKind(SpanKind.CLIENT) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + equalTo(maybeStable(DB_NAME), DB), + equalTo(DB_USER, emitStableDatabaseSemconv() ? null : USER_DB), + equalTo(maybeStable(DB_STATEMENT), "select * from test"), + equalTo(maybeStable(DB_OPERATION), "SELECT"), + equalTo(maybeStable(DB_SQL_TABLE), "test"), + equalTo(SERVER_ADDRESS, host), + equalTo(SERVER_PORT, port)), + span -> + span.hasName("callback") + .hasKind(SpanKind.INTERNAL) + .hasParent(trace.getSpan(0)))); + testing.waitAndAssertTraces(assertions); + } + + @Test + void testConcurrency() throws Exception { + int count = 50; + CountDownLatch latch = new CountDownLatch(count); + List> futureList = new ArrayList<>(); + List> resultList = new ArrayList<>(); + for (int i = 0; i < count; i++) { + CompletableFuture future = new CompletableFuture<>(); + futureList.add(future); + resultList.add( + future.whenComplete((rows, throwable) -> testing.runWithSpan("callback", () -> {}))); + } + ExecutorService executorService = Executors.newFixedThreadPool(4); + cleanup.deferCleanup(() -> executorService.shutdown()); + for (CompletableFuture future : futureList) { + executorService.submit( + () -> { + testing.runWithSpan( + "parent", + () -> + pool.withConnection( + conn -> + conn.preparedQuery("select * from test where id = $1") + .execute(Tuple.of(1))) + .onComplete( + rowSetAsyncResult -> { + if (rowSetAsyncResult.succeeded()) { + future.complete(rowSetAsyncResult.result()); + } else { + future.completeExceptionally(rowSetAsyncResult.cause()); + } + latch.countDown(); + })); + }); + } + latch.await(30, TimeUnit.SECONDS); + for (CompletableFuture result : resultList) { + result.get(10, TimeUnit.SECONDS); + } + + List> assertions = + Collections.nCopies( + count, + trace -> + trace.hasSpansSatisfyingExactly( + span -> span.hasName("parent").hasKind(SpanKind.INTERNAL), + span -> + span.hasName("SELECT tempdb.test") + .hasKind(SpanKind.CLIENT) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + equalTo(maybeStable(DB_NAME), DB), + equalTo(DB_USER, emitStableDatabaseSemconv() ? null : USER_DB), + equalTo( + maybeStable(DB_STATEMENT), "select * from test where id = $1"), + equalTo(maybeStable(DB_OPERATION), "SELECT"), + equalTo(maybeStable(DB_SQL_TABLE), "test"), + equalTo(SERVER_ADDRESS, host), + equalTo(SERVER_PORT, port)), + span -> + span.hasName("callback") + .hasKind(SpanKind.INTERNAL) + .hasParent(trace.getSpan(0)))); + testing.waitAndAssertTraces(assertions); + } +} diff --git a/instrumentation/vertx/vertx-sql-client/vertx-sql-client-common/javaagent/build.gradle.kts b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-common/javaagent/build.gradle.kts new file mode 100644 index 000000000000..677838399411 --- /dev/null +++ b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-common/javaagent/build.gradle.kts @@ -0,0 +1,8 @@ +plugins { + id("otel.javaagent-instrumentation") +} + +dependencies { + compileOnly("io.vertx:vertx-sql-client:4.0.0") + compileOnly("io.vertx:vertx-codegen:4.0.0") +} diff --git a/instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientAttributesGetter.java b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/sql/VertxSqlClientAttributesGetter.java similarity index 96% rename from instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientAttributesGetter.java rename to instrumentation/vertx/vertx-sql-client/vertx-sql-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/sql/VertxSqlClientAttributesGetter.java index 8064e874c783..339393f94c38 100644 --- a/instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientAttributesGetter.java +++ b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/sql/VertxSqlClientAttributesGetter.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql; +package io.opentelemetry.javaagent.instrumentation.vertx.sql; import static java.util.Collections.singleton; @@ -16,7 +16,7 @@ import java.util.function.Function; import javax.annotation.Nullable; -public enum VertxSqlClientAttributesGetter +enum VertxSqlClientAttributesGetter implements SqlClientAttributesGetter { INSTANCE; diff --git a/instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientNetAttributesGetter.java b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/sql/VertxSqlClientNetAttributesGetter.java similarity index 72% rename from instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientNetAttributesGetter.java rename to instrumentation/vertx/vertx-sql-client/vertx-sql-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/sql/VertxSqlClientNetAttributesGetter.java index f14caf7e8caf..3b05f172fb08 100644 --- a/instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientNetAttributesGetter.java +++ b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/sql/VertxSqlClientNetAttributesGetter.java @@ -3,13 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql; +package io.opentelemetry.javaagent.instrumentation.vertx.sql; import io.opentelemetry.instrumentation.api.semconv.network.ServerAttributesGetter; import javax.annotation.Nullable; -public enum VertxSqlClientNetAttributesGetter - implements ServerAttributesGetter { +enum VertxSqlClientNetAttributesGetter implements ServerAttributesGetter { INSTANCE; @Nullable diff --git a/instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientRequest.java b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/sql/VertxSqlClientRequest.java similarity index 93% rename from instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientRequest.java rename to instrumentation/vertx/vertx-sql-client/vertx-sql-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/sql/VertxSqlClientRequest.java index 6355fd3f6e24..c4ac6a4cc0f7 100644 --- a/instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/v4_0/sql/VertxSqlClientRequest.java +++ b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/sql/VertxSqlClientRequest.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql; +package io.opentelemetry.javaagent.instrumentation.vertx.sql; import io.vertx.sqlclient.SqlConnectOptions; diff --git a/instrumentation/vertx/vertx-sql-client/vertx-sql-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/sql/VertxSqlClientUtil.java b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/sql/VertxSqlClientUtil.java new file mode 100644 index 000000000000..470ed8d1977b --- /dev/null +++ b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/sql/VertxSqlClientUtil.java @@ -0,0 +1,91 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.vertx.sql; + +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.api.util.VirtualField; +import io.vertx.core.Future; +import io.vertx.core.Promise; +import io.vertx.sqlclient.Pool; +import io.vertx.sqlclient.SqlConnectOptions; +import java.util.concurrent.CompletableFuture; + +public final class VertxSqlClientUtil { + private static final ThreadLocal connectOptions = new ThreadLocal<>(); + + public static void setSqlConnectOptions(SqlConnectOptions sqlConnectOptions) { + connectOptions.set(sqlConnectOptions); + } + + public static SqlConnectOptions getSqlConnectOptions() { + return connectOptions.get(); + } + + private static final VirtualField poolConnectOptions = + VirtualField.find(Pool.class, SqlConnectOptions.class); + + public static void setPoolConnectOptions(Pool pool, SqlConnectOptions sqlConnectOptions) { + poolConnectOptions.set(pool, sqlConnectOptions); + } + + public static SqlConnectOptions getPoolSqlConnectOptions(Pool pool) { + return poolConnectOptions.get(pool); + } + + private static final VirtualField, RequestData> requestDataField = + VirtualField.find(Promise.class, RequestData.class); + + public static void attachRequest( + Promise promise, VertxSqlClientRequest request, Context context, Context parentContext) { + requestDataField.set(promise, new RequestData(request, context, parentContext)); + } + + public static Scope endQuerySpan( + Instrumenter instrumenter, + Promise promise, + Throwable throwable) { + RequestData requestData = requestDataField.get(promise); + if (requestData == null) { + return null; + } + instrumenter.end(requestData.context, requestData.request, null, throwable); + return requestData.parentContext.makeCurrent(); + } + + static class RequestData { + final VertxSqlClientRequest request; + final Context context; + final Context parentContext; + + RequestData(VertxSqlClientRequest request, Context context, Context parentContext) { + this.request = request; + this.context = context; + this.parentContext = parentContext; + } + } + + public static Future wrapContext(Future future) { + Context context = Context.current(); + CompletableFuture result = new CompletableFuture<>(); + future + .toCompletionStage() + .whenComplete( + (value, throwable) -> { + try (Scope ignore = context.makeCurrent()) { + if (throwable != null) { + result.completeExceptionally(throwable); + } else { + result.complete(value); + } + } + }); + return Future.fromCompletionStage(result); + } + + private VertxSqlClientUtil() {} +} diff --git a/instrumentation/vertx/vertx-sql-client/vertx-sql-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/sql/VertxSqlInstrumenterFactory.java b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/sql/VertxSqlInstrumenterFactory.java new file mode 100644 index 000000000000..d21b69444cd3 --- /dev/null +++ b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/vertx/sql/VertxSqlInstrumenterFactory.java @@ -0,0 +1,47 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.vertx.sql; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.instrumentation.api.incubator.semconv.db.DbClientMetrics; +import io.opentelemetry.instrumentation.api.incubator.semconv.db.DbClientSpanNameExtractor; +import io.opentelemetry.instrumentation.api.incubator.semconv.db.SqlClientAttributesExtractor; +import io.opentelemetry.instrumentation.api.incubator.semconv.net.PeerServiceAttributesExtractor; +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.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.semconv.network.ServerAttributesExtractor; +import io.opentelemetry.javaagent.bootstrap.internal.AgentCommonConfig; + +public final class VertxSqlInstrumenterFactory { + + public static Instrumenter createInstrumenter( + String instrumentationName) { + SpanNameExtractor spanNameExtractor = + DbClientSpanNameExtractor.create(VertxSqlClientAttributesGetter.INSTANCE); + + InstrumenterBuilder builder = + Instrumenter.builder( + GlobalOpenTelemetry.get(), instrumentationName, spanNameExtractor) + .addAttributesExtractor( + SqlClientAttributesExtractor.builder(VertxSqlClientAttributesGetter.INSTANCE) + .setStatementSanitizationEnabled( + AgentCommonConfig.get().isStatementSanitizationEnabled()) + .build()) + .addAttributesExtractor( + ServerAttributesExtractor.create(VertxSqlClientNetAttributesGetter.INSTANCE)) + .addAttributesExtractor( + PeerServiceAttributesExtractor.create( + VertxSqlClientNetAttributesGetter.INSTANCE, + AgentCommonConfig.get().getPeerServiceResolver())) + .addOperationMetrics(DbClientMetrics.get()); + + return builder.buildInstrumenter(SpanKindExtractor.alwaysClient()); + } + + private VertxSqlInstrumenterFactory() {} +} diff --git a/instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/vertx/sqlclient/impl/QueryExecutorUtil.java b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-common/javaagent/src/main/java/io/vertx/sqlclient/impl/QueryExecutorUtil.java similarity index 100% rename from instrumentation/vertx/vertx-sql-client-4.0/javaagent/src/main/java/io/vertx/sqlclient/impl/QueryExecutorUtil.java rename to instrumentation/vertx/vertx-sql-client/vertx-sql-client-common/javaagent/src/main/java/io/vertx/sqlclient/impl/QueryExecutorUtil.java diff --git a/settings.gradle.kts b/settings.gradle.kts index cefa52b83cb7..083f7637421c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -604,7 +604,9 @@ include(":instrumentation:vertx:vertx-kafka-client-3.6:javaagent") include(":instrumentation:vertx:vertx-kafka-client-3.6:testing") include(":instrumentation:vertx:vertx-redis-client-4.0:javaagent") include(":instrumentation:vertx:vertx-rx-java-3.5:javaagent") -include(":instrumentation:vertx:vertx-sql-client-4.0:javaagent") +include(":instrumentation:vertx:vertx-sql-client:vertx-sql-client-4.0:javaagent") +include(":instrumentation:vertx:vertx-sql-client:vertx-sql-client-5.0:javaagent") +include(":instrumentation:vertx:vertx-sql-client:vertx-sql-client-common:javaagent") include(":instrumentation:vertx:vertx-web-3.0:javaagent") include(":instrumentation:vertx:vertx-web-3.0:testing") include(":instrumentation:vibur-dbcp-11.0:javaagent") From 5a3b1b4e5d9b779d41824596bf87392548633cd0 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Fri, 23 May 2025 17:16:22 +0300 Subject: [PATCH 2/3] update fossa conf --- .fossa.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.fossa.yml b/.fossa.yml index 0d29905b0eb0..ccc9ec9f8d38 100644 --- a/.fossa.yml +++ b/.fossa.yml @@ -958,9 +958,6 @@ targets: - type: gradle path: ./ target: ':instrumentation:vertx:vertx-rx-java-3.5:javaagent' - - type: gradle - path: ./ - target: ':instrumentation:vertx:vertx-sql-client-4.0:javaagent' - type: gradle path: ./ target: ':instrumentation:vertx:vertx-web-3.0:javaagent' @@ -1117,6 +1114,15 @@ targets: - type: gradle path: ./ target: ':instrumentation:vertx:vertx-http-client:vertx-http-client-common:javaagent' + - type: gradle + path: ./ + target: ':instrumentation:vertx:vertx-sql-client:vertx-sql-client-4.0:javaagent' + - type: gradle + path: ./ + target: ':instrumentation:vertx:vertx-sql-client:vertx-sql-client-5.0:javaagent' + - type: gradle + path: ./ + target: ':instrumentation:vertx:vertx-sql-client:vertx-sql-client-common:javaagent' experimental: gradle: From 884cf8d05d91209e76a71a43f553b69539622be8 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Fri, 23 May 2025 19:05:15 +0300 Subject: [PATCH 3/3] set min java version to 11 --- .../vertx-sql-client-5.0/javaagent/build.gradle.kts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/build.gradle.kts b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/build.gradle.kts index 012878cf49da..eb511e08a1c7 100644 --- a/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/build.gradle.kts +++ b/instrumentation/vertx/vertx-sql-client/vertx-sql-client-5.0/javaagent/build.gradle.kts @@ -11,6 +11,10 @@ muzzle { } } +otelJava { + minJavaVersionSupported.set(JavaVersion.VERSION_11) +} + dependencies { val version = "5.0.0" library("io.vertx:vertx-sql-client:$version")