diff --git a/dd-java-agent/agent-bootstrap/src/jmh/java/datadog/trace/bootstrap/instrumentation/decorator/DatabaseClientConnectionBenchmark.java b/dd-java-agent/agent-bootstrap/src/jmh/java/datadog/trace/bootstrap/instrumentation/decorator/DatabaseClientConnectionBenchmark.java
new file mode 100644
index 00000000000..ff70c1f147c
--- /dev/null
+++ b/dd-java-agent/agent-bootstrap/src/jmh/java/datadog/trace/bootstrap/instrumentation/decorator/DatabaseClientConnectionBenchmark.java
@@ -0,0 +1,209 @@
+package datadog.trace.bootstrap.instrumentation.decorator;
+
+import static datadog.trace.bootstrap.instrumentation.api.Tags.DB_USER;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import datadog.trace.api.GlobalTracer;
+import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
+import datadog.trace.bootstrap.instrumentation.api.TagExtractor;
+import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString;
+import datadog.trace.common.writer.Writer;
+import datadog.trace.core.CoreTracer;
+import datadog.trace.core.DDSpan;
+import java.util.List;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Param;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Threads;
+import org.openjdk.jmh.annotations.Warmup;
+
+/**
+ * Acceptance test for the {@code dbUser} peel: measures the param-injected connection-tags {@link
+ * TagExtractor} form of {@link DatabaseClientDecorator#onConnection(AgentSpan, Object,
+ * TagExtractor)} — the shape that replaced the sparsely-overridden {@code dbUser} template method.
+ *
+ *
One decorator type is used throughout (so the receiver and the {@code dbInstance}/{@code
+ * dbHostname} template calls stay monomorphic); only the injected extractor varies, to isolate the
+ * question raised in review: does passing the extractor as a caller-side constant devirtualize and
+ * inline?
+ *
+ *
{@code mode}:
+ *
+ *
+ * mono — a single {@code static final} extractor at the call site (the production
+ * shape: each integration's advice passes its own constant). Expect {@code extract()} to
+ * devirtualize and inline when {@code onConnection} inlines.
+ * mega — {@link #TYPES} distinct extractor types cycled through the one site (the
+ * worst case: a single shared site that never sees a stable type). Characterizes the downside
+ * if the call is not inlined.
+ *
+ *
+ * Run with {@code -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining} to confirm the mechanism
+ * (the tree, not just the number) — look for {@code DatabaseClientDecorator::onConnection} and the
+ * extractor {@code extract} bodies.
+ */
+@State(Scope.Thread)
+@BenchmarkMode(Mode.Throughput)
+@OutputTimeUnit(SECONDS)
+@Warmup(iterations = 5, time = 2)
+@Measurement(iterations = 5, time = 2)
+@Fork(3)
+@Threads(8)
+public class DatabaseClientConnectionBenchmark {
+
+ private static final int TYPES = 8;
+ private static final String CONN = "bench-user";
+
+ /** The mono call site: a single static-final constant extractor. */
+ private static final TagExtractor MONO = new E0();
+
+ @Param({"mono", "mega"})
+ String mode;
+
+ private boolean mega;
+ private BenchDbDecorator decorator;
+ private AgentSpan span;
+ private TagExtractor[] extractors;
+ private int idx;
+
+ @SuppressWarnings("unchecked")
+ @Setup(Level.Trial)
+ public void setUp() {
+ CoreTracer tracer =
+ CoreTracer.builder().strictTraceWrites(true).writer(new NoOpWriter()).build();
+ GlobalTracer.forceRegister(tracer);
+ decorator = new BenchDbDecorator();
+ span = tracer.startSpan("benchmark", "db.query");
+ extractors =
+ new TagExtractor[] {
+ new E0(), new E1(), new E2(), new E3(), new E4(), new E5(), new E6(), new E7()
+ };
+ mega = "mega".equals(mode);
+ }
+
+ @Benchmark
+ public AgentSpan onConnection() {
+ if (mega) {
+ int i = idx;
+ idx = (i + 1 == TYPES) ? 0 : i + 1;
+ return decorator.onConnection(span, CONN, extractors[i]);
+ }
+ return decorator.onConnection(span, CONN, MONO);
+ }
+
+ // Eight structurally-identical but distinct extractor types (so the mega site sees a rotating
+ // type).
+ static final class E0 implements TagExtractor {
+ public void extract(String c, AgentSpan s) {
+ s.setTag(DB_USER, c);
+ }
+ }
+
+ static final class E1 implements TagExtractor {
+ public void extract(String c, AgentSpan s) {
+ s.setTag(DB_USER, c);
+ }
+ }
+
+ static final class E2 implements TagExtractor {
+ public void extract(String c, AgentSpan s) {
+ s.setTag(DB_USER, c);
+ }
+ }
+
+ static final class E3 implements TagExtractor {
+ public void extract(String c, AgentSpan s) {
+ s.setTag(DB_USER, c);
+ }
+ }
+
+ static final class E4 implements TagExtractor {
+ public void extract(String c, AgentSpan s) {
+ s.setTag(DB_USER, c);
+ }
+ }
+
+ static final class E5 implements TagExtractor {
+ public void extract(String c, AgentSpan s) {
+ s.setTag(DB_USER, c);
+ }
+ }
+
+ static final class E6 implements TagExtractor {
+ public void extract(String c, AgentSpan s) {
+ s.setTag(DB_USER, c);
+ }
+ }
+
+ static final class E7 implements TagExtractor {
+ public void extract(String c, AgentSpan s) {
+ s.setTag(DB_USER, c);
+ }
+ }
+
+ static final class BenchDbDecorator extends DatabaseClientDecorator {
+ private static final CharSequence COMPONENT = UTF8BytesString.create("benchmark");
+
+ @Override
+ protected String[] instrumentationNames() {
+ return new String[] {"benchmark"};
+ }
+
+ @Override
+ protected String service() {
+ return "benchmark-db";
+ }
+
+ @Override
+ protected CharSequence component() {
+ return COMPONENT;
+ }
+
+ @Override
+ protected CharSequence spanType() {
+ return "sql";
+ }
+
+ @Override
+ protected String dbType() {
+ return "benchdb";
+ }
+
+ @Override
+ protected String dbInstance(String connection) {
+ return connection;
+ }
+
+ @Override
+ protected CharSequence dbHostname(String connection) {
+ return null;
+ }
+ }
+
+ private static class NoOpWriter implements Writer {
+ @Override
+ public void write(final List trace) {}
+
+ @Override
+ public void start() {}
+
+ @Override
+ public boolean flush() {
+ return false;
+ }
+
+ @Override
+ public void close() {}
+
+ @Override
+ public void incrementDropCounts(final int spanCount) {}
+ }
+}
diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/decorator/DatabaseClientDecorator.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/decorator/DatabaseClientDecorator.java
index 7336a059bdc..7c108758e24 100644
--- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/decorator/DatabaseClientDecorator.java
+++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/decorator/DatabaseClientDecorator.java
@@ -16,6 +16,7 @@
import datadog.trace.api.naming.SpanNaming;
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
import datadog.trace.bootstrap.instrumentation.api.AgentTracer;
+import datadog.trace.bootstrap.instrumentation.api.TagExtractor;
import datadog.trace.bootstrap.instrumentation.api.Tags;
import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString;
import java.util.function.BiConsumer;
@@ -55,12 +56,15 @@ public String getDbType() {
protected abstract String dbType();
- protected abstract String dbUser(CONNECTION connection);
-
protected abstract String dbInstance(CONNECTION connection);
protected abstract CharSequence dbHostname(CONNECTION connection);
+ /**
+ * No-op connection-tag extractor: the default for stores that contribute no pure connection tags.
+ */
+ private static final TagExtractor NO_CONNECTION_TAGS = (connection, span) -> {};
+
/**
* This should be called when the connection is being used, not when it's created.
*
@@ -69,8 +73,26 @@ public String getDbType() {
* @return
*/
public AgentSpan onConnection(final AgentSpan span, final CONNECTION connection) {
+ return onConnection(span, connection, noConnectionTags());
+ }
+
+ /**
+ * As {@link #onConnection(AgentSpan, Object)}, but with a {@link TagExtractor} for the store's
+ * pure connection tags (e.g. {@code db.user} for SQL) injected as a parameter.
+ *
+ * Passing the extractor as a caller-side argument — rather than fetching it from a virtual
+ * method — is what preserves inlining: at a monomorphic advice site the extractor is a {@code
+ * static final} constant, so when this (small) method inlines, {@code extractor.extract(...)}
+ * devirtualizes and inlines too. It replaces the previous per-store template methods (the
+ * sparsely overridden {@code dbUser}, which most NoSQL stores could only answer with {@code
+ * null}) and is the seam for disentangling pure tag extraction from the derivation below.
+ */
+ public AgentSpan onConnection(
+ final AgentSpan span,
+ final CONNECTION connection,
+ final TagExtractor connectionTags) {
if (connection != null) {
- span.setTag(Tags.DB_USER, dbUser(connection));
+ connectionTags.extract(connection, span);
onInstance(span, dbInstance(connection));
CharSequence hostName = dbHostname(connection);
if (hostName != null) {
@@ -84,6 +106,11 @@ public AgentSpan onConnection(final AgentSpan span, final CONNECTION connection)
return span;
}
+ @SuppressWarnings("unchecked")
+ protected static TagExtractor noConnectionTags() {
+ return (TagExtractor) NO_CONNECTION_TAGS;
+ }
+
protected AgentSpan onInstance(final AgentSpan span, final String dbInstance) {
if (dbInstance != null) {
span.setTag(Tags.DB_INSTANCE, dbInstance);
diff --git a/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/instrumentation/decorator/DBTypeProcessingDatabaseClientDecoratorTest.groovy b/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/instrumentation/decorator/DBTypeProcessingDatabaseClientDecoratorTest.groovy
index 624100fcc50..c7794fcda1f 100644
--- a/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/instrumentation/decorator/DBTypeProcessingDatabaseClientDecoratorTest.groovy
+++ b/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/instrumentation/decorator/DBTypeProcessingDatabaseClientDecoratorTest.groovy
@@ -67,11 +67,6 @@ class DBTypeProcessingDatabaseClientDecoratorTest extends ClientDecoratorTest {
return "test-db"
}
- @Override
- protected String dbUser(Map map) {
- return map.user
- }
-
@Override
protected String dbInstance(Map map) {
return map.instance
diff --git a/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/instrumentation/decorator/DatabaseClientDecoratorTest.groovy b/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/instrumentation/decorator/DatabaseClientDecoratorTest.groovy
index 93852ccc88c..6f6bab2e8fa 100644
--- a/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/instrumentation/decorator/DatabaseClientDecoratorTest.groovy
+++ b/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/instrumentation/decorator/DatabaseClientDecoratorTest.groovy
@@ -51,7 +51,8 @@ class DatabaseClientDecoratorTest extends ClientDecoratorTest {
then:
if (session) {
- 1 * span.setTag(Tags.DB_USER, session.user)
+ // db.user is no longer set by the 2-arg onConnection (it used to come from the dbUser template
+ // method); it now arrives via the connection-tags extractor of the 3-arg form (see below).
if (session.instance != null) {
1 * span.setTag(Tags.DB_INSTANCE, session.instance)
}
@@ -88,6 +89,32 @@ class DatabaseClientDecoratorTest extends ClientDecoratorTest {
true | true | true | [user: "test-user", instance: "test-instance"]
}
+ def "test onConnection applies the connection-tags extractor"() {
+ setup:
+ def decorator = newDecorator()
+ def session = [user: "test-user"]
+
+ when:
+ decorator.onConnection(span, session, { Map m, AgentSpan s -> s.setTag(Tags.DB_USER, m.user) })
+
+ then:
+ 1 * span.setTag(Tags.DB_USER, "test-user")
+ 0 * _
+ }
+
+ def "test onConnection with a null connection skips the extractor"() {
+ setup:
+ def decorator = newDecorator()
+ def extractor = Mock(datadog.trace.bootstrap.instrumentation.api.TagExtractor)
+
+ when:
+ decorator.onConnection(span, null, extractor)
+
+ then:
+ 0 * extractor.extract(_, _)
+ 0 * _
+ }
+
def "test onStatement"() {
setup:
def decorator = newDecorator()
@@ -134,11 +161,6 @@ class DatabaseClientDecoratorTest extends ClientDecoratorTest {
return "test-db"
}
- @Override
- protected String dbUser(Map map) {
- return map.user
- }
-
@Override
protected String dbInstance(Map map) {
return map.instance
diff --git a/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/instrumentation/decorator/OrmClientDecoratorTest.groovy b/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/instrumentation/decorator/OrmClientDecoratorTest.groovy
index f5c2995ccaa..8778ca6be09 100644
--- a/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/instrumentation/decorator/OrmClientDecoratorTest.groovy
+++ b/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/instrumentation/decorator/OrmClientDecoratorTest.groovy
@@ -35,11 +35,6 @@ class OrmClientDecoratorTest extends DatabaseClientDecoratorTest {
return "test-db"
}
- @Override
- protected String dbUser(Object o) {
- return "test-user"
- }
-
@Override
protected String dbInstance(Object o) {
return "test-user"
diff --git a/dd-java-agent/instrumentation/aerospike-4.0/src/main/java/datadog/trace/instrumentation/aerospike4/AerospikeClientDecorator.java b/dd-java-agent/instrumentation/aerospike-4.0/src/main/java/datadog/trace/instrumentation/aerospike4/AerospikeClientDecorator.java
index e00683755c9..4b403f37809 100644
--- a/dd-java-agent/instrumentation/aerospike-4.0/src/main/java/datadog/trace/instrumentation/aerospike4/AerospikeClientDecorator.java
+++ b/dd-java-agent/instrumentation/aerospike-4.0/src/main/java/datadog/trace/instrumentation/aerospike4/AerospikeClientDecorator.java
@@ -50,11 +50,6 @@ protected String dbType() {
return DB_TYPE;
}
- @Override
- protected String dbUser(final Node node) {
- return null;
- }
-
@Override
protected String dbInstance(final Node node) {
return null;
diff --git a/dd-java-agent/instrumentation/couchbase/couchbase-2.0/src/main/java/datadog/trace/instrumentation/couchbase/client/CouchbaseClientDecorator.java b/dd-java-agent/instrumentation/couchbase/couchbase-2.0/src/main/java/datadog/trace/instrumentation/couchbase/client/CouchbaseClientDecorator.java
index cd592761951..0b8e57673f3 100644
--- a/dd-java-agent/instrumentation/couchbase/couchbase-2.0/src/main/java/datadog/trace/instrumentation/couchbase/client/CouchbaseClientDecorator.java
+++ b/dd-java-agent/instrumentation/couchbase/couchbase-2.0/src/main/java/datadog/trace/instrumentation/couchbase/client/CouchbaseClientDecorator.java
@@ -42,11 +42,6 @@ protected String dbType() {
return "couchbase";
}
- @Override
- protected String dbUser(final Object o) {
- return null;
- }
-
@Override
protected String dbInstance(final Object o) {
return null;
diff --git a/dd-java-agent/instrumentation/couchbase/couchbase-3.1/src/main/java/datadog/trace/instrumentation/couchbase_31/client/CouchbaseClientDecorator.java b/dd-java-agent/instrumentation/couchbase/couchbase-3.1/src/main/java/datadog/trace/instrumentation/couchbase_31/client/CouchbaseClientDecorator.java
index 803b53e7e49..de988fa86ee 100644
--- a/dd-java-agent/instrumentation/couchbase/couchbase-3.1/src/main/java/datadog/trace/instrumentation/couchbase_31/client/CouchbaseClientDecorator.java
+++ b/dd-java-agent/instrumentation/couchbase/couchbase-3.1/src/main/java/datadog/trace/instrumentation/couchbase_31/client/CouchbaseClientDecorator.java
@@ -51,11 +51,6 @@ protected String dbType() {
return DB_TYPE;
}
- @Override
- protected String dbUser(final Object o) {
- return null;
- }
-
@Override
protected String dbInstance(final Object o) {
return null;
diff --git a/dd-java-agent/instrumentation/couchbase/couchbase-3.2/src/main/java/datadog/trace/instrumentation/couchbase_32/client/CouchbaseClientDecorator.java b/dd-java-agent/instrumentation/couchbase/couchbase-3.2/src/main/java/datadog/trace/instrumentation/couchbase_32/client/CouchbaseClientDecorator.java
index 642f88eb739..985cf901f6d 100644
--- a/dd-java-agent/instrumentation/couchbase/couchbase-3.2/src/main/java/datadog/trace/instrumentation/couchbase_32/client/CouchbaseClientDecorator.java
+++ b/dd-java-agent/instrumentation/couchbase/couchbase-3.2/src/main/java/datadog/trace/instrumentation/couchbase_32/client/CouchbaseClientDecorator.java
@@ -51,11 +51,6 @@ protected String dbType() {
return DB_TYPE;
}
- @Override
- protected String dbUser(final Object o) {
- return null;
- }
-
@Override
protected String dbInstance(final Object o) {
return null;
diff --git a/dd-java-agent/instrumentation/datanucleus-4.0.5/src/main/java/datadog/trace/instrumentation/datanucleus/DatanucleusDecorator.java b/dd-java-agent/instrumentation/datanucleus-4.0.5/src/main/java/datadog/trace/instrumentation/datanucleus/DatanucleusDecorator.java
index bbd970de659..1de3ea5b480 100644
--- a/dd-java-agent/instrumentation/datanucleus-4.0.5/src/main/java/datadog/trace/instrumentation/datanucleus/DatanucleusDecorator.java
+++ b/dd-java-agent/instrumentation/datanucleus-4.0.5/src/main/java/datadog/trace/instrumentation/datanucleus/DatanucleusDecorator.java
@@ -68,11 +68,6 @@ protected String dbType() {
return null;
}
- @Override
- protected String dbUser(final Object o) {
- return null;
- }
-
@Override
protected String dbInstance(final Object o) {
return null;
diff --git a/dd-java-agent/instrumentation/datastax-cassandra/datastax-cassandra-3.0/src/main/java/datadog/trace/instrumentation/datastax/cassandra/CassandraClientDecorator.java b/dd-java-agent/instrumentation/datastax-cassandra/datastax-cassandra-3.0/src/main/java/datadog/trace/instrumentation/datastax/cassandra/CassandraClientDecorator.java
index 09f83cd84fa..a3967b4c4d2 100644
--- a/dd-java-agent/instrumentation/datastax-cassandra/datastax-cassandra-3.0/src/main/java/datadog/trace/instrumentation/datastax/cassandra/CassandraClientDecorator.java
+++ b/dd-java-agent/instrumentation/datastax-cassandra/datastax-cassandra-3.0/src/main/java/datadog/trace/instrumentation/datastax/cassandra/CassandraClientDecorator.java
@@ -62,11 +62,6 @@ protected String dbType() {
return DB_TYPE;
}
- @Override
- protected String dbUser(final Session session) {
- return null;
- }
-
@Override
protected String dbInstance(final Session session) {
return session.getLoggedKeyspace();
diff --git a/dd-java-agent/instrumentation/datastax-cassandra/datastax-cassandra-4.0/src/main/java/datadog/trace/instrumentation/datastax/cassandra4/CassandraClientDecorator.java b/dd-java-agent/instrumentation/datastax-cassandra/datastax-cassandra-4.0/src/main/java/datadog/trace/instrumentation/datastax/cassandra4/CassandraClientDecorator.java
index 73badd7fbd2..a4356c6f74c 100644
--- a/dd-java-agent/instrumentation/datastax-cassandra/datastax-cassandra-4.0/src/main/java/datadog/trace/instrumentation/datastax/cassandra4/CassandraClientDecorator.java
+++ b/dd-java-agent/instrumentation/datastax-cassandra/datastax-cassandra-4.0/src/main/java/datadog/trace/instrumentation/datastax/cassandra4/CassandraClientDecorator.java
@@ -67,11 +67,6 @@ protected String dbType() {
return DB_TYPE;
}
- @Override
- protected String dbUser(final Session session) {
- return null;
- }
-
@Override
protected String dbInstance(final Session session) {
return session.getKeyspace().map(Objects::toString).orElse(null);
diff --git a/dd-java-agent/instrumentation/elasticsearch/elasticsearch-common/src/main/java/datadog/trace/instrumentation/elasticsearch/ElasticsearchRestClientDecorator.java b/dd-java-agent/instrumentation/elasticsearch/elasticsearch-common/src/main/java/datadog/trace/instrumentation/elasticsearch/ElasticsearchRestClientDecorator.java
index 0741e14a39e..ea133164520 100644
--- a/dd-java-agent/instrumentation/elasticsearch/elasticsearch-common/src/main/java/datadog/trace/instrumentation/elasticsearch/ElasticsearchRestClientDecorator.java
+++ b/dd-java-agent/instrumentation/elasticsearch/elasticsearch-common/src/main/java/datadog/trace/instrumentation/elasticsearch/ElasticsearchRestClientDecorator.java
@@ -57,11 +57,6 @@ protected String dbType() {
return "elasticsearch";
}
- @Override
- protected String dbUser(final Object o) {
- return null;
- }
-
@Override
protected String dbInstance(final Object o) {
return null;
diff --git a/dd-java-agent/instrumentation/elasticsearch/elasticsearch-common/src/main/java/datadog/trace/instrumentation/elasticsearch/ElasticsearchTransportClientDecorator.java b/dd-java-agent/instrumentation/elasticsearch/elasticsearch-common/src/main/java/datadog/trace/instrumentation/elasticsearch/ElasticsearchTransportClientDecorator.java
index 172a7a56ef8..0ceb11c5bfd 100644
--- a/dd-java-agent/instrumentation/elasticsearch/elasticsearch-common/src/main/java/datadog/trace/instrumentation/elasticsearch/ElasticsearchTransportClientDecorator.java
+++ b/dd-java-agent/instrumentation/elasticsearch/elasticsearch-common/src/main/java/datadog/trace/instrumentation/elasticsearch/ElasticsearchTransportClientDecorator.java
@@ -45,11 +45,6 @@ protected String dbType() {
return DB_TYPE;
}
- @Override
- protected String dbUser(final Object o) {
- return null;
- }
-
@Override
protected String dbInstance(final Object o) {
return null;
diff --git a/dd-java-agent/instrumentation/hibernate/hibernate-common/src/main/java/datadog/trace/instrumentation/hibernate/HibernateDecorator.java b/dd-java-agent/instrumentation/hibernate/hibernate-common/src/main/java/datadog/trace/instrumentation/hibernate/HibernateDecorator.java
index 6c7aa6b9798..e7f4136e139 100644
--- a/dd-java-agent/instrumentation/hibernate/hibernate-common/src/main/java/datadog/trace/instrumentation/hibernate/HibernateDecorator.java
+++ b/dd-java-agent/instrumentation/hibernate/hibernate-common/src/main/java/datadog/trace/instrumentation/hibernate/HibernateDecorator.java
@@ -40,11 +40,6 @@ protected String dbType() {
return null;
}
- @Override
- protected String dbUser(final Object o) {
- return null;
- }
-
@Override
protected String dbInstance(final Object o) {
return null;
diff --git a/dd-java-agent/instrumentation/ignite-2.0/src/main/java/datadog/trace/instrumentation/ignite/v2/cache/IgniteCacheDecorator.java b/dd-java-agent/instrumentation/ignite-2.0/src/main/java/datadog/trace/instrumentation/ignite/v2/cache/IgniteCacheDecorator.java
index ef372f24a06..64b2649f7b8 100644
--- a/dd-java-agent/instrumentation/ignite-2.0/src/main/java/datadog/trace/instrumentation/ignite/v2/cache/IgniteCacheDecorator.java
+++ b/dd-java-agent/instrumentation/ignite-2.0/src/main/java/datadog/trace/instrumentation/ignite/v2/cache/IgniteCacheDecorator.java
@@ -56,11 +56,6 @@ protected String dbType() {
return DB_TYPE;
}
- @Override
- protected String dbUser(IgniteCache igniteCache) {
- return null;
- }
-
@Override
protected String dbInstance(IgniteCache igniteCache) {
return null;
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
index 4f001e3c73f..db1d0b4c14d 100644
--- 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
@@ -2,6 +2,7 @@
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_USER;
import static datadog.trace.bootstrap.instrumentation.api.Tags.DB_WAREHOUSE;
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
@@ -27,6 +28,9 @@ private ConnectionInfoExtractor() {}
@Override
public void extract(final DBInfo info, final AgentSpan span) {
+ // DB_USER is set unconditionally to preserve the prior DatabaseClientDecorator behavior (it set
+ // db.user from dbUser(info) without a present-check); the rest skip null/empty.
+ span.setTag(DB_USER, info.getUser());
setTagIfPresent(span, DB_WAREHOUSE, info.getWarehouse());
setTagIfPresent(span, DB_SCHEMA, info.getSchema());
setTagIfPresent(span, DB_POOL_NAME, info.getPoolName());
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 32b59beafbc..d3799172c20 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
@@ -128,11 +128,6 @@ protected String dbType() {
return "jdbc";
}
- @Override
- protected String dbUser(final DBInfo info) {
- return info.getUser();
- }
-
@Override
protected String dbInstance(final DBInfo info) {
if (info.getInstance() != null) {
@@ -150,10 +145,10 @@ protected String dbHostname(final DBInfo info) {
public AgentSpan onConnection(final AgentSpan span, DBInfo dbInfo) {
if (dbInfo != null) {
processDatabaseType(span, dbInfo.getType());
-
- span.setTags(dbInfo, ConnectionInfoExtractor.INSTANCE);
}
- return super.onConnection(span, dbInfo);
+ // Pure connection tags (db.user / warehouse / schema / pool) are injected via the param form;
+ // the base applies them under its own null-check alongside instance/hostname derivation.
+ return super.onConnection(span, dbInfo, ConnectionInfoExtractor.INSTANCE);
}
public static DBInfo parseDBInfo(
diff --git a/dd-java-agent/instrumentation/jedis/jedis-1.4/src/main/java/datadog/trace/instrumentation/jedis/JedisClientDecorator.java b/dd-java-agent/instrumentation/jedis/jedis-1.4/src/main/java/datadog/trace/instrumentation/jedis/JedisClientDecorator.java
index f85167f6ba2..012880d4a5b 100644
--- a/dd-java-agent/instrumentation/jedis/jedis-1.4/src/main/java/datadog/trace/instrumentation/jedis/JedisClientDecorator.java
+++ b/dd-java-agent/instrumentation/jedis/jedis-1.4/src/main/java/datadog/trace/instrumentation/jedis/JedisClientDecorator.java
@@ -40,11 +40,6 @@ protected String dbType() {
return REDIS;
}
- @Override
- protected String dbUser(final Connection connection) {
- return null;
- }
-
@Override
protected String dbInstance(final Connection connection) {
return null;
diff --git a/dd-java-agent/instrumentation/jedis/jedis-3.0/src/main/java/datadog/trace/instrumentation/jedis30/JedisClientDecorator.java b/dd-java-agent/instrumentation/jedis/jedis-3.0/src/main/java/datadog/trace/instrumentation/jedis30/JedisClientDecorator.java
index edaaa9278b3..e0bd1c94911 100644
--- a/dd-java-agent/instrumentation/jedis/jedis-3.0/src/main/java/datadog/trace/instrumentation/jedis30/JedisClientDecorator.java
+++ b/dd-java-agent/instrumentation/jedis/jedis-3.0/src/main/java/datadog/trace/instrumentation/jedis30/JedisClientDecorator.java
@@ -41,11 +41,6 @@ protected String dbType() {
return REDIS;
}
- @Override
- protected String dbUser(final Connection connection) {
- return null;
- }
-
@Override
protected String dbInstance(final Connection connection) {
return null;
diff --git a/dd-java-agent/instrumentation/jedis/jedis-4.0/src/main/java/redis/clients/jedis/JedisClientDecorator.java b/dd-java-agent/instrumentation/jedis/jedis-4.0/src/main/java/redis/clients/jedis/JedisClientDecorator.java
index ccbfc3d3418..8e8e51027dd 100644
--- a/dd-java-agent/instrumentation/jedis/jedis-4.0/src/main/java/redis/clients/jedis/JedisClientDecorator.java
+++ b/dd-java-agent/instrumentation/jedis/jedis-4.0/src/main/java/redis/clients/jedis/JedisClientDecorator.java
@@ -40,11 +40,6 @@ protected String dbType() {
return REDIS;
}
- @Override
- protected String dbUser(final Connection connection) {
- return null;
- }
-
@Override
protected String dbInstance(final Connection connection) {
return null;
diff --git a/dd-java-agent/instrumentation/lettuce/lettuce-4.0/src/main/java/datadog/trace/instrumentation/lettuce4/LettuceClientDecorator.java b/dd-java-agent/instrumentation/lettuce/lettuce-4.0/src/main/java/datadog/trace/instrumentation/lettuce4/LettuceClientDecorator.java
index 31b8c2e67e2..034fbd8fb28 100644
--- a/dd-java-agent/instrumentation/lettuce/lettuce-4.0/src/main/java/datadog/trace/instrumentation/lettuce4/LettuceClientDecorator.java
+++ b/dd-java-agent/instrumentation/lettuce/lettuce-4.0/src/main/java/datadog/trace/instrumentation/lettuce4/LettuceClientDecorator.java
@@ -45,11 +45,6 @@ protected String dbType() {
return "redis";
}
- @Override
- protected String dbUser(final RedisURI connection) {
- return null;
- }
-
@Override
protected String dbInstance(final RedisURI connection) {
return null;
diff --git a/dd-java-agent/instrumentation/lettuce/lettuce-5.0/src/main/java/datadog/trace/instrumentation/lettuce5/LettuceClientDecorator.java b/dd-java-agent/instrumentation/lettuce/lettuce-5.0/src/main/java/datadog/trace/instrumentation/lettuce5/LettuceClientDecorator.java
index a8442a1f320..00b2582295d 100644
--- a/dd-java-agent/instrumentation/lettuce/lettuce-5.0/src/main/java/datadog/trace/instrumentation/lettuce5/LettuceClientDecorator.java
+++ b/dd-java-agent/instrumentation/lettuce/lettuce-5.0/src/main/java/datadog/trace/instrumentation/lettuce5/LettuceClientDecorator.java
@@ -41,11 +41,6 @@ protected String dbType() {
return "redis";
}
- @Override
- protected String dbUser(final RedisURI connection) {
- return null;
- }
-
@Override
protected String dbInstance(final RedisURI connection) {
return null;
diff --git a/dd-java-agent/instrumentation/mongo/mongo-common/src/main/java/datadog/trace/instrumentation/mongo/MongoDecorator.java b/dd-java-agent/instrumentation/mongo/mongo-common/src/main/java/datadog/trace/instrumentation/mongo/MongoDecorator.java
index bb6c0f7d8bd..030586fdf53 100644
--- a/dd-java-agent/instrumentation/mongo/mongo-common/src/main/java/datadog/trace/instrumentation/mongo/MongoDecorator.java
+++ b/dd-java-agent/instrumentation/mongo/mongo-common/src/main/java/datadog/trace/instrumentation/mongo/MongoDecorator.java
@@ -52,11 +52,6 @@ protected final String dbType() {
return DB_TYPE;
}
- @Override
- protected final String dbUser(final CommandStartedEvent event) {
- return null;
- }
-
@Override
protected final String dbHostname(CommandStartedEvent event) {
final ConnectionDescription connectionDescription = event.getConnectionDescription();
diff --git a/dd-java-agent/instrumentation/opensearch/opensearch-common/src/main/java/datadog/trace/instrumentation/opensearch/OpensearchRestClientDecorator.java b/dd-java-agent/instrumentation/opensearch/opensearch-common/src/main/java/datadog/trace/instrumentation/opensearch/OpensearchRestClientDecorator.java
index ec07a1c8e55..0d98fe70401 100644
--- a/dd-java-agent/instrumentation/opensearch/opensearch-common/src/main/java/datadog/trace/instrumentation/opensearch/OpensearchRestClientDecorator.java
+++ b/dd-java-agent/instrumentation/opensearch/opensearch-common/src/main/java/datadog/trace/instrumentation/opensearch/OpensearchRestClientDecorator.java
@@ -55,11 +55,6 @@ protected String dbType() {
return "opensearch";
}
- @Override
- protected String dbUser(final Object o) {
- return null;
- }
-
@Override
protected String dbInstance(final Object o) {
return null;
diff --git a/dd-java-agent/instrumentation/opensearch/opensearch-common/src/main/java/datadog/trace/instrumentation/opensearch/OpensearchTransportClientDecorator.java b/dd-java-agent/instrumentation/opensearch/opensearch-common/src/main/java/datadog/trace/instrumentation/opensearch/OpensearchTransportClientDecorator.java
index a91b3dffcbc..b36fe4ac655 100644
--- a/dd-java-agent/instrumentation/opensearch/opensearch-common/src/main/java/datadog/trace/instrumentation/opensearch/OpensearchTransportClientDecorator.java
+++ b/dd-java-agent/instrumentation/opensearch/opensearch-common/src/main/java/datadog/trace/instrumentation/opensearch/OpensearchTransportClientDecorator.java
@@ -44,11 +44,6 @@ protected String dbType() {
return DB_TYPE;
}
- @Override
- protected String dbUser(final Object o) {
- return null;
- }
-
@Override
protected String dbInstance(final Object o) {
return null;
diff --git a/dd-java-agent/instrumentation/rediscala-1.8/src/main/java/datadog/trace/instrumentation/rediscala/RediscalaClientDecorator.java b/dd-java-agent/instrumentation/rediscala-1.8/src/main/java/datadog/trace/instrumentation/rediscala/RediscalaClientDecorator.java
index 3205409a63e..303bbc8e71c 100644
--- a/dd-java-agent/instrumentation/rediscala-1.8/src/main/java/datadog/trace/instrumentation/rediscala/RediscalaClientDecorator.java
+++ b/dd-java-agent/instrumentation/rediscala-1.8/src/main/java/datadog/trace/instrumentation/rediscala/RediscalaClientDecorator.java
@@ -43,11 +43,6 @@ protected String dbType() {
return "redis";
}
- @Override
- protected String dbUser(final RedisConnectionInfo redisConnectionInfo) {
- return null;
- }
-
@Override
protected String dbInstance(final RedisConnectionInfo redisConnectionInfo) {
return null;
diff --git a/dd-java-agent/instrumentation/redisson/redisson-2.0.0/src/main/java/datadog/trace/instrumentation/redisson/RedissonClientDecorator.java b/dd-java-agent/instrumentation/redisson/redisson-2.0.0/src/main/java/datadog/trace/instrumentation/redisson/RedissonClientDecorator.java
index 481fd745e3b..d115e6883bb 100644
--- a/dd-java-agent/instrumentation/redisson/redisson-2.0.0/src/main/java/datadog/trace/instrumentation/redisson/RedissonClientDecorator.java
+++ b/dd-java-agent/instrumentation/redisson/redisson-2.0.0/src/main/java/datadog/trace/instrumentation/redisson/RedissonClientDecorator.java
@@ -42,11 +42,6 @@ protected String dbType() {
return "redis";
}
- @Override
- protected String dbUser(CommandData, ?> commandData) {
- return null;
- }
-
@Override
protected String dbInstance(CommandData, ?> commandData) {
return null;
diff --git a/dd-java-agent/instrumentation/redisson/redisson-2.3.0/src/main/java/datadog/trace/instrumentation/redisson23/RedissonClientDecorator.java b/dd-java-agent/instrumentation/redisson/redisson-2.3.0/src/main/java/datadog/trace/instrumentation/redisson23/RedissonClientDecorator.java
index 19e452b3f14..cfc96c62da5 100644
--- a/dd-java-agent/instrumentation/redisson/redisson-2.3.0/src/main/java/datadog/trace/instrumentation/redisson23/RedissonClientDecorator.java
+++ b/dd-java-agent/instrumentation/redisson/redisson-2.3.0/src/main/java/datadog/trace/instrumentation/redisson23/RedissonClientDecorator.java
@@ -42,11 +42,6 @@ protected String dbType() {
return "redis";
}
- @Override
- protected String dbUser(CommandData, ?> commandData) {
- return null;
- }
-
@Override
protected String dbInstance(CommandData, ?> commandData) {
return null;
diff --git a/dd-java-agent/instrumentation/redisson/redisson-3.10.3/src/main/java/datadog/trace/instrumentation/redisson30/RedissonClientDecorator.java b/dd-java-agent/instrumentation/redisson/redisson-3.10.3/src/main/java/datadog/trace/instrumentation/redisson30/RedissonClientDecorator.java
index 4d157fb8f06..3fe22fddc6d 100644
--- a/dd-java-agent/instrumentation/redisson/redisson-3.10.3/src/main/java/datadog/trace/instrumentation/redisson30/RedissonClientDecorator.java
+++ b/dd-java-agent/instrumentation/redisson/redisson-3.10.3/src/main/java/datadog/trace/instrumentation/redisson30/RedissonClientDecorator.java
@@ -42,11 +42,6 @@ protected String dbType() {
return "redis";
}
- @Override
- protected String dbUser(CommandData, ?> commandData) {
- return null;
- }
-
@Override
protected String dbInstance(CommandData, ?> commandData) {
return null;
diff --git a/dd-java-agent/instrumentation/spymemcached-2.10/src/main/java/datadog/trace/instrumentation/spymemcached/MemcacheClientDecorator.java b/dd-java-agent/instrumentation/spymemcached-2.10/src/main/java/datadog/trace/instrumentation/spymemcached/MemcacheClientDecorator.java
index bcfc58674d5..ea01cf282b5 100644
--- a/dd-java-agent/instrumentation/spymemcached-2.10/src/main/java/datadog/trace/instrumentation/spymemcached/MemcacheClientDecorator.java
+++ b/dd-java-agent/instrumentation/spymemcached-2.10/src/main/java/datadog/trace/instrumentation/spymemcached/MemcacheClientDecorator.java
@@ -44,11 +44,6 @@ protected String dbType() {
return DB_TYPE;
}
- @Override
- protected String dbUser(final MemcachedConnection session) {
- return null;
- }
-
@Override
protected String dbInstance(final MemcachedConnection connection) {
return null;
diff --git a/dd-java-agent/instrumentation/valkey-java-5.3/src/main/java/io/valkey/ValkeyClientDecorator.java b/dd-java-agent/instrumentation/valkey-java-5.3/src/main/java/io/valkey/ValkeyClientDecorator.java
index 0e0e6cf43bf..ebb8ef0bc6c 100644
--- a/dd-java-agent/instrumentation/valkey-java-5.3/src/main/java/io/valkey/ValkeyClientDecorator.java
+++ b/dd-java-agent/instrumentation/valkey-java-5.3/src/main/java/io/valkey/ValkeyClientDecorator.java
@@ -40,11 +40,6 @@ protected String dbType() {
return VALKEY;
}
- @Override
- protected String dbUser(final Connection connection) {
- return null;
- }
-
@Override
protected String dbInstance(final Connection connection) {
return null;
diff --git a/dd-java-agent/instrumentation/vertx/vertx-redis-client/vertx-redis-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_redis_client/VertxRedisClientDecorator.java b/dd-java-agent/instrumentation/vertx/vertx-redis-client/vertx-redis-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_redis_client/VertxRedisClientDecorator.java
index dec7fe39d02..f04c3498365 100644
--- a/dd-java-agent/instrumentation/vertx/vertx-redis-client/vertx-redis-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_redis_client/VertxRedisClientDecorator.java
+++ b/dd-java-agent/instrumentation/vertx/vertx-redis-client/vertx-redis-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_redis_client/VertxRedisClientDecorator.java
@@ -54,11 +54,6 @@ protected String dbType() {
return "redis";
}
- @Override
- protected String dbUser(final SocketAddress socketAddress) {
- return null;
- }
-
@Override
protected String dbInstance(final SocketAddress socketAddress) {
return null;
diff --git a/dd-java-agent/instrumentation/vertx/vertx-sql-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_sql_client_39/VertxSqlClientDecorator.java b/dd-java-agent/instrumentation/vertx/vertx-sql-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_sql_client_39/VertxSqlClientDecorator.java
index d95a6c65137..43fcb7f268e 100644
--- a/dd-java-agent/instrumentation/vertx/vertx-sql-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_sql_client_39/VertxSqlClientDecorator.java
+++ b/dd-java-agent/instrumentation/vertx/vertx-sql-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_sql_client_39/VertxSqlClientDecorator.java
@@ -53,11 +53,6 @@ protected String dbType() {
return "vertx-sql";
}
- @Override
- protected String dbUser(final DBInfo info) {
- return info.getUser();
- }
-
@Override
protected String dbInstance(final DBInfo info) {
if (info.getInstance() != null) {
@@ -92,7 +87,7 @@ public AgentSpan startAndDecorateSpanForStatement(
if (dbInfo != null) {
processDatabaseType(span, dbInfo.getType());
}
- super.onConnection(span, dbInfo);
+ super.onConnection(span, dbInfo, VertxSqlConnectionExtractor.INSTANCE);
if (null != dbQueryInfo) {
span.setResourceName(dbQueryInfo.getSql());
span.setTag(DB_OPERATION, dbQueryInfo.getOperation());
diff --git a/dd-java-agent/instrumentation/vertx/vertx-sql-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_sql_client_39/VertxSqlConnectionExtractor.java b/dd-java-agent/instrumentation/vertx/vertx-sql-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_sql_client_39/VertxSqlConnectionExtractor.java
new file mode 100644
index 00000000000..880188e2826
--- /dev/null
+++ b/dd-java-agent/instrumentation/vertx/vertx-sql-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_sql_client_39/VertxSqlConnectionExtractor.java
@@ -0,0 +1,26 @@
+package datadog.trace.instrumentation.vertx_sql_client_39;
+
+import static datadog.trace.bootstrap.instrumentation.api.Tags.DB_USER;
+
+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 Vertx-SQL's pure connection tags ({@code db.user}). The
+ * SQL-family counterpart to the NoSQL stores that contribute none — injected via the param form of
+ * {@code DatabaseClientDecorator.onConnection} rather than the removed {@code dbUser} template
+ * method.
+ */
+public final class VertxSqlConnectionExtractor implements TagExtractor {
+ public static final VertxSqlConnectionExtractor INSTANCE = new VertxSqlConnectionExtractor();
+
+ private VertxSqlConnectionExtractor() {}
+
+ @Override
+ public void extract(final DBInfo info, final AgentSpan span) {
+ // Unconditional to preserve the prior DatabaseClientDecorator behavior (db.user was set from
+ // dbUser(info) with no present-check).
+ span.setTag(DB_USER, info.getUser());
+ }
+}