From 542782912682b6c487fd550f920ee52e667c0913 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Wed, 29 Oct 2025 10:44:53 +0200 Subject: [PATCH 1/2] Make sqlcommenter more configurable --- .../semconv/db/internal/SqlCommenter.java | 51 +++++++ .../db/internal/SqlCommenterBuilder.java | 89 +++++++++++++ .../semconv/db/internal/SqlCommenterUtil.java | 73 +++++------ .../db/internal/SqlCommenterUtilTest.java | 24 ++-- .../jdbc/javaagent/build.gradle.kts | 8 +- .../jdbc/ConnectionInstrumentation.java | 5 +- .../instrumentation/jdbc/JdbcSingletons.java | 38 ++++-- .../jdbc/StatementInstrumentation.java | 4 +- .../jdbc/OpenTelemetryDriver.java | 17 ++- .../jdbc/datasource/JdbcTelemetry.java | 9 +- .../jdbc/datasource/JdbcTelemetryBuilder.java | 9 +- .../datasource/OpenTelemetryDataSource.java | 15 ++- .../datasource/internal/Experimental.java | 49 +++++-- .../OpenTelemetryCallableStatement.java | 12 +- .../internal/OpenTelemetryConnection.java | 124 ++++++------------ .../OpenTelemetryPreparedStatement.java | 5 +- .../jdbc/internal/OpenTelemetryStatement.java | 14 +- .../internal/OpenTelemetryConnectionTest.java | 3 +- .../r2dbc/v1_0/R2dbcSingletons.java | 5 + .../r2dbc/v1_0/R2dbcTelemetry.java | 11 +- .../r2dbc/v1_0/R2dbcTelemetryBuilder.java | 9 +- .../r2dbc/v1_0/internal/Experimental.java | 60 +++++++-- .../v1_0/internal/R2dbcSqlCommenterUtil.java | 19 ++- .../sqlcommenter/SqlCommenterCustomizer.java | 22 ++++ .../SqlCommenterCustomizerHolder.java | 33 +++++ .../javaagent/tooling/AgentInstaller.java | 15 +++ testing/agent-exporter/build.gradle.kts | 1 + .../TestAgentSqlCommenterCustomizer.java | 21 +++ 28 files changed, 530 insertions(+), 215 deletions(-) create mode 100644 instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenter.java create mode 100644 instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenterBuilder.java create mode 100644 javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/bootstrap/internal/sqlcommenter/SqlCommenterCustomizer.java create mode 100644 javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/bootstrap/internal/sqlcommenter/SqlCommenterCustomizerHolder.java create mode 100644 testing/agent-exporter/src/main/java/io/opentelemetry/javaagent/testing/sqlcommenter/TestAgentSqlCommenterCustomizer.java diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenter.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenter.java new file mode 100644 index 000000000000..5594530326bf --- /dev/null +++ b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenter.java @@ -0,0 +1,51 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.api.incubator.semconv.db.internal; + +import io.opentelemetry.context.propagation.TextMapPropagator; +import java.util.function.BiFunction; +import java.util.function.Predicate; + +/** + * This class is internal and experimental. Its APIs are unstable and can change at any time. Its + * APIs (or a version of them) may be promoted to the public stable API in the future, but no + * guarantees are made. + */ +public final class SqlCommenter { + private final boolean enabled; + private final BiFunction propagator; + private final Predicate prepend; + + SqlCommenter( + boolean enabled, + BiFunction propagator, + Predicate prepend) { + this.enabled = enabled; + this.propagator = propagator; + this.prepend = prepend; + } + + public static SqlCommenterBuilder builder() { + return new SqlCommenterBuilder(); + } + + public static SqlCommenter noop() { + return builder().build(); + } + + public String processQuery(Object connection, String sql, boolean safe) { + if (!enabled) { + return sql; + } + + return SqlCommenterUtil.processQuery( + sql, propagator.apply(connection, safe), prepend.test(connection)); + } + + public boolean isEnabled() { + return enabled; + } +} diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenterBuilder.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenterBuilder.java new file mode 100644 index 000000000000..907fc76937ad --- /dev/null +++ b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenterBuilder.java @@ -0,0 +1,89 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.api.incubator.semconv.db.internal; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.propagation.TextMapPropagator; +import java.sql.Connection; +import java.sql.Statement; +import java.util.function.BiFunction; +import java.util.function.Predicate; + +/** + * This class is internal and experimental. Its APIs are unstable and can change at any time. Its + * APIs (or a version of them) may be promoted to the public stable API in the future, but no + * guarantees are made. + */ +public final class SqlCommenterBuilder { + private boolean enabled; + private BiFunction propagator = + (unused1, unused2) -> W3CTraceContextPropagator.getInstance(); + private Predicate prepend = unused -> false; + + SqlCommenterBuilder() {} + + /** Enable adding sqlcommenter comments to sql queries. Default is disabled. */ + @CanIgnoreReturnValue + public SqlCommenterBuilder setEnabled(boolean enabled) { + this.enabled = enabled; + return this; + } + + /** + * Prepend the sqlcommenter comment to the query instead of appending it. Default is to append. + */ + @CanIgnoreReturnValue + public SqlCommenterBuilder setPrepend(boolean prepend) { + this.prepend = unused -> prepend; + return this; + } + + /** + * Prepend the sqlcommenter comment to the query instead of appending it. Default is to append. + * + * @param prepend a predicate that receives the database connection. Connection may be a jdbc + * Connection, R2DBC Connection, or any other connection type used by the data access + * framework performing the operation. + */ + @CanIgnoreReturnValue + public SqlCommenterBuilder setPrepend(Predicate prepend) { + this.prepend = prepend; + return this; + } + + /** + * Set the propagator used to inject tracing context into sql comments. Default is W3C Trace + * Context propagator. + */ + @CanIgnoreReturnValue + public SqlCommenterBuilder setPropagator(TextMapPropagator propagator) { + this.propagator = (unused1, unused2) -> propagator; + return this; + } + + /** + * Set the propagator used to inject tracing context into sql comments. Default is W3C Trace + * Context propagator. + * + * @param propagator a function that receives the database connection and whether the query is + * executed only once or could be reused. Connection may be a jdbc Connection, R2DBC + * Connection, or any other connection type used by the data access framework performing the + * operation. If the second argument to the function is true, the query is executed only once + * (e.g. JDBC {@link Statement#execute(String)}). If false, the query could be reused (e.g. + * JDBC {@link Connection#prepareStatement(String)}). + */ + @CanIgnoreReturnValue + public SqlCommenterBuilder setPropagator( + BiFunction propagator) { + this.propagator = propagator; + return this; + } + + public SqlCommenter build() { + return new SqlCommenter(enabled, propagator, prepend); + } +} diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenterUtil.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenterUtil.java index a1f510d544bb..0f795414d0ef 100644 --- a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenterUtil.java +++ b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenterUtil.java @@ -6,25 +6,22 @@ package io.opentelemetry.instrumentation.api.incubator.semconv.db.internal; import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; import io.opentelemetry.context.Context; +import io.opentelemetry.context.propagation.TextMapPropagator; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; -import javax.annotation.Nullable; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; -/** - * This class is internal and experimental. Its APIs are unstable and can change at any time. Its - * APIs (or a version of them) may be promoted to the public stable API in the future, but no - * guarantees are made. - */ -public final class SqlCommenterUtil { +final class SqlCommenterUtil { /** * Append comment containing tracing information at the end of the query. See sqlcommenter for the description of the * algorithm. */ - public static String processQuery(String query) { + public static String processQuery(String query, TextMapPropagator propagator, boolean prepend) { if (!Span.current().getSpanContext().isValid()) { return query; } @@ -33,38 +30,41 @@ public static String processQuery(String query) { return query; } - class State { - @Nullable String traceparent; - @Nullable String tracestate; - } + Map state = new LinkedHashMap<>(); + propagator.inject( + Context.current(), + state, + (carrier, key, value) -> { + if (carrier == null) { + return; + } + carrier.put(key, value); + }); - State state = new State(); + if (state.isEmpty()) { + return query; + } - W3CTraceContextPropagator.getInstance() - .inject( - Context.current(), - state, - (carrier, key, value) -> { - if (carrier == null) { - return; - } - if ("traceparent".equals(key)) { - carrier.traceparent = value; - } else if ("tracestate".equals(key)) { - carrier.tracestate = value; - } - }); + StringBuilder stringBuilder = new StringBuilder("/*"); try { - // we know that the traceparent doesn't contain anything that needs to be encoded - query += " /*traceparent='" + state.traceparent + "'"; - if (state.tracestate != null) { - query += ", tracestate=" + serialize(state.tracestate); + for (Iterator> iterator = state.entrySet().iterator(); + iterator.hasNext(); ) { + Map.Entry entry = iterator.next(); + stringBuilder + .append(serialize(entry.getKey())) + .append("='") + .append(serialize(entry.getValue())) + .append("'"); + if (iterator.hasNext()) { + stringBuilder.append(", "); + } } - query += "*/"; } catch (UnsupportedEncodingException exception) { // this exception should never happen as UTF-8 encoding is always available } - return query; + stringBuilder.append("*/"); + + return prepend ? stringBuilder + " " + query : query + " " + stringBuilder; } private static boolean containsSqlComment(String query) { @@ -72,12 +72,11 @@ private static boolean containsSqlComment(String query) { } private static String serialize(String value) throws UnsupportedEncodingException { - // specification requires percent encoding, here we use the java build in url encoder that + // specification requires percent encoding, here we use the java built in url encoder that // encodes space as '+' instead of '%20' as required - String result = URLEncoder.encode(value, "UTF-8").replace("+", "%20"); // specification requires escaping ' with a backslash, we skip this because URLEncoder already // encodes the ' - return "'" + result + "'"; + return URLEncoder.encode(value, "UTF-8").replace("+", "%20"); } private SqlCommenterUtil() {} diff --git a/instrumentation-api-incubator/src/test/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenterUtilTest.java b/instrumentation-api-incubator/src/test/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenterUtilTest.java index 45aecad5cd2a..101c385f9fd9 100644 --- a/instrumentation-api-incubator/src/test/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenterUtilTest.java +++ b/instrumentation-api-incubator/src/test/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenterUtilTest.java @@ -11,12 +11,16 @@ import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.api.trace.TraceFlags; import io.opentelemetry.api.trace.TraceState; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; +import io.opentelemetry.context.propagation.TextMapPropagator; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +import org.junitpioneer.jupiter.cartesian.CartesianTest; class SqlCommenterUtilTest { + private static final TextMapPropagator propagator = W3CTraceContextPropagator.getInstance(); @ParameterizedTest @ValueSource(strings = {"SELECT /**/ 1", "SELECT 1 --", "SELECT '/*'"}) @@ -32,13 +36,14 @@ void skipQueriesWithComments(String query) { TraceState.getDefault()))); try (Scope ignore = parent.makeCurrent()) { - assertThat(SqlCommenterUtil.processQuery(query)).isEqualTo(query); + assertThat(SqlCommenterUtil.processQuery(query, propagator, false)).isEqualTo(query); } } - @ParameterizedTest - @ValueSource(booleans = {true, false}) - void sqlCommenter(boolean hasTraceState) { + @CartesianTest + void sqlCommenter( + @CartesianTest.Values(booleans = {true, false}) boolean hasTraceState, + @CartesianTest.Values(booleans = {true, false}) boolean prepend) { TraceState state = hasTraceState ? TraceState.builder().put("test", "test'").build() : TraceState.getDefault(); Context parent = @@ -52,11 +57,12 @@ void sqlCommenter(boolean hasTraceState) { state))); try (Scope ignore = parent.makeCurrent()) { - assertThat(SqlCommenterUtil.processQuery("SELECT 1")) - .isEqualTo( - hasTraceState - ? "SELECT 1 /*traceparent='00-ff01020304050600ff0a0b0c0d0e0f00-090a0b0c0d0e0f00-01', tracestate='test%3Dtest%27'*/" - : "SELECT 1 /*traceparent='00-ff01020304050600ff0a0b0c0d0e0f00-090a0b0c0d0e0f00-01'*/"); + String fragment = + hasTraceState + ? "/*traceparent='00-ff01020304050600ff0a0b0c0d0e0f00-090a0b0c0d0e0f00-01', tracestate='test%3Dtest%27'*/" + : "/*traceparent='00-ff01020304050600ff0a0b0c0d0e0f00-090a0b0c0d0e0f00-01'*/"; + assertThat(SqlCommenterUtil.processQuery("SELECT 1", propagator, prepend)) + .isEqualTo(prepend ? fragment + " SELECT 1" : "SELECT 1 " + fragment); } } } diff --git a/instrumentation/jdbc/javaagent/build.gradle.kts b/instrumentation/jdbc/javaagent/build.gradle.kts index 7ef7022a6300..27bc326563d3 100644 --- a/instrumentation/jdbc/javaagent/build.gradle.kts +++ b/instrumentation/jdbc/javaagent/build.gradle.kts @@ -63,11 +63,17 @@ tasks { } val testSqlCommenter by registering(Test::class) { + testClassesDirs = sourceSets.test.get().output.classesDirs + classpath = sourceSets.test.get().runtimeClasspath + filter { includeTestsMatching("SqlCommenterTest") } include("**/SqlCommenterTest.*") - jvmArgs("-Dotel.instrumentation.jdbc.experimental.sqlcommenter.enabled=true") + // This property is read in TestAgentSqlCommenterCustomizer, we use it instead of the + // otel.instrumentation.jdbc.experimental.sqlcommenter.enabled to test that the + // SqlCommenterCustomizer is run. + jvmArgs("-Dotel.testing.sqlcommenter.enabled=true") } val testStableSemconv by registering(Test::class) { diff --git a/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/ConnectionInstrumentation.java b/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/ConnectionInstrumentation.java index ca3e19f5e1d3..caa87a25d35a 100644 --- a/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/ConnectionInstrumentation.java +++ b/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/ConnectionInstrumentation.java @@ -99,11 +99,12 @@ public Context storeInContext(Context context) { @AssignReturned.ToArguments(@ToArgument(value = 0, index = 0)) @Advice.OnMethodEnter(suppress = Throwable.class) - public static Object[] processSql(@Advice.Argument(0) String sql) { + public static Object[] processSql( + @Advice.This Connection connection, @Advice.Argument(0) String sql) { Context context = Java8BytecodeBridge.currentContext(); if (PrepareContext.get(context) == null) { // process sql only in the outermost prepare call and save the original sql in context - String processSql = JdbcSingletons.processSql(sql); + String processSql = JdbcSingletons.processSql(connection, sql, true); Scope scope = PrepareContext.init(context, sql).makeCurrent(); return new Object[] {processSql, scope}; } else { diff --git a/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/JdbcSingletons.java b/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/JdbcSingletons.java index 4ecd74a7738d..285a2b25a35f 100644 --- a/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/JdbcSingletons.java +++ b/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/JdbcSingletons.java @@ -8,7 +8,8 @@ import static io.opentelemetry.instrumentation.jdbc.internal.JdbcInstrumenterFactory.createDataSourceInstrumenter; import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenterUtil; +import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenter; +import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenterBuilder; import io.opentelemetry.instrumentation.api.incubator.semconv.net.PeerServiceAttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; @@ -18,8 +19,11 @@ import io.opentelemetry.instrumentation.jdbc.internal.JdbcNetworkAttributesGetter; import io.opentelemetry.javaagent.bootstrap.internal.AgentCommonConfig; import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig; +import io.opentelemetry.javaagent.bootstrap.internal.sqlcommenter.SqlCommenterCustomizerHolder; import io.opentelemetry.javaagent.bootstrap.jdbc.DbInfo; +import java.sql.Connection; import java.sql.SQLException; +import java.sql.Statement; import java.sql.Wrapper; import java.util.Collections; import javax.sql.DataSource; @@ -29,11 +33,7 @@ public final class JdbcSingletons { private static final Instrumenter TRANSACTION_INSTRUMENTER; public static final Instrumenter DATASOURCE_INSTRUMENTER = createDataSourceInstrumenter(GlobalOpenTelemetry.get(), true); - private static final boolean SQLCOMMENTER_ENABLED = - AgentInstrumentationConfig.get() - .getBoolean( - "otel.instrumentation.jdbc.experimental.sqlcommenter.enabled", - AgentCommonConfig.get().isSqlCommenterEnabled()); + private static final SqlCommenter SQL_COMMENTER = configureSqlCommenter(); public static final boolean CAPTURE_QUERY_PARAMETERS; static { @@ -103,8 +103,30 @@ private static boolean isWrapperInternal(T object, Class return false; } - public static String processSql(String sql) { - return SQLCOMMENTER_ENABLED ? SqlCommenterUtil.processQuery(sql) : sql; + private static SqlCommenter configureSqlCommenter() { + SqlCommenterBuilder builder = SqlCommenter.builder(); + builder.setEnabled( + AgentInstrumentationConfig.get() + .getBoolean( + "otel.instrumentation.jdbc.experimental.sqlcommenter.enabled", + AgentCommonConfig.get().isSqlCommenterEnabled())); + SqlCommenterCustomizerHolder.getCustomizer().customize(builder); + return builder.build(); + } + + public static String processSql(Statement statement, String sql, boolean safe) { + Connection connection; + try { + connection = statement.getConnection(); + } catch (SQLException exception) { + // connection was already closed + return sql; + } + return processSql(connection, sql, safe); + } + + public static String processSql(Connection connection, String sql, boolean safe) { + return SQL_COMMENTER.processQuery(connection, sql, safe); } private JdbcSingletons() {} diff --git a/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/StatementInstrumentation.java b/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/StatementInstrumentation.java index d82a1b3abaee..0c057b64c9ea 100644 --- a/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/StatementInstrumentation.java +++ b/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/StatementInstrumentation.java @@ -69,7 +69,7 @@ public static Object[] onEnter( return new Object[] {null, sql}; } - String processedSql = JdbcSingletons.processSql(sql); + String processedSql = JdbcSingletons.processSql(statement, sql, false); return new Object[] { JdbcAdviceScope.startStatement(CallDepth.forClass(Statement.class), sql, statement), processedSql @@ -101,7 +101,7 @@ public static String addBatch( } JdbcData.addStatementBatch(statement, sql); - return JdbcSingletons.processSql(sql); + return JdbcSingletons.processSql(statement, sql, false); } } diff --git a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/OpenTelemetryDriver.java b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/OpenTelemetryDriver.java index 34a96c2caa0f..617da2b99f03 100644 --- a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/OpenTelemetryDriver.java +++ b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/OpenTelemetryDriver.java @@ -23,6 +23,7 @@ import static io.opentelemetry.instrumentation.jdbc.internal.JdbcInstrumenterFactory.INSTRUMENTATION_NAME; import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenter; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.api.internal.ConfigPropertiesUtil; import io.opentelemetry.instrumentation.api.internal.EmbeddedInstrumentationProperties; @@ -62,12 +63,14 @@ public final class OpenTelemetryDriver implements Driver { private static final AtomicBoolean REGISTERED = new AtomicBoolean(); private static final List DRIVER_CANDIDATES = new CopyOnWriteArrayList<>(); - // XXX value proeprty? - private static final boolean sqlCommenterEnabled = - ConfigPropertiesUtil.getBoolean( - "otel.instrumentation.jdbc.experimental.sqlcommenter.enabled", - ConfigPropertiesUtil.getBoolean( - "otel.instrumentation.common.experimental.db-sqlcommenter.enabled", false)); + private static final SqlCommenter sqlCommenter = + SqlCommenter.builder() + .setEnabled( + ConfigPropertiesUtil.getBoolean( + "otel.instrumentation.jdbc.experimental.sqlcommenter.enabled", + ConfigPropertiesUtil.getBoolean( + "otel.instrumentation.common.experimental.db-sqlcommenter.enabled", false))) + .build(); static { try { @@ -263,7 +266,7 @@ public Connection connect(String url, Properties info) throws SQLException { statementInstrumenter, transactionInstrumenter, captureQueryParameters, - sqlCommenterEnabled); + sqlCommenter); } @Override diff --git a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/datasource/JdbcTelemetry.java b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/datasource/JdbcTelemetry.java index 2e60d2521236..09c391d14b63 100644 --- a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/datasource/JdbcTelemetry.java +++ b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/datasource/JdbcTelemetry.java @@ -6,6 +6,7 @@ package io.opentelemetry.instrumentation.jdbc.datasource; import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenter; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.jdbc.internal.DbRequest; import io.opentelemetry.instrumentation.jdbc.internal.dbinfo.DbInfo; @@ -28,19 +29,19 @@ public static JdbcTelemetryBuilder builder(OpenTelemetry openTelemetry) { private final Instrumenter statementInstrumenter; private final Instrumenter transactionInstrumenter; private final boolean captureQueryParameters; - private final boolean sqlCommenterEnabled; + private final SqlCommenter sqlCommenter; JdbcTelemetry( Instrumenter dataSourceInstrumenter, Instrumenter statementInstrumenter, Instrumenter transactionInstrumenter, boolean captureQueryParameters, - boolean sqlCommenterEnabled) { + SqlCommenter sqlCommenter) { this.dataSourceInstrumenter = dataSourceInstrumenter; this.statementInstrumenter = statementInstrumenter; this.transactionInstrumenter = transactionInstrumenter; this.captureQueryParameters = captureQueryParameters; - this.sqlCommenterEnabled = sqlCommenterEnabled; + this.sqlCommenter = sqlCommenter; } public DataSource wrap(DataSource dataSource) { @@ -50,6 +51,6 @@ public DataSource wrap(DataSource dataSource) { this.statementInstrumenter, this.transactionInstrumenter, this.captureQueryParameters, - this.sqlCommenterEnabled); + this.sqlCommenter); } } diff --git a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/datasource/JdbcTelemetryBuilder.java b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/datasource/JdbcTelemetryBuilder.java index c466d1f02a24..4ca2dbd9158c 100644 --- a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/datasource/JdbcTelemetryBuilder.java +++ b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/datasource/JdbcTelemetryBuilder.java @@ -7,6 +7,8 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenter; +import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenterBuilder; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.jdbc.datasource.internal.Experimental; import io.opentelemetry.instrumentation.jdbc.internal.DbRequest; @@ -23,11 +25,10 @@ public final class JdbcTelemetryBuilder { private boolean statementSanitizationEnabled = true; private boolean transactionInstrumenterEnabled = false; private boolean captureQueryParameters = false; - private boolean sqlCommenterEnabled = false; + private final SqlCommenterBuilder sqlCommenterBuilder = SqlCommenter.builder(); static { - Experimental.internalSetEnableSqlCommenter( - (builder, sqlCommenterEnabled) -> builder.sqlCommenterEnabled = sqlCommenterEnabled); + Experimental.internalSetSqlCommenterBuilder(builder -> builder.sqlCommenterBuilder); } JdbcTelemetryBuilder(OpenTelemetry openTelemetry) { @@ -95,6 +96,6 @@ public JdbcTelemetry build() { statementInstrumenter, transactionInstrumenter, captureQueryParameters, - sqlCommenterEnabled); + sqlCommenterBuilder.build()); } } diff --git a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/datasource/OpenTelemetryDataSource.java b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/datasource/OpenTelemetryDataSource.java index 5efb2e0bd67c..7f0c86d9fac9 100644 --- a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/datasource/OpenTelemetryDataSource.java +++ b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/datasource/OpenTelemetryDataSource.java @@ -30,6 +30,7 @@ import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; +import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenter; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.jdbc.internal.DbRequest; import io.opentelemetry.instrumentation.jdbc.internal.OpenTelemetryConnection; @@ -50,7 +51,7 @@ public class OpenTelemetryDataSource implements DataSource, AutoCloseable { private final Instrumenter statementInstrumenter; private final Instrumenter transactionInstrumenter; private final boolean captureQueryParameters; - private final boolean sqlCommenterEnabled; + private final SqlCommenter sqlCommenter; private volatile DbInfo cachedDbInfo; /** @@ -77,7 +78,7 @@ public OpenTelemetryDataSource(DataSource delegate, OpenTelemetry openTelemetry) this.statementInstrumenter = createStatementInstrumenter(openTelemetry); this.transactionInstrumenter = createTransactionInstrumenter(openTelemetry, false); this.captureQueryParameters = false; - this.sqlCommenterEnabled = false; + this.sqlCommenter = SqlCommenter.noop(); } /** @@ -86,7 +87,7 @@ public OpenTelemetryDataSource(DataSource delegate, OpenTelemetry openTelemetry) * @param delegate the DataSource to wrap * @param dataSourceInstrumenter the DataSource Instrumenter to use * @param statementInstrumenter the Statement Instrumenter to use - * @param sqlCommenterEnabled whether to augment sql query with comment containing the tracing + * @param sqlCommenter helper class for augment sql queries with a comment containing the tracing * information */ OpenTelemetryDataSource( @@ -95,13 +96,13 @@ public OpenTelemetryDataSource(DataSource delegate, OpenTelemetry openTelemetry) Instrumenter statementInstrumenter, Instrumenter transactionInstrumenter, boolean captureQueryParameters, - boolean sqlCommenterEnabled) { + SqlCommenter sqlCommenter) { this.delegate = delegate; this.dataSourceInstrumenter = dataSourceInstrumenter; this.statementInstrumenter = statementInstrumenter; this.transactionInstrumenter = transactionInstrumenter; this.captureQueryParameters = captureQueryParameters; - this.sqlCommenterEnabled = sqlCommenterEnabled; + this.sqlCommenter = sqlCommenter; } @Override @@ -114,7 +115,7 @@ public Connection getConnection() throws SQLException { statementInstrumenter, transactionInstrumenter, captureQueryParameters, - sqlCommenterEnabled); + sqlCommenter); } @Override @@ -127,7 +128,7 @@ public Connection getConnection(String username, String password) throws SQLExce statementInstrumenter, transactionInstrumenter, captureQueryParameters, - sqlCommenterEnabled); + sqlCommenter); } @Override diff --git a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/datasource/internal/Experimental.java b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/datasource/internal/Experimental.java index b3fc57f9c9f6..c5f5b08589fe 100644 --- a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/datasource/internal/Experimental.java +++ b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/datasource/internal/Experimental.java @@ -5,8 +5,10 @@ package io.opentelemetry.instrumentation.jdbc.datasource.internal; +import io.opentelemetry.context.propagation.TextMapPropagator; +import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenterBuilder; import io.opentelemetry.instrumentation.jdbc.datasource.JdbcTelemetryBuilder; -import java.util.function.BiConsumer; +import java.util.function.Function; import javax.annotation.Nullable; /** @@ -16,25 +18,56 @@ */ public final class Experimental { - @Nullable private static volatile BiConsumer setEnableSqlCommenter; + @Nullable + private static volatile Function sqlCommenterBuilder; /** * Sets whether to augment sql query with comment containing the tracing information. See sqlcommenter for more info. * *

WARNING: augmenting queries with tracing context will make query texts unique, which may - * have adverse impact on database performance. Consult with database experts before enabling. + * have adverse impact on database performance. Consult with database experts before enabling. If + * this is an issue, consider replacing the default W3C Trace Context propagator with a propagator + * that only adds static values, such as service name. + * + *

WARNING: for prepared statements query is modified when the statement is created, this means + * that the inserted tracing context could be wrong if the prepared statement is reused. Consider + * replacing the default W3C Trace Context propagator with a propagator that only adds static + * values, such as service name. */ public static void setEnableSqlCommenter( JdbcTelemetryBuilder builder, boolean sqlCommenterEnabled) { - if (setEnableSqlCommenter != null) { - setEnableSqlCommenter.accept(builder, sqlCommenterEnabled); + if (sqlCommenterBuilder != null) { + sqlCommenterBuilder.apply(builder).setEnabled(sqlCommenterEnabled); + } + } + + /** + * Set the propagator used to inject tracing context into sql comments. By default, W3C Trace + * Context propagator is used. + */ + public static void setSqlCommenterPropagator( + JdbcTelemetryBuilder builder, TextMapPropagator propagator) { + if (sqlCommenterBuilder != null) { + sqlCommenterBuilder.apply(builder).setPropagator(propagator); + } + } + + /** + * Sets whether to prepend the sql comment to the query instead of appending it. Default is to + * append. This is useful for preserving the comment on databases that truncate long queries in + * their diagnostic output. + */ + public static void setSqlCommenterPrepend( + JdbcTelemetryBuilder builder, boolean sqlCommenterPrepend) { + if (sqlCommenterBuilder != null) { + sqlCommenterBuilder.apply(builder).setPrepend(sqlCommenterPrepend); } } - public static void internalSetEnableSqlCommenter( - BiConsumer setEnableSqlCommenter) { - Experimental.setEnableSqlCommenter = setEnableSqlCommenter; + public static void internalSetSqlCommenterBuilder( + Function sqlCommenterBuilder) { + Experimental.sqlCommenterBuilder = sqlCommenterBuilder; } private Experimental() {} diff --git a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryCallableStatement.java b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryCallableStatement.java index 17761f62504a..9150c42bf132 100644 --- a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryCallableStatement.java +++ b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryCallableStatement.java @@ -20,6 +20,7 @@ package io.opentelemetry.instrumentation.jdbc.internal; +import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenter; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.jdbc.internal.dbinfo.DbInfo; import java.io.InputStream; @@ -53,15 +54,8 @@ public OpenTelemetryCallableStatement( String query, Instrumenter instrumenter, boolean captureQueryParameters, - boolean sqlCommenterEnabled) { - super( - delegate, - connection, - dbInfo, - query, - instrumenter, - captureQueryParameters, - sqlCommenterEnabled); + SqlCommenter sqlCommenter) { + super(delegate, connection, dbInfo, query, instrumenter, captureQueryParameters, sqlCommenter); } @Override diff --git a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryConnection.java b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryConnection.java index 226bcf0bcda2..a84253bbd2ff 100644 --- a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryConnection.java +++ b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryConnection.java @@ -22,7 +22,7 @@ import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; -import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenterUtil; +import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenter; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.jdbc.internal.dbinfo.DbInfo; import java.sql.Array; @@ -57,7 +57,7 @@ public class OpenTelemetryConnection implements Connection { protected final Instrumenter statementInstrumenter; protected final Instrumenter transactionInstrumenter; private final boolean captureQueryParameters; - protected final boolean sqlCommenterEnabled; + protected final SqlCommenter sqlCommenter; protected OpenTelemetryConnection( Connection delegate, @@ -65,13 +65,13 @@ protected OpenTelemetryConnection( Instrumenter statementInstrumenter, Instrumenter transactionInstrumenter, boolean captureQueryParameters, - boolean sqlCommenterEnabled) { + SqlCommenter sqlCommenter) { this.delegate = delegate; this.dbInfo = dbInfo; this.statementInstrumenter = statementInstrumenter; this.transactionInstrumenter = transactionInstrumenter; this.captureQueryParameters = captureQueryParameters; - this.sqlCommenterEnabled = sqlCommenterEnabled; + this.sqlCommenter = sqlCommenter; } // visible for testing @@ -90,7 +90,7 @@ public static Connection create( Instrumenter statementInstrumenter, Instrumenter transactionInstrumenter, boolean captureQueryParameters, - boolean sqlCommenterEnabled) { + SqlCommenter sqlCommenter) { if (hasJdbc43) { return new OpenTelemetryConnectionJdbc43( delegate, @@ -98,7 +98,7 @@ public static Connection create( statementInstrumenter, transactionInstrumenter, captureQueryParameters, - sqlCommenterEnabled); + sqlCommenter); } return new OpenTelemetryConnection( delegate, @@ -106,26 +106,39 @@ public static Connection create( statementInstrumenter, transactionInstrumenter, captureQueryParameters, - sqlCommenterEnabled); + sqlCommenter); } private String processQuery(String sql) { - return sqlCommenterEnabled ? SqlCommenterUtil.processQuery(sql) : sql; + return sqlCommenter.processQuery(delegate, sql, false); + } + + private Statement wrapStatement(Statement statement) { + return new OpenTelemetryStatement<>( + statement, this, dbInfo, statementInstrumenter, sqlCommenter); + } + + private PreparedStatement wrapPreparedStatement(PreparedStatement statement, String sql) { + return new OpenTelemetryPreparedStatement<>( + statement, this, dbInfo, sql, statementInstrumenter, captureQueryParameters, sqlCommenter); + } + + private CallableStatement wrapCallableStatement(CallableStatement statement, String sql) { + return new OpenTelemetryCallableStatement<>( + statement, this, dbInfo, sql, statementInstrumenter, captureQueryParameters, sqlCommenter); } @Override public Statement createStatement() throws SQLException { Statement statement = delegate.createStatement(); - return new OpenTelemetryStatement<>( - statement, this, dbInfo, statementInstrumenter, sqlCommenterEnabled); + return wrapStatement(statement); } @Override public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { Statement statement = delegate.createStatement(resultSetType, resultSetConcurrency); - return new OpenTelemetryStatement<>( - statement, this, dbInfo, statementInstrumenter, sqlCommenterEnabled); + return wrapStatement(statement); } @Override @@ -133,22 +146,14 @@ public Statement createStatement( int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { Statement statement = delegate.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); - return new OpenTelemetryStatement<>( - statement, this, dbInfo, statementInstrumenter, sqlCommenterEnabled); + return wrapStatement(statement); } @Override public PreparedStatement prepareStatement(String sql) throws SQLException { String processedSql = processQuery(sql); PreparedStatement statement = delegate.prepareStatement(processedSql); - return new OpenTelemetryPreparedStatement<>( - statement, - this, - dbInfo, - sql, - statementInstrumenter, - captureQueryParameters, - sqlCommenterEnabled); + return wrapPreparedStatement(statement, sql); } @Override @@ -157,14 +162,7 @@ public PreparedStatement prepareStatement(String sql, int resultSetType, int res String processedSql = processQuery(sql); PreparedStatement statement = delegate.prepareStatement(processedSql, resultSetType, resultSetConcurrency); - return new OpenTelemetryPreparedStatement<>( - statement, - this, - dbInfo, - sql, - statementInstrumenter, - captureQueryParameters, - sqlCommenterEnabled); + return wrapPreparedStatement(statement, sql); } @Override @@ -175,70 +173,35 @@ public PreparedStatement prepareStatement( PreparedStatement statement = delegate.prepareStatement( processedSql, resultSetType, resultSetConcurrency, resultSetHoldability); - return new OpenTelemetryPreparedStatement<>( - statement, - this, - dbInfo, - sql, - statementInstrumenter, - captureQueryParameters, - sqlCommenterEnabled); + return wrapPreparedStatement(statement, sql); } @Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { String processedSql = processQuery(sql); PreparedStatement statement = delegate.prepareStatement(processedSql, autoGeneratedKeys); - return new OpenTelemetryPreparedStatement<>( - statement, - this, - dbInfo, - sql, - statementInstrumenter, - captureQueryParameters, - sqlCommenterEnabled); + return wrapPreparedStatement(statement, sql); } @Override public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { String processedSql = processQuery(sql); PreparedStatement statement = delegate.prepareStatement(processedSql, columnIndexes); - return new OpenTelemetryPreparedStatement<>( - statement, - this, - dbInfo, - sql, - statementInstrumenter, - captureQueryParameters, - sqlCommenterEnabled); + return wrapPreparedStatement(statement, sql); } @Override public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { String processedSql = processQuery(sql); PreparedStatement statement = delegate.prepareStatement(processedSql, columnNames); - return new OpenTelemetryPreparedStatement<>( - statement, - this, - dbInfo, - sql, - statementInstrumenter, - captureQueryParameters, - sqlCommenterEnabled); + return wrapPreparedStatement(statement, sql); } @Override public CallableStatement prepareCall(String sql) throws SQLException { String processedSql = processQuery(sql); CallableStatement statement = delegate.prepareCall(processedSql); - return new OpenTelemetryCallableStatement<>( - statement, - this, - dbInfo, - sql, - statementInstrumenter, - captureQueryParameters, - sqlCommenterEnabled); + return wrapCallableStatement(statement, sql); } @Override @@ -247,14 +210,7 @@ public CallableStatement prepareCall(String sql, int resultSetType, int resultSe String processedSql = processQuery(sql); CallableStatement statement = delegate.prepareCall(processedSql, resultSetType, resultSetConcurrency); - return new OpenTelemetryCallableStatement<>( - statement, - this, - dbInfo, - sql, - statementInstrumenter, - captureQueryParameters, - sqlCommenterEnabled); + return wrapCallableStatement(statement, sql); } @Override @@ -266,13 +222,7 @@ public CallableStatement prepareCall( delegate.prepareCall( processedSql, resultSetType, resultSetConcurrency, resultSetHoldability); return new OpenTelemetryCallableStatement<>( - statement, - this, - dbInfo, - sql, - statementInstrumenter, - captureQueryParameters, - sqlCommenterEnabled); + statement, this, dbInfo, sql, statementInstrumenter, captureQueryParameters, sqlCommenter); } @Override @@ -502,14 +452,14 @@ static class OpenTelemetryConnectionJdbc43 extends OpenTelemetryConnection { Instrumenter statementInstrumenter, Instrumenter transactionInstrumenter, boolean captureQueryParameters, - boolean sqlCommenterEnabled) { + SqlCommenter sqlCommenter) { super( delegate, dbInfo, statementInstrumenter, transactionInstrumenter, captureQueryParameters, - sqlCommenterEnabled); + sqlCommenter); } @SuppressWarnings("Since15") diff --git a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryPreparedStatement.java b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryPreparedStatement.java index fc3ca1b2399c..a8a233d1346d 100644 --- a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryPreparedStatement.java +++ b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryPreparedStatement.java @@ -20,6 +20,7 @@ package io.opentelemetry.instrumentation.jdbc.internal; +import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenter; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.jdbc.internal.dbinfo.DbInfo; import java.io.InputStream; @@ -59,8 +60,8 @@ public OpenTelemetryPreparedStatement( String query, Instrumenter instrumenter, boolean captureQueryParameters, - boolean sqlCommenterEnabled) { - super(delegate, connection, dbInfo, query, instrumenter, sqlCommenterEnabled); + SqlCommenter sqlCommenter) { + super(delegate, connection, dbInfo, query, instrumenter, sqlCommenter); this.captureQueryParameters = captureQueryParameters; this.parameters = new HashMap<>(); } diff --git a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryStatement.java b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryStatement.java index 56551fd90b81..3f5711b81eb0 100644 --- a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryStatement.java +++ b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryStatement.java @@ -22,7 +22,7 @@ import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; -import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenterUtil; +import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenter; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.jdbc.internal.dbinfo.DbInfo; import java.sql.Connection; @@ -41,7 +41,7 @@ class OpenTelemetryStatement implements Statement { protected final DbInfo dbInfo; protected final String query; protected final Instrumenter instrumenter; - protected final boolean sqlCommenterEnabled; + protected final SqlCommenter sqlCommenter; private final List batchCommands = new ArrayList<>(); protected long batchSize; @@ -51,8 +51,8 @@ class OpenTelemetryStatement implements Statement { OpenTelemetryConnection connection, DbInfo dbInfo, Instrumenter instrumenter, - boolean sqlCommenterEnabled) { - this(delegate, connection, dbInfo, null, instrumenter, sqlCommenterEnabled); + SqlCommenter sqlCommenter) { + this(delegate, connection, dbInfo, null, instrumenter, sqlCommenter); } OpenTelemetryStatement( @@ -61,17 +61,17 @@ class OpenTelemetryStatement implements Statement { DbInfo dbInfo, String query, Instrumenter instrumenter, - boolean sqlCommenterEnabled) { + SqlCommenter sqlCommenter) { this.delegate = delegate; this.connection = connection; this.dbInfo = dbInfo; this.query = query; this.instrumenter = instrumenter; - this.sqlCommenterEnabled = sqlCommenterEnabled; + this.sqlCommenter = sqlCommenter; } private String processQuery(String sql) { - return sqlCommenterEnabled ? SqlCommenterUtil.processQuery(sql) : sql; + return sqlCommenter.processQuery(connection.delegate, sql, false); } @Override diff --git a/instrumentation/jdbc/library/src/test/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryConnectionTest.java b/instrumentation/jdbc/library/src/test/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryConnectionTest.java index 260f23077016..d3d8e26a6e28 100644 --- a/instrumentation/jdbc/library/src/test/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryConnectionTest.java +++ b/instrumentation/jdbc/library/src/test/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryConnectionTest.java @@ -11,6 +11,7 @@ import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenter; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.jdbc.TestConnection; import io.opentelemetry.instrumentation.jdbc.internal.dbinfo.DbInfo; @@ -123,6 +124,6 @@ private static OpenTelemetryConnection getConnection(OpenTelemetry openTelemetry statementInstrumenter, transactionInstrumenter, false, - false); + SqlCommenter.noop()); } } diff --git a/instrumentation/r2dbc-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/r2dbc/v1_0/R2dbcSingletons.java b/instrumentation/r2dbc-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/r2dbc/v1_0/R2dbcSingletons.java index b443d2eded13..a0b16c4e900f 100644 --- a/instrumentation/r2dbc-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/r2dbc/v1_0/R2dbcSingletons.java +++ b/instrumentation/r2dbc-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/r2dbc/v1_0/R2dbcSingletons.java @@ -13,6 +13,7 @@ import io.opentelemetry.instrumentation.r2dbc.v1_0.internal.shaded.internal.R2dbcNetAttributesGetter; import io.opentelemetry.javaagent.bootstrap.internal.AgentCommonConfig; import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig; +import io.opentelemetry.javaagent.bootstrap.internal.sqlcommenter.SqlCommenterCustomizerHolder; public final class R2dbcSingletons { @@ -36,6 +37,10 @@ public final class R2dbcSingletons { .getBoolean( "otel.instrumentation.r2dbc.experimental.sqlcommenter.enabled", AgentCommonConfig.get().isSqlCommenterEnabled())); + Experimental.customizeSqlCommenter( + builder, + sqlCommenterBuilder -> + SqlCommenterCustomizerHolder.getCustomizer().customize(sqlCommenterBuilder)); TELEMETRY = builder.build(); } diff --git a/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/R2dbcTelemetry.java b/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/R2dbcTelemetry.java index b1609037f0d5..3230f0284f90 100644 --- a/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/R2dbcTelemetry.java +++ b/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/R2dbcTelemetry.java @@ -6,6 +6,7 @@ package io.opentelemetry.instrumentation.r2dbc.v1_0; import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenter; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.r2dbc.v1_0.internal.DbExecution; import io.opentelemetry.instrumentation.r2dbc.v1_0.internal.R2dbcSqlCommenterUtil; @@ -31,18 +32,18 @@ public static R2dbcTelemetryBuilder builder(OpenTelemetry openTelemetry) { } private final Instrumenter instrumenter; - private final boolean sqlCommenterEnabled; + private final SqlCommenter sqlCommenter; - R2dbcTelemetry(Instrumenter instrumenter, boolean sqlCommenterEnabled) { + R2dbcTelemetry(Instrumenter instrumenter, SqlCommenter sqlCommenter) { this.instrumenter = instrumenter; - this.sqlCommenterEnabled = sqlCommenterEnabled; + this.sqlCommenter = sqlCommenter; } public ConnectionFactory wrapConnectionFactory( ConnectionFactory originalFactory, ConnectionFactoryOptions factoryOptions) { ProxyConfig proxyConfig = new ProxyConfig(); - if (sqlCommenterEnabled) { - R2dbcSqlCommenterUtil.configure(proxyConfig); + if (sqlCommenter.isEnabled()) { + R2dbcSqlCommenterUtil.configure(proxyConfig, sqlCommenter); } proxyConfig.addListener(new TraceProxyListener(instrumenter, factoryOptions)); return ProxyConnectionFactory.builder(originalFactory, proxyConfig).build(); diff --git a/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/R2dbcTelemetryBuilder.java b/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/R2dbcTelemetryBuilder.java index e98fb5e48d9b..d0d6b46367ae 100644 --- a/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/R2dbcTelemetryBuilder.java +++ b/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/R2dbcTelemetryBuilder.java @@ -7,6 +7,8 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenter; +import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenterBuilder; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; import io.opentelemetry.instrumentation.r2dbc.v1_0.internal.DbExecution; @@ -22,11 +24,10 @@ public final class R2dbcTelemetryBuilder { private boolean statementSanitizationEnabled = true; private UnaryOperator> spanNameExtractorTransformer = UnaryOperator.identity(); - private boolean sqlCommenterEnabled; + private final SqlCommenterBuilder sqlCommenterBuilder = SqlCommenter.builder(); static { - Experimental.internalSetEnableSqlCommenter( - (builder, sqlCommenterEnabled) -> builder.sqlCommenterEnabled = sqlCommenterEnabled); + Experimental.internalSetSqlCommenterBuilder(builder -> builder.sqlCommenterBuilder); } R2dbcTelemetryBuilder(OpenTelemetry openTelemetry) { @@ -81,6 +82,6 @@ public R2dbcTelemetryBuilder setSpanNameExtractor( public R2dbcTelemetry build() { return new R2dbcTelemetry( instrumenterBuilder.build(spanNameExtractorTransformer, statementSanitizationEnabled), - sqlCommenterEnabled); + sqlCommenterBuilder.build()); } } diff --git a/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/internal/Experimental.java b/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/internal/Experimental.java index 9ba9e8fb6c14..ba3bebd09575 100644 --- a/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/internal/Experimental.java +++ b/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/internal/Experimental.java @@ -5,8 +5,11 @@ package io.opentelemetry.instrumentation.r2dbc.v1_0.internal; +import io.opentelemetry.context.propagation.TextMapPropagator; +import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenterBuilder; import io.opentelemetry.instrumentation.r2dbc.v1_0.R2dbcTelemetryBuilder; -import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Function; import javax.annotation.Nullable; /** @@ -17,25 +20,66 @@ public final class Experimental { @Nullable - private static volatile BiConsumer setEnableSqlCommenter; + private static volatile Function sqlCommenterBuilder; /** * Sets whether to augment sql query with comment containing the tracing information. See sqlcommenter for more info. * *

WARNING: augmenting queries with tracing context will make query texts unique, which may - * have adverse impact on database performance. Consult with database experts before enabling. + * have adverse impact on database performance. Consult with database experts before enabling. If + * this is an issue, consider replacing the default W3C Trace Context propagator with a propagator + * that only adds static values, such as service name. + * + *

WARNING: for prepared statements query is modified when the statement is created, this means + * that the inserted tracing context could be wrong if the prepared statement is reused. Consider + * replacing the default W3C Trace Context propagator with a propagator that only adds static + * values, such as service name. */ public static void setEnableSqlCommenter( R2dbcTelemetryBuilder builder, boolean sqlCommenterEnabled) { - if (setEnableSqlCommenter != null) { - setEnableSqlCommenter.accept(builder, sqlCommenterEnabled); + if (sqlCommenterBuilder != null) { + sqlCommenterBuilder.apply(builder).setEnabled(sqlCommenterEnabled); + } + } + + /** + * Set the propagator used to inject tracing context into sql comments. By default, W3C Trace + * Context propagator is used. + */ + public static void setSqlCommenterPropagator( + R2dbcTelemetryBuilder builder, TextMapPropagator propagator) { + if (sqlCommenterBuilder != null) { + sqlCommenterBuilder.apply(builder).setPropagator(propagator); + } + } + + /** + * Sets whether to prepend the sql comment to the query instead of appending it. Default is to + * append. This is useful for preserving the comment on databases that truncate long queries in + * their diagnostic output. + */ + public static void setSqlCommenterPrepend( + R2dbcTelemetryBuilder builder, boolean sqlCommenterPrepend) { + if (sqlCommenterBuilder != null) { + sqlCommenterBuilder.apply(builder).setPrepend(sqlCommenterPrepend); + } + } + + /** + * Customize the configuration of {@link SqlCommenterBuilder} used in {@link + * R2dbcTelemetryBuilder}. + */ + public static void customizeSqlCommenter( + R2dbcTelemetryBuilder builder, Consumer customizer) { + if (sqlCommenterBuilder != null) { + customizer.accept(sqlCommenterBuilder.apply(builder)); } } - public static void internalSetEnableSqlCommenter( - BiConsumer setEnableSqlCommenter) { - Experimental.setEnableSqlCommenter = setEnableSqlCommenter; + public static void internalSetSqlCommenterBuilder( + Function sqlCommenterBuilder) { + Experimental.sqlCommenterBuilder = sqlCommenterBuilder; } private Experimental() {} diff --git a/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/internal/R2dbcSqlCommenterUtil.java b/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/internal/R2dbcSqlCommenterUtil.java index a90c8ed5e5ff..6e412e6ece5f 100644 --- a/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/internal/R2dbcSqlCommenterUtil.java +++ b/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/internal/R2dbcSqlCommenterUtil.java @@ -5,12 +5,14 @@ package io.opentelemetry.instrumentation.r2dbc.v1_0.internal; -import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenterUtil; +import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenter; import io.r2dbc.proxy.callback.ProxyConfig; import io.r2dbc.proxy.core.ConnectionInfo; import io.r2dbc.proxy.core.StatementInfo; import io.r2dbc.proxy.core.ValueStore; import io.r2dbc.proxy.listener.BindParameterConverter; +import io.r2dbc.spi.Connection; +import io.r2dbc.spi.Wrapped; import java.util.HashMap; import java.util.Map; @@ -21,12 +23,14 @@ public final class R2dbcSqlCommenterUtil { private static final String KEY_ORIGINAL_QUERY_MAP = "originalQueryMap"; - public static void configure(ProxyConfig proxyConfig) { + public static void configure(ProxyConfig proxyConfig, SqlCommenter sqlCommenter) { proxyConfig.setBindParameterConverter( new BindParameterConverter() { @Override public String onCreateStatement(String query, StatementInfo info) { - String modifiedQuery = SqlCommenterUtil.processQuery(query); + Connection connection = + unwapConnection(info.getConnectionInfo().getOriginalConnection()); + String modifiedQuery = sqlCommenter.processQuery(connection, query, true); if (!modifiedQuery.equals(query)) { // We store mapping from the modified query to original query on the connection // the assumption here is that since the connection is not thread safe it won't be @@ -38,6 +42,15 @@ public String onCreateStatement(String query, StatementInfo info) { }); } + @SuppressWarnings("unchecked") + private static Connection unwapConnection(Connection connection) { + if (connection instanceof Wrapped) { + Wrapped wrapped = (Wrapped) connection; + return wrapped.unwrap(); + } + return connection; + } + @SuppressWarnings("unchecked") private static Map getOriginalQueryMap(ValueStore valueStore) { return valueStore.get(KEY_ORIGINAL_QUERY_MAP, Map.class); diff --git a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/bootstrap/internal/sqlcommenter/SqlCommenterCustomizer.java b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/bootstrap/internal/sqlcommenter/SqlCommenterCustomizer.java new file mode 100644 index 000000000000..0b0a223dbd16 --- /dev/null +++ b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/bootstrap/internal/sqlcommenter/SqlCommenterCustomizer.java @@ -0,0 +1,22 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.bootstrap.internal.sqlcommenter; + +import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenterBuilder; + +/** + * Customize configuration for {@link SqlCommenterBuilder}. This lets extensions configure different + * propagators and decide whether to prepend or append the sqlcommenter comment based on the + * database where the query is executed. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public interface SqlCommenterCustomizer { + + /** Customize the given {@link SqlCommenterBuilder}. */ + void customize(SqlCommenterBuilder builder); +} diff --git a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/bootstrap/internal/sqlcommenter/SqlCommenterCustomizerHolder.java b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/bootstrap/internal/sqlcommenter/SqlCommenterCustomizerHolder.java new file mode 100644 index 000000000000..46366cbb3837 --- /dev/null +++ b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/bootstrap/internal/sqlcommenter/SqlCommenterCustomizerHolder.java @@ -0,0 +1,33 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.bootstrap.internal.sqlcommenter; + +import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenterBuilder; + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ +public final class SqlCommenterCustomizerHolder { + private static volatile SqlCommenterCustomizer customizer = + new SqlCommenterCustomizerHolder.NoOpCustomizer(); + + public static void setCustomizer(SqlCommenterCustomizer customizer) { + SqlCommenterCustomizerHolder.customizer = customizer; + } + + public static SqlCommenterCustomizer getCustomizer() { + return customizer; + } + + private SqlCommenterCustomizerHolder() {} + + private static class NoOpCustomizer implements SqlCommenterCustomizer { + + @Override + public void customize(SqlCommenterBuilder builder) {} + } +} diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AgentInstaller.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AgentInstaller.java index e45fae651526..31757b9d0250 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AgentInstaller.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AgentInstaller.java @@ -30,6 +30,8 @@ import io.opentelemetry.javaagent.bootstrap.http.HttpServerResponseMutator; import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig; import io.opentelemetry.javaagent.bootstrap.internal.ConfiguredResourceAttributesHolder; +import io.opentelemetry.javaagent.bootstrap.internal.sqlcommenter.SqlCommenterCustomizer; +import io.opentelemetry.javaagent.bootstrap.internal.sqlcommenter.SqlCommenterCustomizerHolder; import io.opentelemetry.javaagent.extension.AgentListener; import io.opentelemetry.javaagent.extension.ignore.IgnoredTypesConfigurer; import io.opentelemetry.javaagent.extension.instrumentation.internal.EarlyInstrumentationModule; @@ -222,6 +224,7 @@ private static void installBytebuddyAgent( instrumentationInstalled = true; addHttpServerResponseCustomizers(extensionClassLoader); + addSqlCommenterCustomizers(extensionClassLoader); runAfterAgentListeners(agentListeners, autoConfiguredSdk, sdkConfig); } @@ -349,6 +352,18 @@ public void customize( }); } + private static void addSqlCommenterCustomizers(ClassLoader extensionClassLoader) { + List customizers = + load(SqlCommenterCustomizer.class, extensionClassLoader); + + SqlCommenterCustomizerHolder.setCustomizer( + builder -> { + for (SqlCommenterCustomizer modifier : customizers) { + modifier.customize(builder); + } + }); + } + private static void runAfterAgentListeners( Iterable agentListeners, AutoConfiguredOpenTelemetrySdk autoConfiguredSdk, diff --git a/testing/agent-exporter/build.gradle.kts b/testing/agent-exporter/build.gradle.kts index 3534d1d8eeb9..e4067eab08c3 100644 --- a/testing/agent-exporter/build.gradle.kts +++ b/testing/agent-exporter/build.gradle.kts @@ -12,6 +12,7 @@ dependencies { compileOnly("com.google.auto.service:auto-service") compileOnly(project(":instrumentation-api")) + compileOnly(project(":instrumentation-api-incubator")) compileOnly(project(":javaagent-extension-api")) compileOnly(project(":javaagent-bootstrap")) compileOnly(project(":javaagent-tooling")) diff --git a/testing/agent-exporter/src/main/java/io/opentelemetry/javaagent/testing/sqlcommenter/TestAgentSqlCommenterCustomizer.java b/testing/agent-exporter/src/main/java/io/opentelemetry/javaagent/testing/sqlcommenter/TestAgentSqlCommenterCustomizer.java new file mode 100644 index 000000000000..ec7b706db955 --- /dev/null +++ b/testing/agent-exporter/src/main/java/io/opentelemetry/javaagent/testing/sqlcommenter/TestAgentSqlCommenterCustomizer.java @@ -0,0 +1,21 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.testing.sqlcommenter; + +import com.google.auto.service.AutoService; +import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenterBuilder; +import io.opentelemetry.javaagent.bootstrap.internal.sqlcommenter.SqlCommenterCustomizer; + +@AutoService(SqlCommenterCustomizer.class) +public class TestAgentSqlCommenterCustomizer implements SqlCommenterCustomizer { + + @Override + public void customize(SqlCommenterBuilder builder) { + if (Boolean.getBoolean("otel.testing.sqlcommenter.enabled")) { + builder.setEnabled(true); + } + } +} From 9fd6c53892919a14dac2c9744167cac02c1e8a2c Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Fri, 31 Oct 2025 12:46:20 +0200 Subject: [PATCH 2/2] address review comment --- .../semconv/db/internal/SqlCommenter.java | 15 +++++++++++++-- .../semconv/db/internal/SqlCommenterBuilder.java | 8 ++++---- .../semconv/db/internal/SqlCommenterUtil.java | 2 +- .../jdbc/ConnectionInstrumentation.java | 2 +- .../instrumentation/jdbc/JdbcSingletons.java | 8 ++++---- .../jdbc/StatementInstrumentation.java | 4 ++-- .../jdbc/internal/OpenTelemetryStatement.java | 2 +- .../v1_0/internal/R2dbcSqlCommenterUtil.java | 2 +- 8 files changed, 27 insertions(+), 16 deletions(-) diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenter.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenter.java index 5594530326bf..e84634af087a 100644 --- a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenter.java +++ b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenter.java @@ -36,13 +36,24 @@ public static SqlCommenter noop() { return builder().build(); } - public String processQuery(Object connection, String sql, boolean safe) { + /** + * Augments the given SQL query with comment containing tracing context. + * + * @param connection connection object, e.g. JDBC connection or R2DBC connection, that is used to + * execute the query + * @param sql original query + * @param executed whether the query is immediately executed after being processed, e.g. {@link + * java.sql.Statement#execute(String)}, or may be executed later, e.g. {@link + * java.sql.Connection#prepareStatement(String)} + * @return modified query + */ + public String processQuery(Object connection, String sql, boolean executed) { if (!enabled) { return sql; } return SqlCommenterUtil.processQuery( - sql, propagator.apply(connection, safe), prepend.test(connection)); + sql, propagator.apply(connection, executed), prepend.test(connection)); } public boolean isEnabled() { diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenterBuilder.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenterBuilder.java index 907fc76937ad..4a95ec9b3a23 100644 --- a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenterBuilder.java +++ b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenterBuilder.java @@ -70,11 +70,11 @@ public SqlCommenterBuilder setPropagator(TextMapPropagator propagator) { * Context propagator. * * @param propagator a function that receives the database connection and whether the query is - * executed only once or could be reused. Connection may be a jdbc Connection, R2DBC - * Connection, or any other connection type used by the data access framework performing the + * executed only once or could be reused. Connection may be a JDBC connection, R2DBC + * connection, or any other connection type used by the data access framework performing the * operation. If the second argument to the function is true, the query is executed only once - * (e.g. JDBC {@link Statement#execute(String)}). If false, the query could be reused (e.g. - * JDBC {@link Connection#prepareStatement(String)}). + * (e.g. JDBC {@link Statement#execute(String)}) immediately after processing. If false, the + * query could be reused (e.g. JDBC {@link Connection#prepareStatement(String)}). */ @CanIgnoreReturnValue public SqlCommenterBuilder setPropagator( diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenterUtil.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenterUtil.java index 0f795414d0ef..f15952c9adb5 100644 --- a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenterUtil.java +++ b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/internal/SqlCommenterUtil.java @@ -17,7 +17,7 @@ final class SqlCommenterUtil { /** - * Append comment containing tracing information at the end of the query. See sqlcommenter for the description of the * algorithm. */ diff --git a/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/ConnectionInstrumentation.java b/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/ConnectionInstrumentation.java index caa87a25d35a..e3925286cb38 100644 --- a/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/ConnectionInstrumentation.java +++ b/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/ConnectionInstrumentation.java @@ -104,7 +104,7 @@ public static Object[] processSql( Context context = Java8BytecodeBridge.currentContext(); if (PrepareContext.get(context) == null) { // process sql only in the outermost prepare call and save the original sql in context - String processSql = JdbcSingletons.processSql(connection, sql, true); + String processSql = JdbcSingletons.processSql(connection, sql, false); Scope scope = PrepareContext.init(context, sql).makeCurrent(); return new Object[] {processSql, scope}; } else { diff --git a/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/JdbcSingletons.java b/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/JdbcSingletons.java index 285a2b25a35f..22e0283b5a35 100644 --- a/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/JdbcSingletons.java +++ b/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/JdbcSingletons.java @@ -114,7 +114,7 @@ private static SqlCommenter configureSqlCommenter() { return builder.build(); } - public static String processSql(Statement statement, String sql, boolean safe) { + public static String processSql(Statement statement, String sql, boolean executed) { Connection connection; try { connection = statement.getConnection(); @@ -122,11 +122,11 @@ public static String processSql(Statement statement, String sql, boolean safe) { // connection was already closed return sql; } - return processSql(connection, sql, safe); + return processSql(connection, sql, executed); } - public static String processSql(Connection connection, String sql, boolean safe) { - return SQL_COMMENTER.processQuery(connection, sql, safe); + public static String processSql(Connection connection, String sql, boolean executed) { + return SQL_COMMENTER.processQuery(connection, sql, executed); } private JdbcSingletons() {} diff --git a/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/StatementInstrumentation.java b/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/StatementInstrumentation.java index 0c057b64c9ea..5625b40d7036 100644 --- a/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/StatementInstrumentation.java +++ b/instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/StatementInstrumentation.java @@ -69,7 +69,7 @@ public static Object[] onEnter( return new Object[] {null, sql}; } - String processedSql = JdbcSingletons.processSql(statement, sql, false); + String processedSql = JdbcSingletons.processSql(statement, sql, true); return new Object[] { JdbcAdviceScope.startStatement(CallDepth.forClass(Statement.class), sql, statement), processedSql @@ -101,7 +101,7 @@ public static String addBatch( } JdbcData.addStatementBatch(statement, sql); - return JdbcSingletons.processSql(statement, sql, false); + return JdbcSingletons.processSql(statement, sql, true); } } diff --git a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryStatement.java b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryStatement.java index 3f5711b81eb0..6209bc6766fa 100644 --- a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryStatement.java +++ b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/OpenTelemetryStatement.java @@ -71,7 +71,7 @@ class OpenTelemetryStatement implements Statement { } private String processQuery(String sql) { - return sqlCommenter.processQuery(connection.delegate, sql, false); + return sqlCommenter.processQuery(connection.delegate, sql, true); } @Override diff --git a/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/internal/R2dbcSqlCommenterUtil.java b/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/internal/R2dbcSqlCommenterUtil.java index 6e412e6ece5f..1e1d07db9f77 100644 --- a/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/internal/R2dbcSqlCommenterUtil.java +++ b/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/internal/R2dbcSqlCommenterUtil.java @@ -30,7 +30,7 @@ public static void configure(ProxyConfig proxyConfig, SqlCommenter sqlCommenter) public String onCreateStatement(String query, StatementInfo info) { Connection connection = unwapConnection(info.getConnectionInfo().getOriginalConnection()); - String modifiedQuery = sqlCommenter.processQuery(connection, query, true); + String modifiedQuery = sqlCommenter.processQuery(connection, query, false); if (!modifiedQuery.equals(query)) { // We store mapping from the modified query to original query on the connection // the assumption here is that since the connection is not thread safe it won't be