Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_OPERATION;
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_SYSTEM;
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_USER;
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DbSystemNameIncubatingValues.POSTGRESQL;
import static java.util.concurrent.TimeUnit.SECONDS;

import io.opentelemetry.api.trace.Span;
Expand Down Expand Up @@ -299,6 +301,9 @@ private void assertTrace() {
.hasKind(SpanKind.CLIENT)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
equalTo(
maybeStable(DB_SYSTEM),
emitStableDatabaseSemconv() ? POSTGRESQL : null),
equalTo(maybeStable(DB_NAME), DB),
equalTo(DB_USER, emitStableDatabaseSemconv() ? null : USER_DB),
equalTo(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_OPERATION;
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_SYSTEM;
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_USER;
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DbSystemNameIncubatingValues.POSTGRESQL;
import static java.util.concurrent.TimeUnit.SECONDS;

import io.opentelemetry.api.trace.Span;
Expand Down Expand Up @@ -310,6 +312,9 @@ private static void assertTrace() {
.hasKind(SpanKind.CLIENT)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
equalTo(
maybeStable(DB_SYSTEM),
emitStableDatabaseSemconv() ? POSTGRESQL : null),
equalTo(maybeStable(DB_NAME), DB),
equalTo(DB_USER, emitStableDatabaseSemconv() ? null : USER_DB),
equalTo(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ dependencies {
compileOnly("io.vertx:vertx-web:$vertxVersion")
compileOnly("io.vertx:vertx-rx-java2:$vertxVersion")

testInstrumentation(project(":instrumentation:executors:javaagent"))
testInstrumentation(project(":instrumentation:jdbc:javaagent"))
testInstrumentation(project(":instrumentation:netty:netty-4.1:javaagent"))
testInstrumentation(project(":instrumentation:rxjava:rxjava-2.0:javaagent"))
testInstrumentation(project(":instrumentation:vertx:vertx-http-client:vertx-http-client-3.0:javaagent"))
testInstrumentation(project(":instrumentation:vertx:vertx-http-client:vertx-http-client-4.0:javaagent"))
testInstrumentation(project(":instrumentation:vertx:vertx-http-client:vertx-http-client-5.0:javaagent"))
testInstrumentation(project(":instrumentation:vertx:vertx-sql-client:vertx-sql-client-4.0:javaagent"))
testInstrumentation(project(":instrumentation:vertx:vertx-sql-client:vertx-sql-client-5.0:javaagent"))
testInstrumentation(project(":instrumentation:vertx:vertx-web-3.0:javaagent"))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,14 @@
import static io.opentelemetry.semconv.UrlAttributes.URL_QUERY;
import static io.opentelemetry.semconv.UrlAttributes.URL_SCHEME;
import static io.opentelemetry.semconv.UserAgentAttributes.USER_AGENT_ORIGINAL;
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_CONNECTION_STRING;
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_SQL_TABLE;
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_STATEMENT;
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SYSTEM;
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_USER;
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DbSystemNameIncubatingValues.HSQLDB;
import static org.assertj.core.api.Assertions.assertThat;

import io.opentelemetry.api.GlobalOpenTelemetry;
Expand Down Expand Up @@ -120,10 +125,19 @@ void contextPropagation() {
.hasKind(SpanKind.INTERNAL)
.hasParent(trace.getSpan(1)),
span ->
span.hasName("SELECT products")
span.hasName(
emitStableDatabaseSemconv()
? "SELECT products"
: "SELECT test.products")
.hasKind(SpanKind.CLIENT)
.hasParent(trace.getSpan(2))
.hasAttributesSatisfyingExactly(
equalTo(maybeStable(DB_SYSTEM), HSQLDB),
equalTo(maybeStable(DB_NAME), "test"),
equalTo(DB_USER, emitStableDatabaseSemconv() ? null : "SA"),
equalTo(
DB_CONNECTION_STRING,
emitStableDatabaseSemconv() ? null : "hsqldb:mem:"),
equalTo(
maybeStable(DB_STATEMENT),
"SELECT id, name, price, weight FROM products"),
Expand Down Expand Up @@ -220,24 +234,33 @@ void highConcurrency() {
.hasAttributesSatisfyingExactly(
equalTo(longKey(TEST_REQUEST_ID_ATTRIBUTE), requestId)),
span ->
span.hasName("SELECT products")
span.hasName(
emitStableDatabaseSemconv()
? "SELECT products"
: "SELECT test.products")
.hasKind(SpanKind.CLIENT)
.hasParent(trace.getSpan(3))
.hasAttributesSatisfyingExactly(
equalTo(maybeStable(DB_SYSTEM), HSQLDB),
equalTo(maybeStable(DB_NAME), "test"),
equalTo(DB_USER, emitStableDatabaseSemconv() ? null : "SA"),
equalTo(
DB_CONNECTION_STRING,
emitStableDatabaseSemconv() ? null : "hsqldb:mem:"),
equalTo(
maybeStable(DB_STATEMENT),
"SELECT id AS request"
+ requestId
+ ", name, price, weight FROM products"),
equalTo(
DB_QUERY_SUMMARY,
emitStableDatabaseSemconv() ? "SELECT products" : null),
equalTo(
maybeStable(DB_OPERATION),
emitStableDatabaseSemconv() ? null : "SELECT"),
equalTo(
maybeStable(DB_SQL_TABLE),
emitStableDatabaseSemconv() ? null : "products")));
emitStableDatabaseSemconv() ? null : "products"),
equalTo(
DB_QUERY_SUMMARY,
emitStableDatabaseSemconv() ? "SELECT products" : null)));
});
}
testing.waitAndAssertTraces(assertions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,18 @@ dependencies {

implementation(project(":instrumentation:vertx:vertx-sql-client:vertx-sql-client-common:javaagent"))

testInstrumentation(project(":instrumentation:jdbc: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")
testImplementation("io.vertx:vertx-jdbc-client:$version")
testImplementation("io.agroal:agroal-pool:1.9")
testImplementation("org.hsqldb:hsqldb:2.3.4")

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-jdbc-client:4.+") // see vertx-sql-client-5.0 module
latestDepTestLibrary("io.vertx:vertx-codegen:4.+") // see vertx-sql-client-5.0 module
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@

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.getDbSystemNameFromClassName;
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 io.opentelemetry.javaagent.instrumentation.vertx.v4_0.sql.VertxSqlClientSingletons.storeConnectOptionsDbSystem;
import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
import static net.bytebuddy.matcher.ElementMatchers.isStatic;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.returns;
Expand Down Expand Up @@ -45,12 +48,16 @@ public ElementMatcher<TypeDescription> typeMatcher() {

@Override
public void transform(TypeTransformer transformer) {
// In vertx 4.x, database-specific sub-interfaces like PgPool and MySQLPool declare their own
// static pool() methods that take subtypes of SqlConnectOptions (e.g. PgConnectOptions) and
// return subtypes of Pool. These are independent static methods, not overrides, and have their
// own separate code paths. hasSuperType is needed to match these variant signatures.
transformer.applyAdviceToMethod(
named("pool")
.and(isStatic())
.and(takesArguments(3))
.and(takesArgument(1, named("io.vertx.sqlclient.SqlConnectOptions")))
.and(returns(named("io.vertx.sqlclient.Pool"))),
.and(takesArgument(1, hasSuperType(named("io.vertx.sqlclient.SqlConnectOptions"))))
.and(returns(hasSuperType(named("io.vertx.sqlclient.Pool")))),
PoolInstrumentation.class.getName() + "$PoolAdvice");

transformer.applyAdviceToMethod(
Expand Down Expand Up @@ -82,6 +89,10 @@ public static void onExit(
}

setPoolConnectOptions(pool, sqlConnectOptions);
// Detect db system from pool implementation class (e.g. PgPool -> postgresql).
// This handles cases where connect options is a generic SqlConnectOptions
// but the pool is database-specific (e.g. Hibernate Reactive).
storeConnectOptionsDbSystem(sqlConnectOptions, getDbSystemNameFromClassName(pool));
setSqlConnectOptions(null);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
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.SqlConnectOptions;
import io.vertx.sqlclient.impl.PreparedStatement;
import io.vertx.sqlclient.impl.QueryExecutorUtil;
import javax.annotation.Nullable;
Expand Down Expand Up @@ -102,9 +103,21 @@ public static AdviceScope start(Object queryExecutor, Object[] arguments) {
return new AdviceScope(callDepth);
}

SqlConnectOptions connectOptions = QueryExecutorUtil.getConnectOptions(queryExecutor);
// connectOptions is null when the pool was created via JDBCPool which bypasses the
// Pool.pool() factory, in that case we skip vertx-sql-client span creation and let JDBC
// instrumentation handle it
if (connectOptions == null) {
return new AdviceScope(callDepth);
}
// Try db system stored from pool class first (handles generic SqlConnectOptions),
// fall back to class name detection on the connect options itself
String dbSystem = VertxSqlClientSingletons.getConnectOptionsDbSystem(connectOptions);
if (dbSystem == null) {
dbSystem = VertxSqlClientUtil.getDbSystemNameFromClassName(connectOptions);
}
VertxSqlClientRequest otelRequest =
new VertxSqlClientRequest(
sql, QueryExecutorUtil.getConnectOptions(queryExecutor), preparedStatement);
new VertxSqlClientRequest(sql, connectOptions, preparedStatement, dbSystem);
Context parentContext = Context.current();
if (!instrumenter().shouldStart(parentContext, otelRequest)) {
return new AdviceScope(callDepth, null, null, null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import io.vertx.sqlclient.SqlConnectOptions;
import io.vertx.sqlclient.SqlConnection;
import io.vertx.sqlclient.impl.SqlClientBase;
import javax.annotation.Nullable;

public final class VertxSqlClientSingletons {
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.vertx-sql-client-4.0";
Expand All @@ -26,6 +27,26 @@ public static Instrumenter<VertxSqlClientRequest, Void> instrumenter() {
private static final VirtualField<SqlClientBase<?>, SqlConnectOptions> connectOptionsField =
VirtualField.find(SqlClientBase.class, SqlConnectOptions.class);

private static final VirtualField<SqlConnectOptions, String> connectOptionsDbSystem =
VirtualField.find(SqlConnectOptions.class, String.class);

public static void storeConnectOptionsDbSystem(
SqlConnectOptions connectOptions, String dbSystem) {
if (connectOptions != null) {
connectOptionsDbSystem.set(connectOptions, dbSystem);
}
}

@Nullable
public static String getConnectOptionsDbSystem(SqlConnectOptions connectOptions) {
if (connectOptions != null) {
return connectOptionsDbSystem.get(connectOptions);
}
// null when db system was not captured at pool creation time; callers should fall back
// to getDbSystemNameFromClassName() on the connect options instance
return null;
}

public static SqlConnectOptions getSqlConnectOptions(SqlClientBase<?> sqlClientBase) {
return connectOptionsField.get(sqlClientBase);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.vertx.v4_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.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStableDbSystemName;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
import static io.opentelemetry.semconv.DbAttributes.DB_QUERY_SUMMARY;
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_CONNECTION_STRING;
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_SQL_TABLE;
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_STATEMENT;
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SYSTEM;
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_USER;
import static java.util.concurrent.TimeUnit.SECONDS;

import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
import io.vertx.core.Vertx;
import io.vertx.jdbcclient.JDBCConnectOptions;
import io.vertx.jdbcclient.JDBCPool;
import io.vertx.sqlclient.Pool;
import io.vertx.sqlclient.PoolOptions;
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;

/**
* Tests that vertx-sql-client instrumentation is suppressed for JDBC-backed connections and JDBC
* instrumentation handles them instead.
*/
@SuppressWarnings("deprecation") // using deprecated semconv
class VertxJdbcClientTest {

private static final String DB = "testdb";

@RegisterExtension
private static final InstrumentationExtension testing = AgentInstrumentationExtension.create();

private static Vertx vertx;
private static Pool pool;

@BeforeAll
static void setUp() throws Exception {
vertx = Vertx.vertx();
pool =
JDBCPool.pool(
vertx,
new JDBCConnectOptions().setJdbcUrl("jdbc:hsqldb:mem:" + DB),
new PoolOptions().setMaxSize(4));
pool.query("create table test(id int primary key, name varchar(255))")
.execute()
.compose(r -> pool.query("insert into test values (1, 'Hello'), (2, 'World')").execute())
.toCompletionStage()
.toCompletableFuture()
.get(30, SECONDS);
}

@AfterAll
static void cleanUp() {
pool.close();
vertx.close();
}

@Test
void testSimpleSelect() throws Exception {
testing
.runWithSpan("parent", () -> pool.query("select * from test").execute())
.toCompletionStage()
.toCompletableFuture()
.get(30, SECONDS);

testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span -> span.hasName("parent").hasKind(SpanKind.INTERNAL),
span ->
span.hasName(
emitStableDatabaseSemconv() ? "SELECT test" : "SELECT " + DB + ".test")
.hasKind(SpanKind.CLIENT)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
equalTo(maybeStable(DB_SYSTEM), maybeStableDbSystemName("hsqldb")),
equalTo(maybeStable(DB_NAME), DB),
equalTo(DB_USER, emitStableDatabaseSemconv() ? null : "SA"),
equalTo(
DB_CONNECTION_STRING,
emitStableDatabaseSemconv() ? null : "hsqldb:mem:"),
equalTo(maybeStable(DB_STATEMENT), "select * from test"),
equalTo(
DB_QUERY_SUMMARY,
emitStableDatabaseSemconv() ? "SELECT test" : null),
equalTo(
maybeStable(DB_OPERATION),
emitStableDatabaseSemconv() ? null : "SELECT"),
equalTo(
maybeStable(DB_SQL_TABLE),
emitStableDatabaseSemconv() ? null : "test"))));
}
}
Loading
Loading