From ccc7e0d973a749b407565cf51df6864dc88b3877 Mon Sep 17 00:00:00 2001 From: Douglas Q Hawkins Date: Tue, 30 Jun 2026 20:51:48 -0400 Subject: [PATCH 1/2] Use TagExtractor for JDBC connection-info tags (canary) First real use of the TagExtractor mechanism: lifts the pure field->tag connection tags (warehouse / schema / pool) out of JDBCDecorator into a static-final non-capturing CONNECTION_INFO_EXTRACTOR, applied via the span-first span.setTags(dbInfo, CONNECTION_INFO_EXTRACTOR) at the single onConnection site (a monomorphic call site the JIT inlines). Behavior- identical to the previous inline setTagIfPresent block. Co-Authored-By: Claude Opus 4.8 --- .../instrumentation/jdbc/JDBCDecorator.java | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCDecorator.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCDecorator.java index 76aacf64d5f..b314fc8110a 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCDecorator.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCDecorator.java @@ -19,6 +19,7 @@ import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.AgentTracer; import datadog.trace.bootstrap.instrumentation.api.InternalSpanTypes; +import datadog.trace.bootstrap.instrumentation.api.TagExtractor; import datadog.trace.bootstrap.instrumentation.api.Tags; import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString; import datadog.trace.bootstrap.instrumentation.decorator.DatabaseClientDecorator; @@ -74,6 +75,19 @@ public class JDBCDecorator extends DatabaseClientDecorator { private static final boolean FETCH_DB_METADATA_ON_QUERY = Config.get().isDbMetadataFetchingOnQueryEnabled(); + // Canary for the TagExtractor mechanism: the JDBC-specific, pure field->tag connection tags + // (warehouse / schema / pool — no derivation). A static-final non-capturing lambda applied via + // span.setTags(...) at the single onConnection site — a monomorphic call site the JIT inlines + // (the span.setTags indirection folds away). Behavior-identical to the previous inline + // setTagIfPresent block. (DB_TYPE / instance / hostname stay in the decorator for now: their + // values feed service-name/naming derivation — bucket (c), a later declarative step.) + private static final TagExtractor CONNECTION_INFO_EXTRACTOR = + (info, span) -> { + setTagIfPresent(span, DB_WAREHOUSE, info.getWarehouse()); + setTagIfPresent(span, DB_SCHEMA, info.getSchema()); + setTagIfPresent(span, DB_POOL_NAME, info.getPoolName()); + }; + private volatile boolean warnedAboutDBMPropagationMode = false; // to log a warning only once private volatile boolean loggedInjectionError = false; @@ -147,7 +161,7 @@ protected String dbHostname(final DBInfo info) { return info.getHost(); } - private void setTagIfPresent(final AgentSpan span, final String key, final String value) { + private static void setTagIfPresent(final AgentSpan span, final String key, final String value) { if (value != null && !value.isEmpty()) { span.setTag(key, value); } @@ -157,9 +171,7 @@ public AgentSpan onConnection(final AgentSpan span, DBInfo dbInfo) { if (dbInfo != null) { processDatabaseType(span, dbInfo.getType()); - setTagIfPresent(span, DB_WAREHOUSE, dbInfo.getWarehouse()); - setTagIfPresent(span, DB_SCHEMA, dbInfo.getSchema()); - setTagIfPresent(span, DB_POOL_NAME, dbInfo.getPoolName()); + span.setTags(dbInfo, CONNECTION_INFO_EXTRACTOR); } return super.onConnection(span, dbInfo); } From 56d280dffdbb9183b87c5b646c728bddcc7de605 Mon Sep 17 00:00:00 2001 From: Douglas Q Hawkins Date: Tue, 30 Jun 2026 21:13:37 -0400 Subject: [PATCH 2/2] Promote JDBC CONNECTION_INFO_EXTRACTOR to a named singleton class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Turns the inline lambda into ConnectionInfoExtractor (a proper TagExtractor with a private-ctor INSTANCE singleton), mirroring PeerConnectionExtractor. Gives it a name at the call site (span.setTags(dbInfo, ConnectionInfoExtractor.INSTANCE)) and makes it composable. The setTagIfPresent helper moves onto the class. Verified auto-injected as a transitive helper (JDBCInstrumentationV0Test: 87/87 green) — no manual helperClassNames() entry needed. Co-Authored-By: Claude Opus 4.8 --- .../jdbc/ConnectionInfoExtractor.java | 40 +++++++++++++++++++ .../instrumentation/jdbc/JDBCDecorator.java | 22 +--------- 2 files changed, 41 insertions(+), 21 deletions(-) create mode 100644 dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/ConnectionInfoExtractor.java diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/ConnectionInfoExtractor.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/ConnectionInfoExtractor.java new file mode 100644 index 00000000000..4f001e3c73f --- /dev/null +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/ConnectionInfoExtractor.java @@ -0,0 +1,40 @@ +package datadog.trace.instrumentation.jdbc; + +import static datadog.trace.bootstrap.instrumentation.api.Tags.DB_POOL_NAME; +import static datadog.trace.bootstrap.instrumentation.api.Tags.DB_SCHEMA; +import static datadog.trace.bootstrap.instrumentation.api.Tags.DB_WAREHOUSE; + +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import datadog.trace.bootstrap.instrumentation.api.TagExtractor; +import datadog.trace.bootstrap.instrumentation.jdbc.DBInfo; + +/** + * Named singleton {@link TagExtractor} for the pure JDBC connection tags (warehouse / schema / + * pool) — no derivation, no side-effects. + * + *

Promoted from an inline lambda in {@link JDBCDecorator} to a named class so it can be + * referenced by name at call sites ({@code span.setTags(dbInfo, ConnectionInfoExtractor.INSTANCE)}) + * and composed with other extractors. Non-capturing and stateless — the single {@link #INSTANCE} is + * effectively a static function object, so a monomorphic call site inlines it away. + * Behavior-identical to the previous inline {@code setTagIfPresent} block. ({@code db.type} / + * instance / hostname stay in the decorator for now: their values feed service-name/naming + * derivation, a later declarative step.) + */ +public final class ConnectionInfoExtractor implements TagExtractor { + public static final ConnectionInfoExtractor INSTANCE = new ConnectionInfoExtractor(); + + private ConnectionInfoExtractor() {} + + @Override + public void extract(final DBInfo info, final AgentSpan span) { + setTagIfPresent(span, DB_WAREHOUSE, info.getWarehouse()); + setTagIfPresent(span, DB_SCHEMA, info.getSchema()); + setTagIfPresent(span, DB_POOL_NAME, info.getPoolName()); + } + + private static void setTagIfPresent(final AgentSpan span, final String key, final String value) { + if (value != null && !value.isEmpty()) { + span.setTag(key, value); + } + } +} diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCDecorator.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCDecorator.java index b314fc8110a..32b59beafbc 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCDecorator.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCDecorator.java @@ -19,7 +19,6 @@ import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.AgentTracer; import datadog.trace.bootstrap.instrumentation.api.InternalSpanTypes; -import datadog.trace.bootstrap.instrumentation.api.TagExtractor; import datadog.trace.bootstrap.instrumentation.api.Tags; import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString; import datadog.trace.bootstrap.instrumentation.decorator.DatabaseClientDecorator; @@ -75,19 +74,6 @@ public class JDBCDecorator extends DatabaseClientDecorator { private static final boolean FETCH_DB_METADATA_ON_QUERY = Config.get().isDbMetadataFetchingOnQueryEnabled(); - // Canary for the TagExtractor mechanism: the JDBC-specific, pure field->tag connection tags - // (warehouse / schema / pool — no derivation). A static-final non-capturing lambda applied via - // span.setTags(...) at the single onConnection site — a monomorphic call site the JIT inlines - // (the span.setTags indirection folds away). Behavior-identical to the previous inline - // setTagIfPresent block. (DB_TYPE / instance / hostname stay in the decorator for now: their - // values feed service-name/naming derivation — bucket (c), a later declarative step.) - private static final TagExtractor CONNECTION_INFO_EXTRACTOR = - (info, span) -> { - setTagIfPresent(span, DB_WAREHOUSE, info.getWarehouse()); - setTagIfPresent(span, DB_SCHEMA, info.getSchema()); - setTagIfPresent(span, DB_POOL_NAME, info.getPoolName()); - }; - private volatile boolean warnedAboutDBMPropagationMode = false; // to log a warning only once private volatile boolean loggedInjectionError = false; @@ -161,17 +147,11 @@ protected String dbHostname(final DBInfo info) { return info.getHost(); } - private static void setTagIfPresent(final AgentSpan span, final String key, final String value) { - if (value != null && !value.isEmpty()) { - span.setTag(key, value); - } - } - public AgentSpan onConnection(final AgentSpan span, DBInfo dbInfo) { if (dbInfo != null) { processDatabaseType(span, dbInfo.getType()); - span.setTags(dbInfo, CONNECTION_INFO_EXTRACTOR); + span.setTags(dbInfo, ConnectionInfoExtractor.INSTANCE); } return super.onConnection(span, dbInfo); }