Allow JDBC autoinstrumentation to use a custom OpenTelemetry instance to be more DI (e.g. Spring Boot) friendly
Related to issue
MODIFY
instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/JdbcSingletons.java
instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/JdbcSingletons.java
package io.opentelemetry.javaagent.instrumentation.jdbc;
+import static io.opentelemetry.instrumentation.jdbc.internal.DataSourceInstrumenterFactory.createDataSourceInstrumenter;
+
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
@@ -17,17 +19,20 @@ import io.opentelemetry.instrumentation.jdbc.internal.JdbcAttributesGetter;
import io.opentelemetry.instrumentation.jdbc.internal.JdbcNetAttributesGetter;
import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig;
import io.opentelemetry.javaagent.bootstrap.internal.InstrumentationConfig;
+import javax.sql.DataSource;
public final class JdbcSingletons {
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.jdbc";
- private static final Instrumenter<DbRequest, Void> INSTRUMENTER;
+ private static final Instrumenter<DbRequest, Void> STATEMENT_INSTRUMENTER;
+ public static final Instrumenter<DataSource, Void> DATASOURCE_INSTRUMENTER =
+ createDataSourceInstrumenter(GlobalOpenTelemetry.get());
static {
JdbcAttributesGetter dbAttributesGetter = new JdbcAttributesGetter();
JdbcNetAttributesGetter netAttributesGetter = new JdbcNetAttributesGetter();
- INSTRUMENTER =
+ STATEMENT_INSTRUMENTER =
Instrumenter.<DbRequest, Void>builder(
GlobalOpenTelemetry.get(),
INSTRUMENTATION_NAME,
@@ -47,8 +52,12 @@ public final class JdbcSingletons {
.buildInstrumenter(SpanKindExtractor.alwaysClient());
}
- public static Instrumenter<DbRequest, Void> instrumenter() {
- return INSTRUMENTER;
+ public static Instrumenter<DbRequest, Void> statementInstrumenter() {
+ return STATEMENT_INSTRUMENTER;
+ }
+
+ public static Instrumenter<DataSource, Void> dataSourceInstrumenter() {
+ return DATASOURCE_INSTRUMENTER;
}
private JdbcSingletons() {}

MODIFY
instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/PreparedStatementInstrumentation.java
instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/PreparedStatementInstrumentation.java
@@ -8,7 +8,7 @@ package io.opentelemetry.javaagent.instrumentation.jdbc;
import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface;
-import static io.opentelemetry.javaagent.instrumentation.jdbc.JdbcSingletons.instrumenter;
+import static io.opentelemetry.javaagent.instrumentation.jdbc.JdbcSingletons.statementInstrumenter;
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
import static net.bytebuddy.matcher.ElementMatchers.named;
@@ -70,11 +70,11 @@ public class PreparedStatementInstrumentation implements TypeInstrumentation {
Context parentContext = currentContext();
request = DbRequest.create(statement);
- if (request == null || !instrumenter().shouldStart(parentContext, request)) {
+ if (request == null || !statementInstrumenter().shouldStart(parentContext, request)) {
return;
}
- context = instrumenter().start(parentContext, request);
+ context = statementInstrumenter().start(parentContext, request);
scope = context.makeCurrent();
}
@@ -91,7 +91,7 @@ public class PreparedStatementInstrumentation implements TypeInstrumentation {
if (scope != null) {
scope.close();
- instrumenter().end(context, request, null, throwable);
+ statementInstrumenter().end(context, request, null, throwable);
}
}
}

MODIFY
instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/StatementInstrumentation.java
instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/StatementInstrumentation.java
@@ -8,7 +8,7 @@ package io.opentelemetry.javaagent.instrumentation.jdbc;
import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface;
-import static io.opentelemetry.javaagent.instrumentation.jdbc.JdbcSingletons.instrumenter;
+import static io.opentelemetry.javaagent.instrumentation.jdbc.JdbcSingletons.statementInstrumenter;
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
import static net.bytebuddy.matcher.ElementMatchers.named;
@@ -70,11 +70,11 @@ public class StatementInstrumentation implements TypeInstrumentation {
Context parentContext = currentContext();
request = DbRequest.create(statement, sql);
- if (request == null || !instrumenter().shouldStart(parentContext, request)) {
+ if (request == null || !statementInstrumenter().shouldStart(parentContext, request)) {
return;
}
- context = instrumenter().start(parentContext, request);
+ context = statementInstrumenter().start(parentContext, request);
scope = context.makeCurrent();
}
@@ -91,7 +91,7 @@ public class StatementInstrumentation implements TypeInstrumentation {
if (scope != null) {
scope.close();
- instrumenter().end(context, request, null, throwable);
+ statementInstrumenter().end(context, request, null, throwable);
}
}
}

MODIFY
instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/datasource/DataSourceInstrumentation.java
instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/datasource/DataSourceInstrumentation.java
package io.opentelemetry.javaagent.instrumentation.jdbc.datasource;
-import static io.opentelemetry.instrumentation.jdbc.internal.DataSourceSingletons.instrumenter;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface;
+import static io.opentelemetry.javaagent.instrumentation.jdbc.JdbcSingletons.dataSourceInstrumenter;
import static net.bytebuddy.matcher.ElementMatchers.named;
import io.opentelemetry.context.Context;
@@ -20,6 +20,7 @@ import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
public class DataSourceInstrumentation implements TypeInstrumentation {
+
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return implementsInterface(named("javax.sql.DataSource"));
@@ -46,7 +47,7 @@ public class DataSourceInstrumentation implements TypeInstrumentation {
return;
}
- context = instrumenter().start(parentContext, ds);
+ context = dataSourceInstrumenter().start(parentContext, ds);
scope = context.makeCurrent();
}
@@ -60,7 +61,7 @@ public class DataSourceInstrumentation implements TypeInstrumentation {
return;
}
scope.close();
- instrumenter().end(context, ds, null, throwable);
+ dataSourceInstrumenter().end(context, ds, null, throwable);
}
}
}

MODIFY
instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/OpenTelemetryDriver.java
instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/OpenTelemetryDriver.java
package io.opentelemetry.instrumentation.jdbc;
-import static io.opentelemetry.instrumentation.jdbc.internal.JdbcSingletons.INSTRUMENTATION_NAME;
+import static io.opentelemetry.instrumentation.jdbc.internal.JdbcInstrumenterFactory.INSTRUMENTATION_NAME;
+import static io.opentelemetry.instrumentation.jdbc.internal.JdbcSingletons.statementInstrumenter;
import io.opentelemetry.instrumentation.api.internal.EmbeddedInstrumentationProperties;
import io.opentelemetry.instrumentation.jdbc.internal.JdbcConnectionUrlParser;
@@ -211,7 +212,7 @@ public final class OpenTelemetryDriver implements Driver {
DbInfo dbInfo = JdbcConnectionUrlParser.parse(realUrl, info);
- return new OpenTelemetryConnection(connection, dbInfo);
+ return new OpenTelemetryConnection(connection, dbInfo, statementInstrumenter());
}
@Override

MODIFY
instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/datasource/OpenTelemetryDataSource.java
instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/datasource/OpenTelemetryDataSource.java
package io.opentelemetry.instrumentation.jdbc.datasource;
-import static io.opentelemetry.instrumentation.jdbc.internal.DataSourceSingletons.instrumenter;
+import static io.opentelemetry.instrumentation.jdbc.internal.DataSourceInstrumenterFactory.createDataSourceInstrumenter;
+import static io.opentelemetry.instrumentation.jdbc.internal.JdbcInstrumenterFactory.createStatementInstrumenter;
import static io.opentelemetry.instrumentation.jdbc.internal.JdbcUtils.computeDbInfo;
+import io.opentelemetry.api.GlobalOpenTelemetry;
+import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
+import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
+import io.opentelemetry.instrumentation.jdbc.internal.DbRequest;
import io.opentelemetry.instrumentation.jdbc.internal.OpenTelemetryConnection;
import io.opentelemetry.instrumentation.jdbc.internal.ThrowingSupplier;
import io.opentelemetry.instrumentation.jdbc.internal.dbinfo.DbInfo;
@@ -40,29 +45,44 @@ import javax.sql.DataSource;
public class OpenTelemetryDataSource implements DataSource, AutoCloseable {
private final DataSource delegate;
+ private final Instrumenter<DataSource, Void> dataSourceInstrumenter;
+ private final Instrumenter<DbRequest, Void> statementInstrumenter;
+
+ /**
+ * Create a OpenTelemetry DataSource wrapping another DataSource.
+ *
+ * @param delegate the DataSource to wrap
+ */
+ @Deprecated
+ public OpenTelemetryDataSource(DataSource delegate) {
+ this(delegate, GlobalOpenTelemetry.get());
+ }
/**
* Create a OpenTelemetry DataSource wrapping another DataSource. This constructor is primarily
* used by dependency injection frameworks.
*
* @param delegate the DataSource to wrap
+ * @param openTelemetry the OpenTelemetry instance to setup for
*/
- public OpenTelemetryDataSource(DataSource delegate) {
+ public OpenTelemetryDataSource(DataSource delegate, OpenTelemetry openTelemetry) {
this.delegate = delegate;
+ this.dataSourceInstrumenter = createDataSourceInstrumenter(openTelemetry);
+ this.statementInstrumenter = createStatementInstrumenter(openTelemetry);
}
@Override
public Connection getConnection() throws SQLException {
Connection connection = wrapCall(delegate::getConnection);
DbInfo dbInfo = computeDbInfo(connection);
- return new OpenTelemetryConnection(connection, dbInfo);
+ return new OpenTelemetryConnection(connection, dbInfo, statementInstrumenter);
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
Connection connection = wrapCall(() -> delegate.getConnection(username, password));
DbInfo dbInfo = computeDbInfo(connection);
- return new OpenTelemetryConnection(connection, dbInfo);
+ return new OpenTelemetryConnection(connection, dbInfo, statementInstrumenter);
}
@Override
@@ -116,15 +136,15 @@ public class OpenTelemetryDataSource implements DataSource, AutoCloseable {
return callable.call();
}
- Context context = instrumenter().start(parentContext, delegate);
+ Context context = this.dataSourceInstrumenter.start(parentContext, delegate);
T result;
try (Scope ignored = context.makeCurrent()) {
result = callable.call();
} catch (Throwable t) {
- instrumenter().end(context, delegate, null, t);
+ this.dataSourceInstrumenter.end(context, delegate, null, t);
throw t;
}
- instrumenter().end(context, delegate, null, null);
+ this.dataSourceInstrumenter.end(context, delegate, null, null);
return result;
}
}

ADD
instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/DataSourceInstrumenterFactory.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.jdbc.internal;
+
+import io.opentelemetry.api.OpenTelemetry;
+import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
+import io.opentelemetry.instrumentation.api.instrumenter.code.CodeAttributesExtractor;
+import io.opentelemetry.instrumentation.api.instrumenter.code.CodeSpanNameExtractor;
+import javax.sql.DataSource;
+
+/**
+ * This class is internal and is hence not for public use. Its APIs are unstable and can change at
+ * any time.
+ */
+public final class DataSourceInstrumenterFactory {
+ private static final String INSTRUMENTATION_NAME = "io.opentelemetry.jdbc";
+ private static final DataSourceCodeAttributesGetter codeAttributesGetter =
+ new DataSourceCodeAttributesGetter();
+
+ public static Instrumenter<DataSource, Void> createDataSourceInstrumenter(
+ OpenTelemetry openTelemetry) {
+ return Instrumenter.<DataSource, Void>builder(
+ openTelemetry, INSTRUMENTATION_NAME, CodeSpanNameExtractor.create(codeAttributesGetter))
+ .addAttributesExtractor(CodeAttributesExtractor.create(codeAttributesGetter))
+ .buildInstrumenter();
+ }
+
+ private DataSourceInstrumenterFactory() {}
+}

DELETE
instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/DataSourceSingletons.java
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.instrumentation.jdbc.internal;
-
-import io.opentelemetry.api.GlobalOpenTelemetry;
-import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
-import io.opentelemetry.instrumentation.api.instrumenter.code.CodeAttributesExtractor;
-import io.opentelemetry.instrumentation.api.instrumenter.code.CodeSpanNameExtractor;
-import javax.sql.DataSource;
-
-/**
- * This class is internal and is hence not for public use. Its APIs are unstable and can change at
- * any time.
- */
-public final class DataSourceSingletons {
- private static final String INSTRUMENTATION_NAME = "io.opentelemetry.jdbc";
-
- private static final Instrumenter<DataSource, Void> INSTRUMENTER;
-
- static {
- DataSourceCodeAttributesGetter codeAttributesGetter = new DataSourceCodeAttributesGetter();
-
- INSTRUMENTER =
- Instrumenter.<DataSource, Void>builder(
- GlobalOpenTelemetry.get(),
- INSTRUMENTATION_NAME,
- CodeSpanNameExtractor.create(codeAttributesGetter))
- .addAttributesExtractor(CodeAttributesExtractor.create(codeAttributesGetter))
- .buildInstrumenter();
- }
-
- public static Instrumenter<DataSource, Void> instrumenter() {
- return INSTRUMENTER;
- }
-
- private DataSourceSingletons() {}
-}

ADD
instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/JdbcInstrumenterFactory.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.jdbc.internal;
+
+import io.opentelemetry.api.GlobalOpenTelemetry;
+import io.opentelemetry.api.OpenTelemetry;
+import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
+import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
+import io.opentelemetry.instrumentation.api.instrumenter.db.DbClientSpanNameExtractor;
+import io.opentelemetry.instrumentation.api.instrumenter.db.SqlClientAttributesExtractor;
+import io.opentelemetry.instrumentation.api.instrumenter.net.NetClientAttributesExtractor;
+import io.opentelemetry.instrumentation.api.internal.ConfigPropertiesUtil;
+
+/**
+ * This class is internal and is hence not for public use. Its APIs are unstable and can change at
+ * any time.
+ */
+public final class JdbcInstrumenterFactory {
+ public static final String INSTRUMENTATION_NAME = "io.opentelemetry.jdbc";
+ private static final JdbcAttributesGetter dbAttributesGetter = new JdbcAttributesGetter();
+ private static final JdbcNetAttributesGetter netAttributesGetter = new JdbcNetAttributesGetter();
+
+ public static Instrumenter<DbRequest, Void> createStatementInstrumenter() {
+ return createStatementInstrumenter(GlobalOpenTelemetry.get());
+ }
+
+ public static Instrumenter<DbRequest, Void> createStatementInstrumenter(
+ OpenTelemetry openTelemetry) {
+ return Instrumenter.<DbRequest, Void>builder(
+ openTelemetry,
+ INSTRUMENTATION_NAME,
+ DbClientSpanNameExtractor.create(dbAttributesGetter))
+ .addAttributesExtractor(
+ SqlClientAttributesExtractor.builder(dbAttributesGetter)
+ .setStatementSanitizationEnabled(
+ ConfigPropertiesUtil.getBoolean(
+ "otel.instrumentation.common.db-statement-sanitizer.enabled", true))
+ .build())
+ .addAttributesExtractor(NetClientAttributesExtractor.create(netAttributesGetter))
+ .buildInstrumenter(SpanKindExtractor.alwaysClient());
+ }
+
+ private JdbcInstrumenterFactory() {}
+}

MODIFY
instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/JdbcSingletons.java
instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/JdbcSingletons.java
package io.opentelemetry.instrumentation.jdbc.internal;
+import static io.opentelemetry.instrumentation.jdbc.internal.JdbcInstrumenterFactory.createStatementInstrumenter;
+
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
-import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
-import io.opentelemetry.instrumentation.api.instrumenter.db.DbClientSpanNameExtractor;
-import io.opentelemetry.instrumentation.api.instrumenter.db.SqlClientAttributesExtractor;
-import io.opentelemetry.instrumentation.api.instrumenter.net.NetClientAttributesExtractor;
-import io.opentelemetry.instrumentation.api.internal.ConfigPropertiesUtil;
/**
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
* any time.
*/
public final class JdbcSingletons {
- public static final String INSTRUMENTATION_NAME = "io.opentelemetry.jdbc";
-
- private static final Instrumenter<DbRequest, Void> INSTRUMENTER;
-
- static {
- JdbcAttributesGetter dbAttributesGetter = new JdbcAttributesGetter();
- JdbcNetAttributesGetter netAttributesGetter = new JdbcNetAttributesGetter();
-
- INSTRUMENTER =
- Instrumenter.<DbRequest, Void>builder(
- GlobalOpenTelemetry.get(),
- INSTRUMENTATION_NAME,
- DbClientSpanNameExtractor.create(dbAttributesGetter))
- .addAttributesExtractor(
- SqlClientAttributesExtractor.builder(dbAttributesGetter)
- .setStatementSanitizationEnabled(
- ConfigPropertiesUtil.getBoolean(
- "otel.instrumentation.common.db-statement-sanitizer.enabled", true))
- .build())
- .addAttributesExtractor(NetClientAttributesExtractor.create(netAttributesGetter))
- .buildInstrumenter(SpanKindExtractor.alwaysClient());
- }
+ public static final Instrumenter<DbRequest, Void> STATEMENT_INSTRUMENTER =
+ createStatementInstrumenter(GlobalOpenTelemetry.get());
- public static Instrumenter<DbRequest, Void> instrumenter() {
- return INSTRUMENTER;
+ public static Instrumenter<DbRequest, Void> statementInstrumenter() {
+ return STATEMENT_INSTRUMENTER;
}
private JdbcSingletons() {}

MODIFY
instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryCallableStatement.java
instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryCallableStatement.java
package io.opentelemetry.instrumentation.jdbc.internal;
+import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.jdbc.internal.dbinfo.DbInfo;
import java.io.InputStream;
import java.io.Reader;
@@ -47,8 +48,9 @@ import java.util.Map;
public class OpenTelemetryCallableStatement<S extends CallableStatement>
extends OpenTelemetryPreparedStatement<S> implements CallableStatement {
- public OpenTelemetryCallableStatement(S delegate, DbInfo dbInfo, String query) {
- super(delegate, dbInfo, query);
+ public OpenTelemetryCallableStatement(
+ S delegate, DbInfo dbInfo, String query, Instrumenter<DbRequest, Void> instrumenter) {
+ super(delegate, dbInfo, query, instrumenter);
}
@Override

MODIFY
instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryConnection.java
instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryConnection.java
package io.opentelemetry.instrumentation.jdbc.internal;
+import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.jdbc.internal.dbinfo.DbInfo;
import java.sql.Array;
import java.sql.Blob;
@@ -48,23 +49,26 @@ public class OpenTelemetryConnection implements Connection {
private final Connection delegate;
private final DbInfo dbInfo;
+ protected final Instrumenter<DbRequest, Void> statementInstrumenter;
- public OpenTelemetryConnection(Connection delegate, DbInfo dbInfo) {
+ public OpenTelemetryConnection(
+ Connection delegate, DbInfo dbInfo, Instrumenter<DbRequest, Void> statementInstrumenter) {
this.delegate = delegate;
this.dbInfo = dbInfo;
+ this.statementInstrumenter = statementInstrumenter;
}
@Override
public Statement createStatement() throws SQLException {
Statement statement = delegate.createStatement();
- return new OpenTelemetryStatement<>(statement, dbInfo);
+ return new OpenTelemetryStatement<>(statement, dbInfo, statementInstrumenter);
}
@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency)
throws SQLException {
Statement statement = delegate.createStatement(resultSetType, resultSetConcurrency);
- return new OpenTelemetryStatement<>(statement, dbInfo);
+ return new OpenTelemetryStatement<>(statement, dbInfo, statementInstrumenter);
}
@Override
@@ -72,13 +76,13 @@ public class OpenTelemetryConnection implements Connection {
int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
Statement statement =
delegate.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
- return new OpenTelemetryStatement<>(statement, dbInfo);
+ return new OpenTelemetryStatement<>(statement, dbInfo, statementInstrumenter);
}
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
PreparedStatement statement = delegate.prepareStatement(sql);
- return new OpenTelemetryPreparedStatement<>(statement, dbInfo, sql);
+ return new OpenTelemetryPreparedStatement<>(statement, dbInfo, sql, statementInstrumenter);
}
@Override
@@ -86,7 +90,7 @@ public class OpenTelemetryConnection implements Connection {
throws SQLException {
PreparedStatement statement =
delegate.prepareStatement(sql, resultSetType, resultSetConcurrency);
- return new OpenTelemetryPreparedStatement<>(statement, dbInfo, sql);
+ return new OpenTelemetryPreparedStatement<>(statement, dbInfo, sql, statementInstrumenter);
}
@Override
@@ -95,38 +99,38 @@ public class OpenTelemetryConnection implements Connection {
throws SQLException {
PreparedStatement statement =
delegate.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
- return new OpenTelemetryPreparedStatement<>(statement, dbInfo, sql);
+ return new OpenTelemetryPreparedStatement<>(statement, dbInfo, sql, statementInstrumenter);
}
@Override
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
PreparedStatement statement = delegate.prepareStatement(sql, autoGeneratedKeys);
- return new OpenTelemetryPreparedStatement<>(statement, dbInfo, sql);
+ return new OpenTelemetryPreparedStatement<>(statement, dbInfo, sql, statementInstrumenter);
}
@Override
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
PreparedStatement statement = delegate.prepareStatement(sql, columnIndexes);
- return new OpenTelemetryPreparedStatement<>(statement, dbInfo, sql);
+ return new OpenTelemetryPreparedStatement<>(statement, dbInfo, sql, statementInstrumenter);
}
@Override
public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
PreparedStatement statement = delegate.prepareStatement(sql, columnNames);
- return new OpenTelemetryPreparedStatement<>(statement, dbInfo, sql);
+ return new OpenTelemetryPreparedStatement<>(statement, dbInfo, sql, statementInstrumenter);
}
@Override
public CallableStatement prepareCall(String sql) throws SQLException {
CallableStatement statement = delegate.prepareCall(sql);
- return new OpenTelemetryCallableStatement<>(statement, dbInfo, sql);
+ return new OpenTelemetryCallableStatement<>(statement, dbInfo, sql, statementInstrumenter);
}
@Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency)
throws SQLException {
CallableStatement statement = delegate.prepareCall(sql, resultSetType, resultSetConcurrency);
- return new OpenTelemetryCallableStatement<>(statement, dbInfo, sql);
+ return new OpenTelemetryCallableStatement<>(statement, dbInfo, sql, statementInstrumenter);
}
@Override
@@ -135,7 +139,7 @@ public class OpenTelemetryConnection implements Connection {
throws SQLException {
CallableStatement statement =
delegate.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
- return new OpenTelemetryCallableStatement<>(statement, dbInfo, sql);
+ return new OpenTelemetryCallableStatement<>(statement, dbInfo, sql, statementInstrumenter);
}
@Override

MODIFY
instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryPreparedStatement.java
instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryPreparedStatement.java
package io.opentelemetry.instrumentation.jdbc.internal;
+import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.jdbc.internal.dbinfo.DbInfo;
import java.io.InputStream;
import java.io.Reader;
@@ -49,8 +50,9 @@ import java.util.Calendar;
public class OpenTelemetryPreparedStatement<S extends PreparedStatement>
extends OpenTelemetryStatement<S> implements PreparedStatement {
- public OpenTelemetryPreparedStatement(S delegate, DbInfo dbInfo, String query) {
- super(delegate, dbInfo, query);
+ public OpenTelemetryPreparedStatement(
+ S delegate, DbInfo dbInfo, String query, Instrumenter<DbRequest, Void> instrumenter) {
+ super(delegate, dbInfo, query, instrumenter);
}
@Override

MODIFY
instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryStatement.java
instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryStatement.java
package io.opentelemetry.instrumentation.jdbc.internal;
-import static io.opentelemetry.instrumentation.jdbc.internal.JdbcSingletons.instrumenter;
-
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
+import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.jdbc.internal.dbinfo.DbInfo;
import java.sql.Connection;
import java.sql.ResultSet;
@@ -41,17 +40,20 @@ public class OpenTelemetryStatement<S extends Statement> implements Statement {
protected final S delegate;
protected final DbInfo dbInfo;
protected final String query;
+ protected final Instrumenter<DbRequest, Void> instrumenter;
private final ArrayList<String> batchCommands = new ArrayList<>();
- OpenTelemetryStatement(S delegate, DbInfo dbInfo) {
- this(delegate, dbInfo, null);
+ OpenTelemetryStatement(S delegate, DbInfo dbInfo, Instrumenter<DbRequest, Void> instrumenter) {
+ this(delegate, dbInfo, null, instrumenter);
}
- OpenTelemetryStatement(S delegate, DbInfo dbInfo, String query) {
+ OpenTelemetryStatement(
+ S delegate, DbInfo dbInfo, String query, Instrumenter<DbRequest, Void> instrumenter) {
this.delegate = delegate;
this.dbInfo = dbInfo;
this.query = query;
+ this.instrumenter = instrumenter;
}
@Override
@@ -282,19 +284,19 @@ public class OpenTelemetryStatement<S extends Statement> implements Statement {
Context parentContext = Context.current();
DbRequest request = DbRequest.create(dbInfo, sql);
- if (!instrumenter().shouldStart(parentContext, request)) {
+ if (!this.instrumenter.shouldStart(parentContext, request)) {
return callable.call();
}
- Context context = instrumenter().start(parentContext, request);
+ Context context = this.instrumenter.start(parentContext, request);
T result;
try (Scope ignored = context.makeCurrent()) {
result = callable.call();
} catch (Throwable t) {
- instrumenter().end(context, request, null, t);
+ this.instrumenter.end(context, request, null, t);
throw t;
}
- instrumenter().end(context, request, null, null);
+ this.instrumenter.end(context, request, null, null);
return result;
}

MODIFY
instrumentation/jdbc/library/src/test/groovy/io/opentelemetry/instrumentation/jdbc/OpenTelemetryConnectionTest.groovy
instrumentation/jdbc/library/src/test/groovy/io/opentelemetry/instrumentation/jdbc/OpenTelemetryConnectionTest.groovy
package io.opentelemetry.instrumentation.jdbc
+
+import io.opentelemetry.api.OpenTelemetry
import io.opentelemetry.api.trace.SpanKind
-import io.opentelemetry.instrumentation.jdbc.internal.dbinfo.DbInfo
+import io.opentelemetry.context.propagation.ContextPropagators
import io.opentelemetry.instrumentation.jdbc.internal.OpenTelemetryCallableStatement
import io.opentelemetry.instrumentation.jdbc.internal.OpenTelemetryConnection
import io.opentelemetry.instrumentation.jdbc.internal.OpenTelemetryPreparedStatement
import io.opentelemetry.instrumentation.jdbc.internal.OpenTelemetryStatement
+import io.opentelemetry.instrumentation.jdbc.internal.dbinfo.DbInfo
import io.opentelemetry.instrumentation.test.InstrumentationSpecification
import io.opentelemetry.instrumentation.test.LibraryTestTrait
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import static io.opentelemetry.api.trace.SpanKind.CLIENT
+import static io.opentelemetry.instrumentation.jdbc.internal.JdbcInstrumenterFactory.createStatementInstrumenter
class OpenTelemetryConnectionTest extends InstrumentationSpecification implements LibraryTestTrait {
def "verify create statement"() {
setup:
+ def instr = createStatementInstrumenter(openTelemetry)
def dbInfo = getDbInfo()
- def connection = new OpenTelemetryConnection(new TestConnection(), dbInfo)
+ def connection = new OpenTelemetryConnection(new TestConnection(), dbInfo, instr)
String query = "SELECT * FROM users"
def statement = connection.createStatement()
runWithSpan("parent") {
@@ -63,18 +68,22 @@ class OpenTelemetryConnectionTest extends InstrumentationSpecification implement
def "verify create statement returns otel wrapper"() {
when:
- def connection = new OpenTelemetryConnection(new TestConnection(), DbInfo.DEFAULT)
+ def ot = OpenTelemetry.propagating(ContextPropagators.noop())
+ def instr = createStatementInstrumenter(ot)
+ def connection = new OpenTelemetryConnection(new TestConnection(), DbInfo.DEFAULT, instr)
then:
connection.createStatement().class == OpenTelemetryStatement
connection.createStatement(0, 0).class == OpenTelemetryStatement
connection.createStatement(0, 0, 0).class == OpenTelemetryStatement
+ connection.createStatement().instrumenter == instr
}
def "verify prepare statement"() {
setup:
+ def instr = createStatementInstrumenter(openTelemetry)
def dbInfo = getDbInfo()
- def connection = new OpenTelemetryConnection(new TestConnection(), dbInfo)
+ def connection = new OpenTelemetryConnection(new TestConnection(), dbInfo, instr)
String query = "SELECT * FROM users"
def statement = connection.prepareStatement(query)
runWithSpan("parent") {
@@ -115,21 +124,26 @@ class OpenTelemetryConnectionTest extends InstrumentationSpecification implement
def "verify prepare statement returns otel wrapper"() {
when:
- def connection = new OpenTelemetryConnection(new TestConnection(), DbInfo.DEFAULT)
+ def ot = OpenTelemetry.propagating(ContextPropagators.noop())
+ def instr = createStatementInstrumenter(ot)
+ def connection = new OpenTelemetryConnection(new TestConnection(), DbInfo.DEFAULT, instr)
+ String query = "SELECT * FROM users"
then:
- connection.prepareStatement("SELECT * FROM users").class == OpenTelemetryPreparedStatement
- connection.prepareStatement("SELECT * FROM users", [0] as int[]).class == OpenTelemetryPreparedStatement
- connection.prepareStatement("SELECT * FROM users", ["id"] as String[]).class == OpenTelemetryPreparedStatement
- connection.prepareStatement("SELECT * FROM users", 0).class == OpenTelemetryPreparedStatement
- connection.prepareStatement("SELECT * FROM users", 0, 0).class == OpenTelemetryPreparedStatement
- connection.prepareStatement("SELECT * FROM users", 0, 0, 0).class == OpenTelemetryPreparedStatement
+ connection.prepareStatement(query).class == OpenTelemetryPreparedStatement
+ connection.prepareStatement(query, [0] as int[]).class == OpenTelemetryPreparedStatement
+ connection.prepareStatement(query, ["id"] as String[]).class == OpenTelemetryPreparedStatement
+ connection.prepareStatement(query, 0).class == OpenTelemetryPreparedStatement
+ connection.prepareStatement(query, 0, 0).class == OpenTelemetryPreparedStatement
+ connection.prepareStatement(query, 0, 0, 0).class == OpenTelemetryPreparedStatement
+ connection.prepareStatement(query).instrumenter == instr
}
def "verify prepare call"() {
setup:
+ def instr = createStatementInstrumenter(openTelemetry)
def dbInfo = getDbInfo()
- def connection = new OpenTelemetryConnection(new TestConnection(), dbInfo)
+ def connection = new OpenTelemetryConnection(new TestConnection(), dbInfo, instr)
String query = "SELECT * FROM users"
def statement = connection.prepareCall(query)
runWithSpan("parent") {
@@ -170,12 +184,16 @@ class OpenTelemetryConnectionTest extends InstrumentationSpecification implement
def "verify prepare call returns otel wrapper"() {
when:
- def connection = new OpenTelemetryConnection(new TestConnection(), DbInfo.DEFAULT)
+ def ot = OpenTelemetry.propagating(ContextPropagators.noop())
+ def instr = createStatementInstrumenter(ot)
+ def connection = new OpenTelemetryConnection(new TestConnection(), DbInfo.DEFAULT, instr)
+ String query = "SELECT * FROM users"
then:
- connection.prepareCall("SELECT * FROM users").class == OpenTelemetryCallableStatement
- connection.prepareCall("SELECT * FROM users", 0, 0).class == OpenTelemetryCallableStatement
- connection.prepareCall("SELECT * FROM users", 0, 0, 0).class == OpenTelemetryCallableStatement
+ connection.prepareCall(query).class == OpenTelemetryCallableStatement
+ connection.prepareCall(query, 0, 0).class == OpenTelemetryCallableStatement
+ connection.prepareCall(query, 0, 0, 0).class == OpenTelemetryCallableStatement
+ connection.prepareCall(query).instrumenter == instr
}
private DbInfo getDbInfo() {

MODIFY
instrumentation/jdbc/library/src/test/groovy/io/opentelemetry/instrumentation/jdbc/datasource/OpenTelemetryDataSourceTest.groovy
instrumentation/jdbc/library/src/test/groovy/io/opentelemetry/instrumentation/jdbc/datasource/OpenTelemetryDataSourceTest.groovy
package io.opentelemetry.instrumentation.jdbc.datasource
+import io.opentelemetry.api.OpenTelemetry
+import io.opentelemetry.context.propagation.ContextPropagators
import io.opentelemetry.instrumentation.jdbc.internal.OpenTelemetryConnection
import spock.lang.Specification
@@ -12,12 +14,14 @@ class OpenTelemetryDataSourceTest extends Specification {
def "verify get connection"() {
when:
- def dataSource = new OpenTelemetryDataSource(new TestDataSource())
+ def ot = OpenTelemetry.propagating(ContextPropagators.noop())
+ def dataSource = new OpenTelemetryDataSource(new TestDataSource(), ot)
def connection = dataSource.getConnection()
then:
connection != null
connection instanceof OpenTelemetryConnection
+ connection.statementInstrumenter != null
when:
def dbInfo = ((OpenTelemetryConnection) connection).dbInfo
@@ -35,12 +39,14 @@ class OpenTelemetryDataSourceTest extends Specification {
def "verify get connection with username and password"() {
when:
- def dataSource = new OpenTelemetryDataSource(new TestDataSource())
+ def ot = OpenTelemetry.propagating(ContextPropagators.noop())
+ def dataSource = new OpenTelemetryDataSource(new TestDataSource(), ot)
def connection = dataSource.getConnection(null, null)
then:
connection != null
connection instanceof OpenTelemetryConnection
+ connection.statementInstrumenter != null
when:
def dbInfo = ((OpenTelemetryConnection) connection).dbInfo
@@ -55,5 +61,4 @@ class OpenTelemetryDataSourceTest extends Specification {
dbInfo.host == "127.0.0.1"
dbInfo.port == 5432
}
-
}

Allow JDBC autoinstrumentation to use a custom OpenTelemetry instance to be more DI (e.g. Spring Boot) friendly (#7697)

Related to issue
https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/7677