From 9f5d390a34b898bc4a8c6ef9367f63f16d57bda7 Mon Sep 17 00:00:00 2001 From: Yury Gribkov Date: Wed, 30 Jul 2025 12:20:26 -0700 Subject: [PATCH 01/12] Populate the base hash with the container tag hash if the process tag propagation feature flag is enabled --- .../datastreams/DefaultPathwayContext.java | 5 ++++ .../DefaultPathwayContextTest.groovy | 27 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultPathwayContext.java b/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultPathwayContext.java index 9fe9af7e9e6..f05de107178 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultPathwayContext.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultPathwayContext.java @@ -7,6 +7,7 @@ import com.datadoghq.sketch.ddsketch.encoding.ByteArrayInput; import com.datadoghq.sketch.ddsketch.encoding.GrowingByteArrayOutput; import com.datadoghq.sketch.ddsketch.encoding.VarEncodingHelper; +import datadog.common.container.ContainerInfo; import datadog.context.propagation.CarrierVisitor; import datadog.trace.api.Config; import datadog.trace.api.ProcessTags; @@ -280,6 +281,10 @@ public static long getBaseHash(WellKnownTags wellKnownTags) { CharSequence processTags = ProcessTags.getTagsForSerialization(); if (processTags != null) { builder.append(processTags); + String containerTagsHash = ContainerInfo.get().getContainerTagsHash(); + if (containerTagsHash != null && !containerTagsHash.isEmpty()) { + builder.append(containerTagsHash); + } } return FNV64Hash.generateHash(builder.toString(), FNV64Hash.Version.v1); } diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/datastreams/DefaultPathwayContextTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/datastreams/DefaultPathwayContextTest.groovy index 802670b6fe5..c7e93f40017 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/core/datastreams/DefaultPathwayContextTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/datastreams/DefaultPathwayContextTest.groovy @@ -1,5 +1,6 @@ package datadog.trace.core.datastreams +import datadog.common.container.ContainerInfo import datadog.communication.ddagent.DDAgentFeaturesDiscovery import datadog.trace.api.Config import datadog.trace.api.DDTraceId @@ -481,6 +482,32 @@ class DefaultPathwayContextTest extends DDCoreSpecification { ProcessTags.reset() } + def "ContainerTagsHash used in hash calculation when enabled propagateTagsEnabled=#propagateTagsEnabled"() { + when: + injectSysConfig(EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED, propagateTagsEnabled.toString()) + ProcessTags.reset() + ProcessTags.addTag("000", "first") + def firstBaseHash = DefaultPathwayContext.getBaseHash(wellKnownTags) + + then: + ContainerInfo.get().setContainerTagsHash("") + def secondBaseHash = DefaultPathwayContext.getBaseHash(wellKnownTags) + + expect: + if (propagateTagsEnabled) { + assert secondBaseHash != firstBaseHash + } else { + assert secondBaseHash == firstBaseHash + } + + cleanup: + injectSysConfig(EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED, "false") + ProcessTags.reset() + + where: + propagateTagsEnabled << [true, false] + } + def "Check context extractor decorator behavior"() { given: def sink = Mock(Sink) From c7a35b294670fdbd05c66a1f7fd5435ed27d29a7 Mon Sep 17 00:00:00 2001 From: Yury Gribkov Date: Wed, 30 Jul 2025 16:46:13 -0700 Subject: [PATCH 02/12] DBM: Inject DD_SERVICE_HASH Extract getBaseHash to be available for SQLCommenter TBD: fix SQLCommenterTest TBD: add DB_DBM_INJECT_SERVICE_HASH_ENABLED --- .../instrumentation/jdbc/build.gradle | 1 + .../jdbc/SQLCommenterBenchmark.java | 4 +- ...BMCompatibleConnectionInstrumentation.java | 2 +- .../instrumentation/jdbc/SQLCommenter.java | 19 ++++++-- .../src/test/groovy/SQLCommenterTest.groovy | 9 +--- .../datastreams/DefaultPathwayContext.java | 21 +-------- .../java/datadog/trace/api/ServiceHash.java | 47 +++++++++++++++++++ 7 files changed, 71 insertions(+), 32 deletions(-) create mode 100644 internal-api/src/main/java/datadog/trace/api/ServiceHash.java diff --git a/dd-java-agent/instrumentation/jdbc/build.gradle b/dd-java-agent/instrumentation/jdbc/build.gradle index 1898efd78b4..dd5861a76f3 100644 --- a/dd-java-agent/instrumentation/jdbc/build.gradle +++ b/dd-java-agent/instrumentation/jdbc/build.gradle @@ -22,6 +22,7 @@ addTestSuiteExtendingForDir('latestDepJava11Test', 'latestDepTest', 'test') dependencies { compileOnly group: 'com.zaxxer', name: 'HikariCP', version: '2.4.0' testImplementation(testFixtures(project(':dd-java-agent:agent-iast'))) + implementation project(':utils:container-utils') // jdbc unit testing testImplementation group: 'com.h2database', name: 'h2', version: '[1.3.168,1.3.169]'// first jdk 1.6 compatible diff --git a/dd-java-agent/instrumentation/jdbc/src/jmh/java/datadog/trace/instrumentation/jdbc/SQLCommenterBenchmark.java b/dd-java-agent/instrumentation/jdbc/src/jmh/java/datadog/trace/instrumentation/jdbc/SQLCommenterBenchmark.java index 195b221d2bc..3331a26d906 100644 --- a/dd-java-agent/instrumentation/jdbc/src/jmh/java/datadog/trace/instrumentation/jdbc/SQLCommenterBenchmark.java +++ b/dd-java-agent/instrumentation/jdbc/src/jmh/java/datadog/trace/instrumentation/jdbc/SQLCommenterBenchmark.java @@ -21,6 +21,7 @@ public class SQLCommenterBenchmark { private static final String parentService = "parent"; private static final String env = "env"; private static final String version = "version"; + private static final String serviceHash = "service-hash"; private static final boolean injectTrace = true; @Benchmark @@ -36,6 +37,7 @@ public void testToComment() { null, env, version, - traceParent); + traceParent, + serviceHash); } } diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DBMCompatibleConnectionInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DBMCompatibleConnectionInstrumentation.java index 1c628afe152..da8ce96c444 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DBMCompatibleConnectionInstrumentation.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DBMCompatibleConnectionInstrumentation.java @@ -125,7 +125,7 @@ public static String onEnter( dbService = traceConfig(activeSpan()).getServiceMapping().getOrDefault(dbService, dbService); } - if (dbInfo.getType().equals("sqlserver")) { + if (dbInfo.getType().equals("sqlserver")) { // TODO why it's decided here? sql = SQLCommenter.append( sql, dbService, dbInfo.getType(), dbInfo.getHost(), dbInfo.getDb()); diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java index 075ccbbbcc7..208fe7d7566 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java @@ -2,7 +2,9 @@ import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; +import datadog.common.container.ContainerInfo; import datadog.trace.api.Config; +import datadog.trace.api.ServiceHash; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.Tags; import java.io.UnsupportedEncodingException; @@ -22,6 +24,7 @@ public class SQLCommenter { private static final String DD_PEER_SERVICE = "ddprs"; private static final String DD_ENV = encode("dde"); private static final String DD_VERSION = encode("ddpv"); + private static final String DD_SERVICE_HASH = encode("ddsh"); private static final String TRACEPARENT = encode("traceparent"); private static final char EQUALS = '='; private static final char COMMA = ','; @@ -117,6 +120,10 @@ public static String inject( final String parentService = config.getServiceName(); final String env = config.getEnv(); final String version = config.getVersion(); + String containerTagsHash = ContainerInfo.get().getContainerTagsHash(); + final String serviceHash = + Long.toString(ServiceHash.getBaseHash(parentService, env, containerTagsHash)); + // config.isDbDbmInjectServiceHash() ; // TODO && baseHash != null final int commentSize = capacity(traceParent, parentService, dbService, env, version); StringBuilder sb = new StringBuilder(sql.length() + commentSize); boolean commentAdded = false; @@ -137,7 +144,8 @@ public static String inject( peerService, env, version, - traceParent); + traceParent, + serviceHash); sb.append(CLOSE_COMMENT); } else { sb.append(OPEN_COMMENT); @@ -152,7 +160,8 @@ public static String inject( peerService, env, version, - traceParent); + traceParent, + serviceHash); sb.append(CLOSE_COMMENT); sb.append(SPACE); @@ -226,9 +235,9 @@ protected static boolean toComment( final String peerService, final String env, final String version, - final String traceparent) { + final String traceparent, + final String serviceHash) { int emptySize = sb.length(); - append(sb, PARENT_SERVICE, parentService, false); append(sb, DATABASE_SERVICE, dbService, sb.length() > emptySize); append(sb, DD_HOSTNAME, hostname, sb.length() > emptySize); @@ -241,6 +250,8 @@ protected static boolean toComment( if (injectTrace) { append(sb, TRACEPARENT, traceparent, sb.length() > emptySize); } + // TODO only if DB_DBM_INJECT_SERVICE_HASH_ENABLED + append(sb, DD_SERVICE_HASH, serviceHash, sb.length() > emptySize); return sb.length() > emptySize; } diff --git a/dd-java-agent/instrumentation/jdbc/src/test/groovy/SQLCommenterTest.groovy b/dd-java-agent/instrumentation/jdbc/src/test/groovy/SQLCommenterTest.groovy index bb1119db1f1..c250d7416f2 100644 --- a/dd-java-agent/instrumentation/jdbc/src/test/groovy/SQLCommenterTest.groovy +++ b/dd-java-agent/instrumentation/jdbc/src/test/groovy/SQLCommenterTest.groovy @@ -2,9 +2,7 @@ import datadog.trace.agent.test.AgentTestRunner import datadog.trace.bootstrap.instrumentation.api.AgentSpan import datadog.trace.bootstrap.instrumentation.api.AgentTracer import datadog.trace.bootstrap.instrumentation.api.Tags - import datadog.trace.instrumentation.jdbc.SQLCommenter - import static datadog.trace.agent.test.utils.TraceUtils.runUnderTrace class SQLCommenterTest extends AgentTestRunner { @@ -30,7 +28,6 @@ class SQLCommenterTest extends AgentTestRunner { " " | "" } - def "test encode Sql Comment"() { setup: injectSysConfig("dd.service", ddService) @@ -38,17 +35,15 @@ class SQLCommenterTest extends AgentTestRunner { injectSysConfig("dd.version", ddVersion) when: - String sqlWithComment = "" + String sqlWithComment if (injectTrace) { sqlWithComment = SQLCommenter.inject(query, dbService, dbType, host, dbName, traceParent, true, appendComment) } else if (appendComment) { sqlWithComment = SQLCommenter.append(query, dbService, dbType, host, dbName) - } - else { + } else { sqlWithComment = SQLCommenter.prepend(query, dbService, dbType, host, dbName) } - then: sqlWithComment == expected diff --git a/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultPathwayContext.java b/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultPathwayContext.java index f05de107178..5573cf56bb8 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultPathwayContext.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultPathwayContext.java @@ -9,8 +9,7 @@ import com.datadoghq.sketch.ddsketch.encoding.VarEncodingHelper; import datadog.common.container.ContainerInfo; import datadog.context.propagation.CarrierVisitor; -import datadog.trace.api.Config; -import datadog.trace.api.ProcessTags; +import datadog.trace.api.ServiceHash; import datadog.trace.api.WellKnownTags; import datadog.trace.api.datastreams.DataStreamsContext; import datadog.trace.api.datastreams.DataStreamsTags; @@ -270,23 +269,7 @@ private static DefaultPathwayContext decode( } public static long getBaseHash(WellKnownTags wellKnownTags) { - StringBuilder builder = new StringBuilder(); - builder.append(wellKnownTags.getService()); - builder.append(wellKnownTags.getEnv()); - - String primaryTag = Config.get().getPrimaryTag(); - if (primaryTag != null) { - builder.append(primaryTag); - } - CharSequence processTags = ProcessTags.getTagsForSerialization(); - if (processTags != null) { - builder.append(processTags); - String containerTagsHash = ContainerInfo.get().getContainerTagsHash(); - if (containerTagsHash != null && !containerTagsHash.isEmpty()) { - builder.append(containerTagsHash); - } - } - return FNV64Hash.generateHash(builder.toString(), FNV64Hash.Version.v1); + return ServiceHash.getBaseHash(wellKnownTags, ContainerInfo.get().getContainerTagsHash()); } private long generatePathwayHash(long nodeHash, long parentHash) { diff --git a/internal-api/src/main/java/datadog/trace/api/ServiceHash.java b/internal-api/src/main/java/datadog/trace/api/ServiceHash.java new file mode 100644 index 00000000000..16ce6a7a367 --- /dev/null +++ b/internal-api/src/main/java/datadog/trace/api/ServiceHash.java @@ -0,0 +1,47 @@ +package datadog.trace.api; + +import datadog.trace.util.FNV64Hash; + +public final class ServiceHash { + + public static long getBaseHash(WellKnownTags wellKnownTags, String containerTagsHash) { + return getBaseHash( + wellKnownTags.getService(), + wellKnownTags.getEnv(), + Config.get().getPrimaryTag(), + ProcessTags.getTagsForSerialization(), + containerTagsHash); + } + + public static long getBaseHash( + CharSequence serviceName, CharSequence env, String containerTagsHash) { + return getBaseHash( + serviceName, + env, + Config.get().getPrimaryTag(), + ProcessTags.getTagsForSerialization(), + containerTagsHash); + } + + private static long getBaseHash( + CharSequence serviceName, + CharSequence env, + String primaryTag, + CharSequence processTags, + String containerTagsHash) { + StringBuilder builder = new StringBuilder(); + builder.append(serviceName); + builder.append(env); + + if (primaryTag != null) { + builder.append(primaryTag); + } + if (processTags != null) { + builder.append(processTags); + if (containerTagsHash != null && !containerTagsHash.isEmpty()) { + builder.append(containerTagsHash); + } + } + return FNV64Hash.generateHash(builder.toString(), FNV64Hash.Version.v1); + } +} From d199ffdaf1e93c7794f5214f85b0da2d4a07919d Mon Sep 17 00:00:00 2001 From: Yury Gribkov Date: Wed, 13 Aug 2025 11:58:43 -0700 Subject: [PATCH 03/12] Remove the useless benchmark that only measures adding strings to a string builder. --- .../instrumentation/jdbc/build.gradle | 5 --- .../jdbc/SQLCommenterBenchmark.java | 43 ------------------- 2 files changed, 48 deletions(-) delete mode 100644 dd-java-agent/instrumentation/jdbc/src/jmh/java/datadog/trace/instrumentation/jdbc/SQLCommenterBenchmark.java diff --git a/dd-java-agent/instrumentation/jdbc/build.gradle b/dd-java-agent/instrumentation/jdbc/build.gradle index dd5861a76f3..9fd8e2d6d8b 100644 --- a/dd-java-agent/instrumentation/jdbc/build.gradle +++ b/dd-java-agent/instrumentation/jdbc/build.gradle @@ -86,8 +86,3 @@ tasks.named("latestDepJava11Test").configure { tasks.withType(Test).configureEach { usesService(testcontainersLimit) } - -jmh { - jmhVersion = '1.28' - duplicateClassesStrategy = DuplicatesStrategy.EXCLUDE -} diff --git a/dd-java-agent/instrumentation/jdbc/src/jmh/java/datadog/trace/instrumentation/jdbc/SQLCommenterBenchmark.java b/dd-java-agent/instrumentation/jdbc/src/jmh/java/datadog/trace/instrumentation/jdbc/SQLCommenterBenchmark.java deleted file mode 100644 index 3331a26d906..00000000000 --- a/dd-java-agent/instrumentation/jdbc/src/jmh/java/datadog/trace/instrumentation/jdbc/SQLCommenterBenchmark.java +++ /dev/null @@ -1,43 +0,0 @@ -package datadog.trace.instrumentation.jdbc; - -import java.util.concurrent.TimeUnit; -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.BenchmarkMode; -import org.openjdk.jmh.annotations.Mode; -import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.State; - -@BenchmarkMode(Mode.AverageTime) -@OutputTimeUnit(TimeUnit.NANOSECONDS) -@State(Scope.Thread) -public class SQLCommenterBenchmark { - - private static final String traceParent = - "00-00000000000000007fffffffffffffff-000000024cb016ea-01"; - private static final String dbService = "users-db"; - private static final String hostname = "my-host"; - private static final String dbName = "credit-card-numbers"; - private static final String parentService = "parent"; - private static final String env = "env"; - private static final String version = "version"; - private static final String serviceHash = "service-hash"; - private static final boolean injectTrace = true; - - @Benchmark - public void testToComment() { - StringBuilder stringBuilder = new StringBuilder(); - SQLCommenter.toComment( - stringBuilder, - injectTrace, - parentService, - dbService, - hostname, - dbName, - null, - env, - version, - traceParent, - serviceHash); - } -} From 0e2880385b5ae21128b0bfb4cd07f0488cf100e9 Mon Sep 17 00:00:00 2001 From: Yury Gribkov Date: Wed, 13 Aug 2025 12:04:10 -0700 Subject: [PATCH 04/12] Clean up the unnecessary complexity of SQLCommenter and add a few fixes --- ...BMCompatibleConnectionInstrumentation.java | 14 +- .../instrumentation/jdbc/SQLCommenter.java | 263 ++++++++---------- .../jdbc/StatementInstrumentation.java | 3 +- .../src/test/groovy/SQLCommenterTest.groovy | 42 +-- 4 files changed, 126 insertions(+), 196 deletions(-) diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DBMCompatibleConnectionInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DBMCompatibleConnectionInstrumentation.java index da8ce96c444..c37546832c5 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DBMCompatibleConnectionInstrumentation.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DBMCompatibleConnectionInstrumentation.java @@ -116,7 +116,6 @@ public static String onEnter( if (callDepth > 0) { return null; } - final String inputSql = sql; final DBInfo dbInfo = JDBCDecorator.parseDBInfo( connection, InstrumentationContext.get(Connection.class, DBInfo.class)); @@ -125,16 +124,9 @@ public static String onEnter( dbService = traceConfig(activeSpan()).getServiceMapping().getOrDefault(dbService, dbService); } - if (dbInfo.getType().equals("sqlserver")) { // TODO why it's decided here? - sql = - SQLCommenter.append( - sql, dbService, dbInfo.getType(), dbInfo.getHost(), dbInfo.getDb()); - } else { - sql = - SQLCommenter.prepend( - sql, dbService, dbInfo.getType(), dbInfo.getHost(), dbInfo.getDb()); - } - return inputSql; + boolean append = "sqlserver".equals(dbInfo.getType()); + return SQLCommenter.inject( + sql, dbService, dbInfo.getType(), dbInfo.getHost(), dbInfo.getDb(), null, append); } return sql; } diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java index 208fe7d7566..30de8be5089 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java @@ -17,6 +17,17 @@ public class SQLCommenter { private static final Logger log = LoggerFactory.getLogger(SQLCommenter.class); private static final String UTF8 = StandardCharsets.UTF_8.toString(); + + private static final char EQUALS = '='; + private static final char COMMA = ','; + private static final char QUOTE = '\''; + private static final char SPACE = ' '; + private static final String OPEN_COMMENT = "/*"; + private static final int OPEN_COMMENT_LEN = OPEN_COMMENT.length(); + private static final String CLOSE_COMMENT = "*/"; + + // Injected fields. When adding a new one, be sure to update all the methods below. + private static final int NUMBER_OF_FIELDS = 9; private static final String PARENT_SERVICE = encode("ddps"); private static final String DATABASE_SERVICE = encode("dddbs"); private static final String DD_HOSTNAME = encode("ddh"); @@ -24,35 +35,12 @@ public class SQLCommenter { private static final String DD_PEER_SERVICE = "ddprs"; private static final String DD_ENV = encode("dde"); private static final String DD_VERSION = encode("ddpv"); - private static final String DD_SERVICE_HASH = encode("ddsh"); private static final String TRACEPARENT = encode("traceparent"); - private static final char EQUALS = '='; - private static final char COMMA = ','; - private static final char QUOTE = '\''; - private static final char SPACE = ' '; - private static final String OPEN_COMMENT = "/*"; - private static final String CLOSE_COMMENT = "*/"; - private static final int INITIAL_CAPACITY = computeInitialCapacity(); - - public static String append( - final String sql, - final String dbService, - final String dbType, - final String hostname, - final String dbName) { - return inject(sql, dbService, dbType, hostname, dbName, null, false, true); - } + private static final String DD_SERVICE_HASH = encode("ddsh"); - public static String prepend( - final String sql, - final String dbService, - final String dbType, - final String hostname, - final String dbName) { - return inject(sql, dbService, dbType, hostname, dbName, null, false, false); - } + private static final int INITIAL_CAPACITY = computeInitialCapacity(); - public static String getFirstWord(String sql) { + protected static String getFirstWord(String sql) { int beginIndex = 0; while (beginIndex < sql.length() && Character.isWhitespace(sql.charAt(beginIndex))) { beginIndex++; @@ -65,14 +53,14 @@ public static String getFirstWord(String sql) { } public static String inject( - final String sql, - final String dbService, - final String dbType, - final String hostname, - final String dbName, - final String traceParent, - final boolean injectTrace, - boolean appendComment) { + String sql, + String dbService, + String dbType, + String hostname, + String dbName, + String traceParent, + boolean preferAppend) { + boolean appendComment = preferAppend; if (sql == null || sql.isEmpty()) { return sql; } @@ -98,14 +86,13 @@ public static String inject( } // Both Postgres and MySQL are unhappy with anything before CALL in a stored - // procedure - // invocation but they seem ok with it after so we force append mode + // procedure invocation, but they seem ok with it after so we force append mode if (firstWord.equalsIgnoreCase("call")) { appendComment = true; } // Append the comment in the case of a pg_hint_plan extension - if (dbType.startsWith("postgres") && containsPgHint(sql)) { + if (dbType.startsWith("postgres") && sql.indexOf("/*+") > 0) { appendComment = true; } } @@ -124,52 +111,47 @@ public static String inject( final String serviceHash = Long.toString(ServiceHash.getBaseHash(parentService, env, containerTagsHash)); // config.isDbDbmInjectServiceHash() ; // TODO && baseHash != null - final int commentSize = capacity(traceParent, parentService, dbService, env, version); - StringBuilder sb = new StringBuilder(sql.length() + commentSize); - boolean commentAdded = false; String peerService = peerServiceObj != null ? peerServiceObj.toString() : null; + final int commentSize = + capacity( + parentService, + dbService, + hostname, + dbName, + peerService, + env, + version, + traceParent, + serviceHash); + StringBuilder sb = new StringBuilder(sql.length() + commentSize); + if (appendComment) { sb.append(sql); sb.append(SPACE); - sb.append(OPEN_COMMENT); - commentAdded = - toComment( - sb, - injectTrace, - parentService, - dbService, - hostname, - dbName, - peerService, - env, - version, - traceParent, - serviceHash); - sb.append(CLOSE_COMMENT); - } else { - sb.append(OPEN_COMMENT); - commentAdded = - toComment( - sb, - injectTrace, - parentService, - dbService, - hostname, - dbName, - peerService, - env, - version, - traceParent, - serviceHash); - - sb.append(CLOSE_COMMENT); - sb.append(SPACE); - sb.append(sql); } - if (!commentAdded) { + sb.append(OPEN_COMMENT); + int initSize = sb.length(); + append(sb, PARENT_SERVICE, parentService, initSize); + append(sb, DATABASE_SERVICE, dbService, initSize); + append(sb, DD_HOSTNAME, hostname, initSize); + append(sb, DD_DB_NAME, dbName, initSize); + append(sb, DD_PEER_SERVICE, peerService, initSize); + append(sb, DD_ENV, env, initSize); + append(sb, DD_VERSION, version, initSize); + append(sb, TRACEPARENT, traceParent, initSize); + // TODO only if DB_DBM_INJECT_SERVICE_HASH_ENABLED + // append(sb, DD_SERVICE_HASH, serviceHash, initSize); + if (initSize == sb.length()) { + // no comment was added + // TODO Is it even possible for all the fields to be unset? return sql; } + sb.append(CLOSE_COMMENT); + if (!appendComment) { + sb.append(SPACE); + sb.append(sql); + } return sb.toString(); } @@ -180,30 +162,22 @@ private static boolean hasDDComment(String sql, final boolean appendComment) { return false; } // else check to see if it's a DBM trace sql comment - int startIdx = 2; + int startIdx = OPEN_COMMENT_LEN; if (appendComment) { - startIdx = sql.lastIndexOf(OPEN_COMMENT) + 2; + startIdx = sql.lastIndexOf(OPEN_COMMENT) + OPEN_COMMENT_LEN; } int startComment = appendComment ? startIdx : sql.length(); - boolean found = false; - if (startComment > 2) { - if (hasMatchingSubstring(sql, startIdx, PARENT_SERVICE)) { - found = true; - } else if (hasMatchingSubstring(sql, startIdx, DATABASE_SERVICE)) { - found = true; - } else if (hasMatchingSubstring(sql, startIdx, DD_HOSTNAME)) { - found = true; - } else if (hasMatchingSubstring(sql, startIdx, DD_DB_NAME)) { - found = true; - } else if (hasMatchingSubstring(sql, startIdx, DD_ENV)) { - found = true; - } else if (hasMatchingSubstring(sql, startIdx, DD_VERSION)) { - found = true; - } else if (hasMatchingSubstring(sql, startIdx, TRACEPARENT)) { - found = true; - } - } - return found; + // TODO isn't the parent service always exits? if so there is no need to do other checks here + return startComment > OPEN_COMMENT_LEN + && (hasMatchingSubstring(sql, startIdx, PARENT_SERVICE) + || hasMatchingSubstring(sql, startIdx, DATABASE_SERVICE) + || hasMatchingSubstring(sql, startIdx, DD_HOSTNAME) + || hasMatchingSubstring(sql, startIdx, DD_DB_NAME) + || hasMatchingSubstring(sql, startIdx, DD_PEER_SERVICE) + || hasMatchingSubstring(sql, startIdx, DD_ENV) + || hasMatchingSubstring(sql, startIdx, DD_VERSION) + || hasMatchingSubstring(sql, startIdx, TRACEPARENT) + || hasMatchingSubstring(sql, startIdx, DD_SERVICE_HASH)); } private static boolean hasMatchingSubstring(String sql, int startIndex, String substring) { @@ -225,77 +199,64 @@ private static String encode(final String val) { return val; } - protected static boolean toComment( - StringBuilder sb, - final boolean injectTrace, - final String parentService, - final String dbService, - final String hostname, - final String dbName, - final String peerService, - final String env, - final String version, - final String traceparent, - final String serviceHash) { - int emptySize = sb.length(); - append(sb, PARENT_SERVICE, parentService, false); - append(sb, DATABASE_SERVICE, dbService, sb.length() > emptySize); - append(sb, DD_HOSTNAME, hostname, sb.length() > emptySize); - append(sb, DD_DB_NAME, dbName, sb.length() > emptySize); - if (peerService != null) { - append(sb, DD_PEER_SERVICE, peerService, sb.length() > emptySize); + private static void append(StringBuilder sb, String key, String value, int initSize) { + if (null == value || value.isEmpty()) { + return; } - append(sb, DD_ENV, env, sb.length() > emptySize); - append(sb, DD_VERSION, version, sb.length() > emptySize); - if (injectTrace) { - append(sb, TRACEPARENT, traceparent, sb.length() > emptySize); + String encodedValue; + try { + encodedValue = URLEncoder.encode(value, UTF8); + } catch (UnsupportedEncodingException e) { + if (log.isDebugEnabled()) { + log.debug("exception thrown while encoding sql comment %s", e); + } + return; } - // TODO only if DB_DBM_INJECT_SERVICE_HASH_ENABLED - append(sb, DD_SERVICE_HASH, serviceHash, sb.length() > emptySize); - return sb.length() > emptySize; - } - private static void append(StringBuilder sb, String key, String value, boolean prependComma) { - if (null != value && !value.isEmpty()) { - try { - if (prependComma) { - sb.append(COMMA); - } - sb.append(key); - sb.append(EQUALS); - sb.append(QUOTE); - sb.append(URLEncoder.encode(value, UTF8)); - sb.append(QUOTE); - } catch (UnsupportedEncodingException e) { - if (log.isDebugEnabled()) { - log.debug("exception thrown while encoding sql comment %s", e); - } - } + if (sb.length() > initSize) { + sb.append(COMMA); } + sb.append(key).append(EQUALS).append(QUOTE).append(encodedValue).append(QUOTE); } private static int capacity( - final String traceparent, final String parentService, final String dbService, + String hostname, + String dbName, + String peerService, final String env, - final String version) { + final String version, + final String traceparent, + String serviceHash) { int len = INITIAL_CAPACITY; - if (null != traceparent) { - len += traceparent.length(); - } if (null != parentService) { len += parentService.length(); } if (null != dbService) { len += dbService.length(); } + if (null != hostname) { + len += hostname.length(); + } + if (null != dbName) { + len += dbName.length(); + } + if (null != peerService) { + len += peerService.length(); + } if (null != env) { len += env.length(); } if (null != version) { len += version.length(); } + if (null != traceparent) { + len += traceparent.length(); + } + if (null != serviceHash) { + len += serviceHash.length(); + } return len; } @@ -305,19 +266,15 @@ private static int computeInitialCapacity() { + DATABASE_SERVICE.length() + DD_HOSTNAME.length() + DD_DB_NAME.length() + + DD_PEER_SERVICE.length() + DD_ENV.length() + DD_VERSION.length() - + TRACEPARENT.length(); + + TRACEPARENT.length() + + DD_SERVICE_HASH.length(); int extraCharsLen = - 4 * 5 + 4 * NUMBER_OF_FIELDS // two quotes, one equals & one comma * number of fields + OPEN_COMMENT.length() - + CLOSE_COMMENT.length(); // two quotes, one equals & one comma * 5 + \* */ + + CLOSE_COMMENT.length(); return tagKeysLen + extraCharsLen; } - - // pg_hint_plan extension works by checking the first block comment - // we'll have to append the traced comment if there is a pghint - private static boolean containsPgHint(String sql) { - return sql.indexOf("/*+") > 0; - } } diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java index 654d98dbed4..206e700fbda 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java @@ -134,8 +134,7 @@ public static AgentScope onEnter( dbInfo.getType(), dbInfo.getHost(), dbInfo.getDb(), - traceParent, - injectTraceInComment, + injectTraceInComment ? traceParent : null, appendComment); } DECORATE.onStatement(span, copy); diff --git a/dd-java-agent/instrumentation/jdbc/src/test/groovy/SQLCommenterTest.groovy b/dd-java-agent/instrumentation/jdbc/src/test/groovy/SQLCommenterTest.groovy index c250d7416f2..6a115bd740d 100644 --- a/dd-java-agent/instrumentation/jdbc/src/test/groovy/SQLCommenterTest.groovy +++ b/dd-java-agent/instrumentation/jdbc/src/test/groovy/SQLCommenterTest.groovy @@ -35,14 +35,7 @@ class SQLCommenterTest extends AgentTestRunner { injectSysConfig("dd.version", ddVersion) when: - String sqlWithComment - if (injectTrace) { - sqlWithComment = SQLCommenter.inject(query, dbService, dbType, host, dbName, traceParent, true, appendComment) - } else if (appendComment) { - sqlWithComment = SQLCommenter.append(query, dbService, dbType, host, dbName) - } else { - sqlWithComment = SQLCommenter.prepend(query, dbService, dbType, host, dbName) - } + String sqlWithComment = SQLCommenter.inject(query, dbService, dbType, host, dbName, injectTrace ? traceParent : null, appendComment) then: sqlWithComment == expected @@ -65,8 +58,8 @@ class SQLCommenterTest extends AgentTestRunner { "SELECT * from FOO -- test query" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-01" | "SELECT * from FOO -- test query /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-01'*/" "SELECT /* customer-comment */ * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-01" | "SELECT /* customer-comment */ * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-01'*/" "SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | true | null | "SELECT * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/" - "SELECT * FROM DUAL" | "SqlCommenter" | "Test" | "my-service" | "oracle" | "h" | "n" | "TestVersion" | false | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "SELECT * FROM DUAL /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/" - "SELECT * FROM sys.tables" | "SqlCommenter" | "Test" | "my-service" | "sqlserver"| "h" | "n" | "TestVersion" | false | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "SELECT * FROM sys.tables /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/" + "SELECT * FROM DUAL" | "SqlCommenter" | "Test" | "my-service" | "oracle" | "h" | "n" | "TestVersion" | false | true | null | "SELECT * FROM DUAL /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/" + "SELECT * FROM sys.tables" | "SqlCommenter" | "Test" | "my-service" | "sqlserver"| "h" | "n" | "TestVersion" | false | true | null | "SELECT * FROM sys.tables /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/" "SELECT /* customer-comment */ * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | true | null | "SELECT /* customer-comment */ * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/" "SELECT * from FOO -- test query" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | true | null | "SELECT * from FOO -- test query /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/" "" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "" @@ -111,35 +104,24 @@ class SQLCommenterTest extends AgentTestRunner { def "test encode Sql Comment with peer service"() { setup: - injectSysConfig("dd.service", ddService) - injectSysConfig("dd.env", ddEnv) - injectSysConfig("dd.version", ddVersion) + injectSysConfig("dd.service", "SqlCommenter") + injectSysConfig("dd.env", "Test") + injectSysConfig("dd.version", "TestVersion") when: - String sqlWithComment = "" - runUnderTrace("testTrace"){ + String sqlWithComment = runUnderTrace("testTrace") { AgentSpan currSpan = AgentTracer.activeSpan() currSpan.setTag(Tags.PEER_SERVICE, peerService) - - if (injectTrace) { - sqlWithComment = SQLCommenter.inject(query, dbService, dbType, host, dbName, traceParent, true, appendComment) - } - else if (appendComment) { - sqlWithComment = SQLCommenter.append(query, dbService, dbType, host, dbName) - } - else { - sqlWithComment = SQLCommenter.prepend(query, dbService, dbType, host, dbName) - } + return SQLCommenter.inject("SELECT * FROM foo", "my-service", dbType, "h", "n", "00-00000000000000007fffffffffffffff-000000024cb016ea-00", true) } then: sqlWithComment == expected where: - query | ddService | ddEnv | dbService | dbType | host | dbName | ddVersion | injectTrace | appendComment | traceParent | peerService | expected - "SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "" | "SELECT * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" - "SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "postgres" | "h" | "n" | "TestVersion" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "" | "SELECT * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" - "SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "testPeer" | "SELECT * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',ddprs='testPeer',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" - "SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "postgres" | "h" | "n" | "TestVersion" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "testPeer" | "SELECT * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',ddprs='testPeer',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" + dbType | peerService | expected + "mysql" | null | "SELECT * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" + "postgres" | "" | "SELECT * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" + "postgres" | "testPeer" | "SELECT * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',ddprs='testPeer',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" } } From bc7eefb54f106b967fc80d9a5c6bd9375c11ba71 Mon Sep 17 00:00:00 2001 From: Yury Gribkov Date: Wed, 13 Aug 2025 13:32:44 -0700 Subject: [PATCH 05/12] Use the predefined comment buffer capacity instead of calculating it each time. --- .../instrumentation/jdbc/SQLCommenter.java | 79 ++----------------- 1 file changed, 7 insertions(+), 72 deletions(-) diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java index 30de8be5089..b2edc94c757 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java @@ -38,7 +38,12 @@ public class SQLCommenter { private static final String TRACEPARENT = encode("traceparent"); private static final String DD_SERVICE_HASH = encode("ddsh"); - private static final int INITIAL_CAPACITY = computeInitialCapacity(); + private static final int KEY_AND_SEPARATORS_ESTIMATED_SIZE = 10; + private static final int VALUE_ESTIMATED_SIZE = 10; + private static final int TRACE_PARENT_EXTRA_ESTIMATED_SIZE = 50; + private static final int INJECTED_COMMENT_ESTIMATED_SIZE = + NUMBER_OF_FIELDS * (KEY_AND_SEPARATORS_ESTIMATED_SIZE + VALUE_ESTIMATED_SIZE) + + TRACE_PARENT_EXTRA_ESTIMATED_SIZE; protected static String getFirstWord(String sql) { int beginIndex = 0; @@ -113,18 +118,7 @@ public static String inject( // config.isDbDbmInjectServiceHash() ; // TODO && baseHash != null String peerService = peerServiceObj != null ? peerServiceObj.toString() : null; - final int commentSize = - capacity( - parentService, - dbService, - hostname, - dbName, - peerService, - env, - version, - traceParent, - serviceHash); - StringBuilder sb = new StringBuilder(sql.length() + commentSize); + StringBuilder sb = new StringBuilder(sql.length() + INJECTED_COMMENT_ESTIMATED_SIZE); if (appendComment) { sb.append(sql); @@ -218,63 +212,4 @@ private static void append(StringBuilder sb, String key, String value, int initS } sb.append(key).append(EQUALS).append(QUOTE).append(encodedValue).append(QUOTE); } - - private static int capacity( - final String parentService, - final String dbService, - String hostname, - String dbName, - String peerService, - final String env, - final String version, - final String traceparent, - String serviceHash) { - int len = INITIAL_CAPACITY; - if (null != parentService) { - len += parentService.length(); - } - if (null != dbService) { - len += dbService.length(); - } - if (null != hostname) { - len += hostname.length(); - } - if (null != dbName) { - len += dbName.length(); - } - if (null != peerService) { - len += peerService.length(); - } - if (null != env) { - len += env.length(); - } - if (null != version) { - len += version.length(); - } - if (null != traceparent) { - len += traceparent.length(); - } - if (null != serviceHash) { - len += serviceHash.length(); - } - return len; - } - - private static int computeInitialCapacity() { - int tagKeysLen = - PARENT_SERVICE.length() - + DATABASE_SERVICE.length() - + DD_HOSTNAME.length() - + DD_DB_NAME.length() - + DD_PEER_SERVICE.length() - + DD_ENV.length() - + DD_VERSION.length() - + TRACEPARENT.length() - + DD_SERVICE_HASH.length(); - int extraCharsLen = - 4 * NUMBER_OF_FIELDS // two quotes, one equals & one comma * number of fields - + OPEN_COMMENT.length() - + CLOSE_COMMENT.length(); - return tagKeysLen + extraCharsLen; - } } From 1992f1430030ef9f84d24a92500ec5062b2667a5 Mon Sep 17 00:00:00 2001 From: Yury Gribkov Date: Wed, 13 Aug 2025 15:58:18 -0700 Subject: [PATCH 06/12] Fix the check to see if a comment has already been injected. Clean up hasDDComment. --- .../instrumentation/jdbc/SQLCommenter.java | 36 +++-- .../src/test/groovy/SQLCommenterTest.groovy | 126 +++++++++--------- 2 files changed, 81 insertions(+), 81 deletions(-) diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java index b2edc94c757..039eabde330 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java @@ -69,10 +69,6 @@ public static String inject( if (sql == null || sql.isEmpty()) { return sql; } - if (hasDDComment(sql, appendComment)) { - return sql; - } - if (dbType != null) { final String firstWord = getFirstWord(sql); @@ -97,10 +93,13 @@ public static String inject( } // Append the comment in the case of a pg_hint_plan extension - if (dbType.startsWith("postgres") && sql.indexOf("/*+") > 0) { + if (dbType.startsWith("postgres") && sql.contains("/*+")) { appendComment = true; } } + if (hasDDComment(sql, appendComment)) { + return sql; + } AgentSpan currSpan = activeSpan(); Object peerServiceObj = null; @@ -150,28 +149,23 @@ public static String inject( } private static boolean hasDDComment(String sql, final boolean appendComment) { - // first check to see if sql ends with a comment if ((!(sql.endsWith(CLOSE_COMMENT)) && appendComment) || ((!(sql.startsWith(OPEN_COMMENT))) && !appendComment)) { return false; } - // else check to see if it's a DBM trace sql comment int startIdx = OPEN_COMMENT_LEN; if (appendComment) { - startIdx = sql.lastIndexOf(OPEN_COMMENT) + OPEN_COMMENT_LEN; - } - int startComment = appendComment ? startIdx : sql.length(); - // TODO isn't the parent service always exits? if so there is no need to do other checks here - return startComment > OPEN_COMMENT_LEN - && (hasMatchingSubstring(sql, startIdx, PARENT_SERVICE) - || hasMatchingSubstring(sql, startIdx, DATABASE_SERVICE) - || hasMatchingSubstring(sql, startIdx, DD_HOSTNAME) - || hasMatchingSubstring(sql, startIdx, DD_DB_NAME) - || hasMatchingSubstring(sql, startIdx, DD_PEER_SERVICE) - || hasMatchingSubstring(sql, startIdx, DD_ENV) - || hasMatchingSubstring(sql, startIdx, DD_VERSION) - || hasMatchingSubstring(sql, startIdx, TRACEPARENT) - || hasMatchingSubstring(sql, startIdx, DD_SERVICE_HASH)); + startIdx += sql.lastIndexOf(OPEN_COMMENT); + } + return hasMatchingSubstring(sql, startIdx, PARENT_SERVICE) + || hasMatchingSubstring(sql, startIdx, DATABASE_SERVICE) + || hasMatchingSubstring(sql, startIdx, DD_HOSTNAME) + || hasMatchingSubstring(sql, startIdx, DD_DB_NAME) + || hasMatchingSubstring(sql, startIdx, DD_PEER_SERVICE) + || hasMatchingSubstring(sql, startIdx, DD_ENV) + || hasMatchingSubstring(sql, startIdx, DD_VERSION) + || hasMatchingSubstring(sql, startIdx, TRACEPARENT) + || hasMatchingSubstring(sql, startIdx, DD_SERVICE_HASH); } private static boolean hasMatchingSubstring(String sql, int startIndex, String substring) { diff --git a/dd-java-agent/instrumentation/jdbc/src/test/groovy/SQLCommenterTest.groovy b/dd-java-agent/instrumentation/jdbc/src/test/groovy/SQLCommenterTest.groovy index 6a115bd740d..96b42439c54 100644 --- a/dd-java-agent/instrumentation/jdbc/src/test/groovy/SQLCommenterTest.groovy +++ b/dd-java-agent/instrumentation/jdbc/src/test/groovy/SQLCommenterTest.groovy @@ -35,71 +35,77 @@ class SQLCommenterTest extends AgentTestRunner { injectSysConfig("dd.version", ddVersion) when: - String sqlWithComment = SQLCommenter.inject(query, dbService, dbType, host, dbName, injectTrace ? traceParent : null, appendComment) + String sqlWithComment = SQLCommenter.inject(query, dbService, dbType, host, dbName, traceParent, append) then: sqlWithComment == expected where: - query | ddService | ddEnv | dbService | dbType | host | dbName | ddVersion | injectTrace | appendComment | traceParent | expected - "SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "SELECT * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" - "SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "postgres" | "h" | "n" | "TestVersion" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "SELECT * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" - "{call dogshelterProc(?, ?)}" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "{call dogshelterProc(?, ?)} /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" - "{call dogshelterProc(?, ?)}" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "{call dogshelterProc(?, ?)} /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" - "{call dogshelterProc(?, ?)}" | "SqlCommenter" | "Test" | "my-service" | "postgres" | "h" | "n" | "TestVersion" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "{call dogshelterProc(?, ?)}" - "CALL dogshelterProc(?, ?)" | "SqlCommenter" | "Test" | "my-service" | "postgres" | "h" | "n" | "TestVersion" | true | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "CALL dogshelterProc(?, ?) /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" - "CALL dogshelterProc(?, ?)" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "CALL dogshelterProc(?, ?) /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" - "SELECT * FROM foo" | "" | "Test" | "" | "mysql" | "h" | "n" | "TestVersion" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "SELECT * FROM foo /*ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" - "SELECT * FROM foo" | "" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "SELECT * FROM foo /*dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" - "SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "" | "" | "TestVersion" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "SELECT * FROM foo /*ddps='SqlCommenter',dddbs='my-service',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" - "SELECT * FROM foo" | "" | "Test" | "" | "" | "h" | "n" | "" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "SELECT * FROM foo /*ddh='h',dddb='n',dde='Test',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" - "SELECT * FROM foo" | "" | "" | "" | "" | "h" | "n" | "" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "SELECT * FROM foo /*ddh='h',dddb='n',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" - "SELECT * FROM foo" | "" | "" | "" | "" | "" | "" | "" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "SELECT * FROM foo /*traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" - "SELECT * from FOO -- test query" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-01" | "SELECT * from FOO -- test query /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-01'*/" - "SELECT /* customer-comment */ * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-01" | "SELECT /* customer-comment */ * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-01'*/" - "SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | true | null | "SELECT * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/" - "SELECT * FROM DUAL" | "SqlCommenter" | "Test" | "my-service" | "oracle" | "h" | "n" | "TestVersion" | false | true | null | "SELECT * FROM DUAL /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/" - "SELECT * FROM sys.tables" | "SqlCommenter" | "Test" | "my-service" | "sqlserver"| "h" | "n" | "TestVersion" | false | true | null | "SELECT * FROM sys.tables /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/" - "SELECT /* customer-comment */ * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | true | null | "SELECT /* customer-comment */ * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/" - "SELECT * from FOO -- test query" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | true | null | "SELECT * from FOO -- test query /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/" - "" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "" - " " | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-01" | " /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-01'*/" - "" | "SqlCommenter" | "Test" | "postgres" | "mysql" | "h" | "n" | "TestVersion" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "" - " " | "SqlCommenter" | "Test" | "postgres" | "mysql" | "h" | "n" | "TestVersion" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-01" | " /*ddps='SqlCommenter',dddbs='postgres',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-01'*/" - "SELECT * FROM foo /*dddbs='my-service',ddh='h',dddb='n',dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | true | null | "SELECT * FROM foo /*dddbs='my-service',ddh='h',dddb='n',dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/" - "SELECT * FROM foo /*ddh='h',dddb='n',dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | true | null | "SELECT * FROM foo /*ddh='h',dddb='n',dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/" - "SELECT * FROM foo /*dddb='n',dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | true | null | "SELECT * FROM foo /*dddb='n',dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/" - "SELECT * FROM foo /*dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | true | null | "SELECT * FROM foo /*dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/" - "SELECT * FROM foo /*ddps='SqlCommenter',ddpv='TestVersion'*/" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | true | null | "SELECT * FROM foo /*ddps='SqlCommenter',ddpv='TestVersion'*/" - "SELECT * FROM foo /*ddpv='TestVersion'*/" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | true | null | "SELECT * FROM foo /*ddpv='TestVersion'*/" - "/*ddjk its a customer */ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | true | null | "/*ddjk its a customer */ SELECT * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/" - "SELECT * FROM foo /*traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-01'*/" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | true | null | "SELECT * FROM foo /*traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-01'*/" - "/*customer-comment*/ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | true | null | "/*customer-comment*/ SELECT * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/" - "/*traceparent" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | true | null | "/*traceparent /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/" - "SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "/*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/ SELECT * FROM foo" - "SELECT * FROM foo" | "" | "Test" | "" | "mysql" | "h" | "n" | "TestVersion" | true | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "/*ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/ SELECT * FROM foo" - "SELECT * FROM foo" | "" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "/*dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/ SELECT * FROM foo" - "SELECT * FROM foo" | "" | "Test" | "" | "" | "h" | "n" | "" | true | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "/*ddh='h',dddb='n',dde='Test',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/ SELECT * FROM foo" - "SELECT * FROM foo" | "" | "" | "" | "" | "" | "" | "" | true | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "/*traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/ SELECT * FROM foo" - "SELECT * from FOO -- test query" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-01" | "/*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-01'*/ SELECT * from FOO -- test query" - "SELECT /* customer-comment */ * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-01" | "/*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-01'*/ SELECT /* customer-comment */ * FROM foo" - "SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | false | null | "/*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/ SELECT * FROM foo" - "SELECT /* customer-comment */ * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | false | null | "/*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/ SELECT /* customer-comment */ * FROM foo" - "SELECT * from FOO -- test query" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | false | null | "/*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/ SELECT * from FOO -- test query" - "" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "" - " " | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-01" | "/*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-01'*/ " - "/*dddbs='my-service',ddh='h',dddb='n',dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | false | null | "/*dddbs='my-service',ddh='h',dddb='n',dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/ SELECT * FROM foo" - "/*ddh='h',dddb='n',dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | false | null | "/*ddh='h',dddb='n',dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/ SELECT * FROM foo" - "/*dddb='n',dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | false | null | "/*dddb='n',dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/ SELECT * FROM foo" - "/*dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | false | null | "/*dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/ SELECT * FROM foo" - "/*ddps='SqlCommenter',ddpv='TestVersion'*/ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | false | null | "/*ddps='SqlCommenter',ddpv='TestVersion'*/ SELECT * FROM foo" - "/*ddpv='TestVersion'*/ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | false | null | "/*ddpv='TestVersion'*/ SELECT * FROM foo" - "/*ddjk its a customer */ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | false | null | "/*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/ /*ddjk its a customer */ SELECT * FROM foo" - "/*traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-01'*/ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | false | null | "/*traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-01'*/ SELECT * FROM foo" - "/*customer-comment*/ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | false | null | "/*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/ /*customer-comment*/ SELECT * FROM foo" - "/*traceparent" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | false | null | "/*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/ /*traceparent" - "SELECT /*+ SeqScan(foo) */ * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "postgres" | "h" | "n" | "TestVersion" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "SELECT /*+ SeqScan(foo) */ * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" - "/*+ SeqScan(foo) */ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "postgres" | "h" | "n" | "TestVersion" | true | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "/*+ SeqScan(foo) */ SELECT * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" + query | ddService | ddEnv | dbService | dbType | host | dbName | ddVersion | append | traceParent | expected + "SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "SELECT * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" + "SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "postgres" | "h" | "n" | "TestVersion" | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "SELECT * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" + "{call dogshelterProc(?, ?)}" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "{call dogshelterProc(?, ?)} /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" + "{call dogshelterProc(?, ?)}" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "{call dogshelterProc(?, ?)} /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" + "{call dogshelterProc(?, ?)}" | "SqlCommenter" | "Test" | "my-service" | "postgres" | "h" | "n" | "TestVersion" | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "{call dogshelterProc(?, ?)}" + "CALL dogshelterProc(?, ?)" | "SqlCommenter" | "Test" | "my-service" | "postgres" | "h" | "n" | "TestVersion" | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "CALL dogshelterProc(?, ?) /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" + "CALL dogshelterProc(?, ?)" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "CALL dogshelterProc(?, ?) /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" + "SELECT * FROM foo" | "" | "Test" | "" | "mysql" | "h" | "n" | "TestVersion" | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "SELECT * FROM foo /*ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" + "SELECT * FROM foo" | "" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "SELECT * FROM foo /*dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" + "SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "" | "" | "TestVersion" | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "SELECT * FROM foo /*ddps='SqlCommenter',dddbs='my-service',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" + "SELECT * FROM foo" | "" | "Test" | "" | "" | "h" | "n" | "" | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "SELECT * FROM foo /*ddh='h',dddb='n',dde='Test',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" + "SELECT * FROM foo" | "" | "" | "" | "" | "h" | "n" | "" | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "SELECT * FROM foo /*ddh='h',dddb='n',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" + "SELECT * FROM foo" | "" | "" | "" | "" | "" | "" | "" | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "SELECT * FROM foo /*traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" + "SELECT * from FOO -- test query" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-01" | "SELECT * from FOO -- test query /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-01'*/" + "SELECT /* customer-comment */ * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-01" | "SELECT /* customer-comment */ * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-01'*/" + "SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | null | "SELECT * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/" + "SELECT * FROM DUAL" | "SqlCommenter" | "Test" | "my-service" | "oracle" | "h" | "n" | "TestVersion" | true | null | "SELECT * FROM DUAL /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/" + "SELECT * FROM sys.tables" | "SqlCommenter" | "Test" | "my-service" | "sqlserver"| "h" | "n" | "TestVersion" | true | null | "SELECT * FROM sys.tables /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/" + "SELECT /* customer-comment */ * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | null | "SELECT /* customer-comment */ * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/" + "SELECT * from FOO -- test query" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | null | "SELECT * from FOO -- test query /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/" + "" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "" + " " | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-01" | " /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-01'*/" + "" | "SqlCommenter" | "Test" | "postgres" | "mysql" | "h" | "n" | "TestVersion" | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "" + " " | "SqlCommenter" | "Test" | "postgres" | "mysql" | "h" | "n" | "TestVersion" | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-01" | " /*ddps='SqlCommenter',dddbs='postgres',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-01'*/" + "SELECT * FROM foo /*dddbs='my-service',ddh='h',dddb='n',dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | null | "SELECT * FROM foo /*dddbs='my-service',ddh='h',dddb='n',dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/" + "SELECT * FROM foo /*ddh='h',dddb='n',dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | null | "SELECT * FROM foo /*ddh='h',dddb='n',dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/" + "SELECT * FROM foo /*dddb='n',dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | null | "SELECT * FROM foo /*dddb='n',dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/" + "SELECT * FROM foo /*dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | null | "SELECT * FROM foo /*dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/" + "SELECT * FROM foo /*ddps='SqlCommenter',ddpv='TestVersion'*/" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | null | "SELECT * FROM foo /*ddps='SqlCommenter',ddpv='TestVersion'*/" + "SELECT * FROM foo /*ddpv='TestVersion'*/" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | null | "SELECT * FROM foo /*ddpv='TestVersion'*/" + "/*ddjk its a customer */ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | null | "/*ddjk its a customer */ SELECT * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/" + "SELECT * FROM foo /*traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-01'*/" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | null | "SELECT * FROM foo /*traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-01'*/" + "/*customer-comment*/ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | null | "/*customer-comment*/ SELECT * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/" + "/*traceparent" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | true | null | "/*traceparent /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/" + "SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "/*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/ SELECT * FROM foo" + "SELECT * FROM foo" | "" | "Test" | "" | "mysql" | "h" | "n" | "TestVersion" | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "/*ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/ SELECT * FROM foo" + "SELECT * FROM foo" | "" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "/*dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/ SELECT * FROM foo" + "SELECT * FROM foo" | "" | "Test" | "" | "" | "h" | "n" | "" | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "/*ddh='h',dddb='n',dde='Test',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/ SELECT * FROM foo" + "SELECT * FROM foo" | "" | "" | "" | "" | "" | "" | "" | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "/*traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/ SELECT * FROM foo" + "SELECT * from FOO -- test query" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-01" | "/*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-01'*/ SELECT * from FOO -- test query" + "SELECT /* customer-comment */ * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-01" | "/*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-01'*/ SELECT /* customer-comment */ * FROM foo" + "SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | null | "/*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/ SELECT * FROM foo" + "SELECT /* customer-comment */ * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | null | "/*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/ SELECT /* customer-comment */ * FROM foo" + "SELECT * from FOO -- test query" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | null | "/*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/ SELECT * from FOO -- test query" + "" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "" + " " | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-01" | "/*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-01'*/ " + "/*dddbs='my-service',ddh='h',dddb='n',dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | null | "/*dddbs='my-service',ddh='h',dddb='n',dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/ SELECT * FROM foo" + "/*ddh='h',dddb='n',dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | null | "/*ddh='h',dddb='n',dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/ SELECT * FROM foo" + "/*dddb='n',dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | null | "/*dddb='n',dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/ SELECT * FROM foo" + "/*dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | null | "/*dde='Test',ddps='SqlCommenter',ddpv='TestVersion'*/ SELECT * FROM foo" + "/*ddps='SqlCommenter',ddpv='TestVersion'*/ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | null | "/*ddps='SqlCommenter',ddpv='TestVersion'*/ SELECT * FROM foo" + "/*ddpv='TestVersion'*/ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | null | "/*ddpv='TestVersion'*/ SELECT * FROM foo" + "/*ddjk its a customer */ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | null | "/*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/ /*ddjk its a customer */ SELECT * FROM foo" + "/*traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-01'*/ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | null | "/*traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-01'*/ SELECT * FROM foo" + "/*customer-comment*/ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | null | "/*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/ /*customer-comment*/ SELECT * FROM foo" + "/*traceparent" | "SqlCommenter" | "Test" | "my-service" | "mysql" | "h" | "n" | "TestVersion" | false | null | "/*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion'*/ /*traceparent" + "SELECT /*+ SeqScan(foo) */ * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "postgres" | "h" | "n" | "TestVersion" | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "SELECT /*+ SeqScan(foo) */ * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" + "/*+ SeqScan(foo) */ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "postgres" | "h" | "n" | "TestVersion" | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "/*+ SeqScan(foo) */ SELECT * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" + "/*+ SeqScan(foo) */ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "postgres" | "h" | "n" | "TestVersion" | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "/*+ SeqScan(foo) */ SELECT * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" + "/*+ SeqScan(foo) */ SELECT * FROM foo" | "SqlCommenter" | "Test" | "my-service" | "postgres" | "h" | "n" | "TestVersion" | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "/*+ SeqScan(foo) */ SELECT * FROM foo /*ddps='SqlCommenter',dddbs='my-service',ddh='h',dddb='n',dde='Test',ddpv='TestVersion',traceparent='00-00000000000000007fffffffffffffff-000000024cb016ea-00'*/" + "/*+ SeqScan(foo) */ SELECT * FROM foo /*ddps=''*/" | "SqlCommenter" | "Test" | "my-service" | "postgres" | "h" | "n" | "TestVersion" | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "/*+ SeqScan(foo) */ SELECT * FROM foo /*ddps=''*/" + "/*+ SeqScan(foo) */ SELECT * FROM foo /*ddps=''*/" | "SqlCommenter" | "Test" | "my-service" | "postgres" | "h" | "n" | "TestVersion" | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "/*+ SeqScan(foo) */ SELECT * FROM foo /*ddps=''*/" + "CALL dogshelterProc(?, ?) /*ddps=''*/" | "SqlCommenter" | "Test" | "my-service" | "postgres" | "h" | "n" | "TestVersion" | false | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "CALL dogshelterProc(?, ?) /*ddps=''*/" + "CALL dogshelterProc(?, ?) /*ddps=''*/" | "SqlCommenter" | "Test" | "my-service" | "postgres" | "h" | "n" | "TestVersion" | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "CALL dogshelterProc(?, ?) /*ddps=''*/" } def "test encode Sql Comment with peer service"() { From e0a0a1a371cfab3bc321fb4d9cffe640cad5f29b Mon Sep 17 00:00:00 2001 From: Yury Gribkov Date: Wed, 13 Aug 2025 16:57:09 -0700 Subject: [PATCH 07/12] Preallocate string builder in bash hash calc --- .../java/datadog/trace/instrumentation/jdbc/SQLCommenter.java | 3 +-- internal-api/src/main/java/datadog/trace/api/ServiceHash.java | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java index 039eabde330..5ff6c817025 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java @@ -14,7 +14,6 @@ import org.slf4j.LoggerFactory; public class SQLCommenter { - private static final Logger log = LoggerFactory.getLogger(SQLCommenter.class); private static final String UTF8 = StandardCharsets.UTF_8.toString(); @@ -26,7 +25,7 @@ public class SQLCommenter { private static final int OPEN_COMMENT_LEN = OPEN_COMMENT.length(); private static final String CLOSE_COMMENT = "*/"; - // Injected fields. When adding a new one, be sure to update all the methods below. + // Injected fields. When adding a new one, be sure to update this and the methods below. private static final int NUMBER_OF_FIELDS = 9; private static final String PARENT_SERVICE = encode("ddps"); private static final String DATABASE_SERVICE = encode("dddbs"); diff --git a/internal-api/src/main/java/datadog/trace/api/ServiceHash.java b/internal-api/src/main/java/datadog/trace/api/ServiceHash.java index 16ce6a7a367..4a87f1db21e 100644 --- a/internal-api/src/main/java/datadog/trace/api/ServiceHash.java +++ b/internal-api/src/main/java/datadog/trace/api/ServiceHash.java @@ -29,7 +29,7 @@ private static long getBaseHash( String primaryTag, CharSequence processTags, String containerTagsHash) { - StringBuilder builder = new StringBuilder(); + StringBuilder builder = new StringBuilder(64); builder.append(serviceName); builder.append(env); From b27ca850360908ca5548070fd225b7680e5ebe94 Mon Sep 17 00:00:00 2001 From: Yury Gribkov Date: Thu, 14 Aug 2025 15:01:29 -0700 Subject: [PATCH 08/12] Introduce DB_DBM_INJECT_SQL_BASEHASH --- .../instrumentation/jdbc/JDBCDecorator.java | 8 +-- .../instrumentation/jdbc/SQLCommenter.java | 58 +++++++++-------- .../src/test/groovy/SQLCommenterTest.groovy | 41 ++++++++++++ .../config/TraceInstrumentationConfig.java | 2 +- .../DefaultDataStreamsMonitoring.java | 8 ++- .../datastreams/DefaultPathwayContext.java | 7 --- .../DefaultPathwayContextTest.groovy | 60 ------------------ .../api/{ServiceHash.java => BaseHash.java} | 11 +--- .../main/java/datadog/trace/api/Config.java | 34 ++++++---- .../java/datadog/trace/api/ProcessTags.java | 4 ++ .../datadog/trace/api/BaseHashTest.groovy | 62 +++++++++++++++++++ 11 files changed, 173 insertions(+), 122 deletions(-) rename internal-api/src/main/java/datadog/trace/api/{ServiceHash.java => BaseHash.java} (74%) create mode 100644 internal-api/src/test/groovy/datadog/trace/api/BaseHashTest.groovy 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 6c8e3b0651c..7acbb038426 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 @@ -51,14 +51,14 @@ public class JDBCDecorator extends DatabaseClientDecorator { public static final String DD_INSTRUMENTATION_PREFIX = "_DD_"; - public static final String DBM_PROPAGATION_MODE = Config.get().getDBMPropagationMode(); + public static final String DBM_PROPAGATION_MODE = Config.get().getDbmPropagationMode(); public static final boolean INJECT_COMMENT = DBM_PROPAGATION_MODE.equals(DBM_PROPAGATION_MODE_FULL) || DBM_PROPAGATION_MODE.equals(DBM_PROPAGATION_MODE_STATIC); private static final boolean INJECT_TRACE_CONTEXT = DBM_PROPAGATION_MODE.equals(DBM_PROPAGATION_MODE_FULL); public static final boolean DBM_TRACE_PREPARED_STATEMENTS = - Config.get().isDBMTracePreparedStatements(); + Config.get().isDbmTracePreparedStatements(); private volatile boolean warnedAboutDBMPropagationMode = false; // to log a warning only once @@ -420,7 +420,7 @@ public boolean shouldInjectTraceContext(DBInfo dbInfo) { } public boolean shouldInjectSQLComment() { - return Config.get().getDBMPropagationMode().equals(DBM_PROPAGATION_MODE_FULL) - || Config.get().getDBMPropagationMode().equals(DBM_PROPAGATION_MODE_STATIC); + return Config.get().getDbmPropagationMode().equals(DBM_PROPAGATION_MODE_FULL) + || Config.get().getDbmPropagationMode().equals(DBM_PROPAGATION_MODE_STATIC); } } diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java index 5ff6c817025..360155b567a 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java @@ -3,8 +3,9 @@ import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; import datadog.common.container.ContainerInfo; +import datadog.trace.api.BaseHash; import datadog.trace.api.Config; -import datadog.trace.api.ServiceHash; +import datadog.trace.api.ProcessTags; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.Tags; import java.io.UnsupportedEncodingException; @@ -64,10 +65,10 @@ public static String inject( String dbName, String traceParent, boolean preferAppend) { - boolean appendComment = preferAppend; if (sql == null || sql.isEmpty()) { return sql; } + boolean appendComment = preferAppend; if (dbType != null) { final String firstWord = getFirstWord(sql); @@ -100,24 +101,20 @@ public static String inject( return sql; } - AgentSpan currSpan = activeSpan(); - Object peerServiceObj = null; - if (currSpan != null) { - peerServiceObj = currSpan.getTag(Tags.PEER_SERVICE); - } - - final Config config = Config.get(); - final String parentService = config.getServiceName(); - final String env = config.getEnv(); - final String version = config.getVersion(); + Config config = Config.get(); + String parentService = config.getServiceName(); + String env = config.getEnv(); + String serviceHash = null; String containerTagsHash = ContainerInfo.get().getContainerTagsHash(); - final String serviceHash = - Long.toString(ServiceHash.getBaseHash(parentService, env, containerTagsHash)); - // config.isDbDbmInjectServiceHash() ; // TODO && baseHash != null - String peerService = peerServiceObj != null ? peerServiceObj.toString() : null; + // TODO so we only inject if both container tags and process tags are available? + if (config.isDbmInjectSqlBaseHash() + && containerTagsHash != null + && ProcessTags.getTagsForSerialization() != null) { + long baseHash = BaseHash.getBaseHash(parentService, env, containerTagsHash); + serviceHash = Long.toString(baseHash); + } StringBuilder sb = new StringBuilder(sql.length() + INJECTED_COMMENT_ESTIMATED_SIZE); - if (appendComment) { sb.append(sql); sb.append(SPACE); @@ -128,15 +125,13 @@ public static String inject( append(sb, DATABASE_SERVICE, dbService, initSize); append(sb, DD_HOSTNAME, hostname, initSize); append(sb, DD_DB_NAME, dbName, initSize); - append(sb, DD_PEER_SERVICE, peerService, initSize); + append(sb, DD_PEER_SERVICE, getPeerService(), initSize); append(sb, DD_ENV, env, initSize); - append(sb, DD_VERSION, version, initSize); + append(sb, DD_VERSION, config.getVersion(), initSize); append(sb, TRACEPARENT, traceParent, initSize); - // TODO only if DB_DBM_INJECT_SERVICE_HASH_ENABLED - // append(sb, DD_SERVICE_HASH, serviceHash, initSize); + append(sb, DD_SERVICE_HASH, serviceHash, initSize); if (initSize == sb.length()) { // no comment was added - // TODO Is it even possible for all the fields to be unset? return sql; } sb.append(CLOSE_COMMENT); @@ -147,9 +142,18 @@ public static String inject( return sb.toString(); } - private static boolean hasDDComment(String sql, final boolean appendComment) { - if ((!(sql.endsWith(CLOSE_COMMENT)) && appendComment) - || ((!(sql.startsWith(OPEN_COMMENT))) && !appendComment)) { + private static String getPeerService() { + AgentSpan span = activeSpan(); + Object peerService = null; + if (span != null) { + peerService = span.getTag(Tags.PEER_SERVICE); + } + return peerService != null ? peerService.toString() : null; + } + + private static boolean hasDDComment(String sql, boolean appendComment) { + if ((!sql.endsWith(CLOSE_COMMENT) && appendComment) + || ((!sql.startsWith(OPEN_COMMENT)) && !appendComment)) { return false; } int startIdx = OPEN_COMMENT_LEN; @@ -168,14 +172,14 @@ private static boolean hasDDComment(String sql, final boolean appendComment) { } private static boolean hasMatchingSubstring(String sql, int startIndex, String substring) { - final boolean tooLong = startIndex + substring.length() >= sql.length(); + boolean tooLong = startIndex + substring.length() >= sql.length(); if (tooLong || !(sql.charAt(startIndex + substring.length()) == EQUALS)) { return false; } return sql.startsWith(substring, startIndex); } - private static String encode(final String val) { + private static String encode(String val) { try { return URLEncoder.encode(val, UTF8); } catch (UnsupportedEncodingException exe) { diff --git a/dd-java-agent/instrumentation/jdbc/src/test/groovy/SQLCommenterTest.groovy b/dd-java-agent/instrumentation/jdbc/src/test/groovy/SQLCommenterTest.groovy index 96b42439c54..36b9cd81b8d 100644 --- a/dd-java-agent/instrumentation/jdbc/src/test/groovy/SQLCommenterTest.groovy +++ b/dd-java-agent/instrumentation/jdbc/src/test/groovy/SQLCommenterTest.groovy @@ -1,4 +1,7 @@ +import datadog.common.container.ContainerInfo import datadog.trace.agent.test.AgentTestRunner +import datadog.trace.api.Config +import datadog.trace.api.ProcessTags import datadog.trace.bootstrap.instrumentation.api.AgentSpan import datadog.trace.bootstrap.instrumentation.api.AgentTracer import datadog.trace.bootstrap.instrumentation.api.Tags @@ -108,6 +111,44 @@ class SQLCommenterTest extends AgentTestRunner { "CALL dogshelterProc(?, ?) /*ddps=''*/" | "SqlCommenter" | "Test" | "my-service" | "postgres" | "h" | "n" | "TestVersion" | true | "00-00000000000000007fffffffffffffff-000000024cb016ea-00" | "CALL dogshelterProc(?, ?) /*ddps=''*/" } + def "inject base hash"() { + setup: + injectSysConfig("dd.service", srv) + injectSysConfig("dd.env", "") + injectSysConfig("dbm.inject.sql.basehash", Boolean.toString(injectHash)) + injectSysConfig("dd.experimental.propagate.process.tags.enabled", Boolean.toString(processTagsEnabled)) + ProcessTags.reset() + ContainerInfo.get().setContainerTagsHash(containerTagsHash) + + expect: + ContainerInfo.get().getContainerTagsHash() == containerTagsHash + and: + Config.get().isExperimentalPropagateProcessTagsEnabled() == processTagsEnabled + and: + SQLCommenter.inject(query, "", "", "", "", "", false) == result + + where: + query | injectHash | containerTagsHash | processTagsEnabled | srv | result + "SELECT *" | true | null | false | "" | "SELECT *" + "SELECT *" | true | null | true | "" | "SELECT *" + "SELECT *" | true | "234563" | false | "" | "SELECT *" + "SELECT *" | true | "234563" | true | "" | "/*ddsh='5036687995954831329'*/ SELECT *" + "SELECT *" | true | "345342" | false | "" | "SELECT *" + "SELECT *" | true | "345342" | true | "" | "/*ddsh='9119195684516789447'*/ SELECT *" + "SELECT *" | true | null | false | "srv" | "/*ddps='srv'*/ SELECT *" + "SELECT *" | true | null | true | "srv" | "/*ddps='srv'*/ SELECT *" + "SELECT *" | true | "234563" | false | "srv" | "/*ddps='srv'*/ SELECT *" + "SELECT *" | true | "234563" | true | "srv" | "/*ddps='srv',ddsh='-4976804795059740068'*/ SELECT *" + "SELECT *" | true | "345342" | false | "srv" | "/*ddps='srv'*/ SELECT *" + "SELECT *" | true | "345342" | true | "srv" | "/*ddps='srv',ddsh='-221156394106738098'*/ SELECT *" + "SELECT *" | false | null | true | "" | "SELECT *" + "SELECT *" | false | "234563" | true | "" | "SELECT *" + "SELECT *" | false | "234563" | true | "srv" | "/*ddps='srv'*/ SELECT *" + "SELECT *" | false | "345342" | true | "srv" | "/*ddps='srv'*/ SELECT *" + "/*ddsh='-3750763034362895579'*/ SELECT *" | true | null | false | "" | "/*ddsh='-3750763034362895579'*/ SELECT *" + "/*ddsh='-3750763034362895579'*/ SELECT *" | true | "234563" | true | "" | "/*ddsh='-3750763034362895579'*/ SELECT *" + } + def "test encode Sql Comment with peer service"() { setup: injectSysConfig("dd.service", "SqlCommenter") diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/TraceInstrumentationConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/TraceInstrumentationConfig.java index de625b66dbc..c2ab4e85393 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/TraceInstrumentationConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/TraceInstrumentationConfig.java @@ -66,8 +66,8 @@ public final class TraceInstrumentationConfig { public static final String JDBC_PREPARED_STATEMENT_CLASS_NAME = "trace.jdbc.prepared.statement.class.name"; + public static final String DB_DBM_INJECT_SQL_BASEHASH = "dbm.inject.sql.basehash"; public static final String DB_DBM_PROPAGATION_MODE_MODE = "dbm.propagation.mode"; - public static final String DB_DBM_TRACE_PREPARED_STATEMENTS = "dbm.trace_prepared_statements"; public static final String JDBC_CONNECTION_CLASS_NAME = "trace.jdbc.connection.class.name"; diff --git a/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultDataStreamsMonitoring.java b/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultDataStreamsMonitoring.java index 58093fae2d2..342d0bdc0b9 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultDataStreamsMonitoring.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultDataStreamsMonitoring.java @@ -7,9 +7,11 @@ import static datadog.trace.util.AgentThreadFactory.THREAD_JOIN_TIMOUT_MS; import static datadog.trace.util.AgentThreadFactory.newAgentThread; +import datadog.common.container.ContainerInfo; import datadog.communication.ddagent.DDAgentFeaturesDiscovery; import datadog.communication.ddagent.SharedCommunicationObjects; import datadog.context.propagation.Propagator; +import datadog.trace.api.BaseHash; import datadog.trace.api.Config; import datadog.trace.api.TraceConfig; import datadog.trace.api.WellKnownTags; @@ -113,7 +115,11 @@ public DefaultDataStreamsMonitoring( this.features = features; this.timeSource = timeSource; this.traceConfigSupplier = traceConfigSupplier; - this.hashOfKnownTags = DefaultPathwayContext.getBaseHash(wellKnownTags); + this.hashOfKnownTags = + BaseHash.getBaseHash( + wellKnownTags.getService(), + wellKnownTags.getEnv(), + ContainerInfo.get().getContainerTagsHash()); this.payloadWriter = payloadWriter; this.bucketDurationNanos = bucketDurationNanos; diff --git a/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultPathwayContext.java b/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultPathwayContext.java index 5573cf56bb8..6991a26dc9e 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultPathwayContext.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultPathwayContext.java @@ -7,10 +7,7 @@ import com.datadoghq.sketch.ddsketch.encoding.ByteArrayInput; import com.datadoghq.sketch.ddsketch.encoding.GrowingByteArrayOutput; import com.datadoghq.sketch.ddsketch.encoding.VarEncodingHelper; -import datadog.common.container.ContainerInfo; import datadog.context.propagation.CarrierVisitor; -import datadog.trace.api.ServiceHash; -import datadog.trace.api.WellKnownTags; import datadog.trace.api.datastreams.DataStreamsContext; import datadog.trace.api.datastreams.DataStreamsTags; import datadog.trace.api.datastreams.PathwayContext; @@ -268,10 +265,6 @@ private static DefaultPathwayContext decode( serviceNameOverride); } - public static long getBaseHash(WellKnownTags wellKnownTags) { - return ServiceHash.getBaseHash(wellKnownTags, ContainerInfo.get().getContainerTagsHash()); - } - private long generatePathwayHash(long nodeHash, long parentHash) { outputBuffer.clear(); outputBuffer.writeLongLE(nodeHash); diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/datastreams/DefaultPathwayContextTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/datastreams/DefaultPathwayContextTest.groovy index c7e93f40017..77d4db39ea6 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/core/datastreams/DefaultPathwayContextTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/datastreams/DefaultPathwayContextTest.groovy @@ -1,10 +1,8 @@ package datadog.trace.core.datastreams -import datadog.common.container.ContainerInfo import datadog.communication.ddagent.DDAgentFeaturesDiscovery import datadog.trace.api.Config import datadog.trace.api.DDTraceId -import datadog.trace.api.ProcessTags import datadog.trace.api.TagMap import datadog.trace.api.TraceConfig import datadog.trace.api.WellKnownTags @@ -17,13 +15,9 @@ import datadog.trace.bootstrap.instrumentation.api.AgentTracer import datadog.trace.common.metrics.Sink import datadog.trace.core.propagation.ExtractedContext import datadog.trace.core.test.DDCoreSpecification - import java.util.function.Consumer - import static datadog.context.Context.root import static datadog.trace.api.TracePropagationStyle.DATADOG -import static datadog.trace.api.config.GeneralConfig.EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED -import static datadog.trace.api.config.GeneralConfig.PRIMARY_TAG import static datadog.trace.api.datastreams.DataStreamsContext.create import static datadog.trace.api.datastreams.DataStreamsContext.fromTags import static datadog.trace.api.datastreams.PathwayContext.PROPAGATION_KEY_BASE64 @@ -454,60 +448,6 @@ class DefaultPathwayContextTest extends DDCoreSpecification { } } - def "Primary tag used in hash calculation"() { - when: - def firstBaseHash = DefaultPathwayContext.getBaseHash(wellKnownTags) - - injectSysConfig(PRIMARY_TAG, "region-2") - def secondBaseHash = DefaultPathwayContext.getBaseHash(wellKnownTags) - - then: - firstBaseHash != secondBaseHash - } - - def "Process Tags used in hash calculation"() { - when: - def firstBaseHash = DefaultPathwayContext.getBaseHash(wellKnownTags) - - injectSysConfig(EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED, "true") - ProcessTags.reset() - ProcessTags.addTag("000", "first") - def secondBaseHash = DefaultPathwayContext.getBaseHash(wellKnownTags) - - then: - firstBaseHash != secondBaseHash - assert ProcessTags.getTagsForSerialization().startsWithAny("000:first,") - cleanup: - injectSysConfig(EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED, "false") - ProcessTags.reset() - } - - def "ContainerTagsHash used in hash calculation when enabled propagateTagsEnabled=#propagateTagsEnabled"() { - when: - injectSysConfig(EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED, propagateTagsEnabled.toString()) - ProcessTags.reset() - ProcessTags.addTag("000", "first") - def firstBaseHash = DefaultPathwayContext.getBaseHash(wellKnownTags) - - then: - ContainerInfo.get().setContainerTagsHash("") - def secondBaseHash = DefaultPathwayContext.getBaseHash(wellKnownTags) - - expect: - if (propagateTagsEnabled) { - assert secondBaseHash != firstBaseHash - } else { - assert secondBaseHash == firstBaseHash - } - - cleanup: - injectSysConfig(EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED, "false") - ProcessTags.reset() - - where: - propagateTagsEnabled << [true, false] - } - def "Check context extractor decorator behavior"() { given: def sink = Mock(Sink) diff --git a/internal-api/src/main/java/datadog/trace/api/ServiceHash.java b/internal-api/src/main/java/datadog/trace/api/BaseHash.java similarity index 74% rename from internal-api/src/main/java/datadog/trace/api/ServiceHash.java rename to internal-api/src/main/java/datadog/trace/api/BaseHash.java index 4a87f1db21e..ffb8695a253 100644 --- a/internal-api/src/main/java/datadog/trace/api/ServiceHash.java +++ b/internal-api/src/main/java/datadog/trace/api/BaseHash.java @@ -2,16 +2,7 @@ import datadog.trace.util.FNV64Hash; -public final class ServiceHash { - - public static long getBaseHash(WellKnownTags wellKnownTags, String containerTagsHash) { - return getBaseHash( - wellKnownTags.getService(), - wellKnownTags.getEnv(), - Config.get().getPrimaryTag(), - ProcessTags.getTagsForSerialization(), - containerTagsHash); - } +public final class BaseHash { public static long getBaseHash( CharSequence serviceName, CharSequence env, String containerTagsHash) { diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index aae53ec7e07..eee9060422f 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -491,6 +491,7 @@ import static datadog.trace.api.config.TraceInstrumentationConfig.DB_CLIENT_HOST_SPLIT_BY_HOST; import static datadog.trace.api.config.TraceInstrumentationConfig.DB_CLIENT_HOST_SPLIT_BY_INSTANCE; import static datadog.trace.api.config.TraceInstrumentationConfig.DB_CLIENT_HOST_SPLIT_BY_INSTANCE_TYPE_SUFFIX; +import static datadog.trace.api.config.TraceInstrumentationConfig.DB_DBM_INJECT_SQL_BASEHASH; import static datadog.trace.api.config.TraceInstrumentationConfig.DB_DBM_PROPAGATION_MODE_MODE; import static datadog.trace.api.config.TraceInstrumentationConfig.DB_DBM_TRACE_PREPARED_STATEMENTS; import static datadog.trace.api.config.TraceInstrumentationConfig.ELASTICSEARCH_BODY_AND_PARAMS_ENABLED; @@ -1040,8 +1041,9 @@ public static String getHostName() { private final int remoteConfigMaxExtraServices; - private final String DBMPropagationMode; - private final boolean DBMTracePreparedStatements; + private final boolean dbmInjectSqlBaseHash; + private final String dbmPropagationMode; + private final boolean dbmTracePreparedStatements; private final boolean dynamicInstrumentationEnabled; private final int dynamicInstrumentationUploadTimeout; @@ -1571,14 +1573,16 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins configProvider.getBoolean( DB_CLIENT_HOST_SPLIT_BY_HOST, DEFAULT_DB_CLIENT_HOST_SPLIT_BY_HOST); - DBMPropagationMode = + dbmPropagationMode = configProvider.getString( DB_DBM_PROPAGATION_MODE_MODE, DEFAULT_DB_DBM_PROPAGATION_MODE_MODE); - DBMTracePreparedStatements = + dbmTracePreparedStatements = configProvider.getBoolean( DB_DBM_TRACE_PREPARED_STATEMENTS, DEFAULT_DB_DBM_TRACE_PREPARED_STATEMENTS); + dbmInjectSqlBaseHash = configProvider.getBoolean(DB_DBM_INJECT_SQL_BASEHASH, false); + splitByTags = tryMakeImmutableSet(configProvider.getList(SPLIT_BY_TAGS)); jeeSplitByDeployment = @@ -4860,12 +4864,16 @@ public long getDependecyResolutionPeriodMillis() { return dependecyResolutionPeriodMillis; } - public boolean isDBMTracePreparedStatements() { - return DBMTracePreparedStatements; + public boolean isDbmInjectSqlBaseHash() { + return dbmInjectSqlBaseHash; + } + + public boolean isDbmTracePreparedStatements() { + return dbmTracePreparedStatements; } - public String getDBMPropagationMode() { - return DBMPropagationMode; + public String getDbmPropagationMode() { + return dbmPropagationMode; } private void logIgnoredSettingWarning( @@ -5370,10 +5378,12 @@ public String toString() { + dbClientSplitByInstanceTypeSuffix + ", dbClientSplitByHost=" + dbClientSplitByHost - + ", DBMPropagationMode=" - + DBMPropagationMode - + ", DBMTracePreparedStatements=" - + DBMTracePreparedStatements + + ", dbmInjectSqlBaseHash=" + + dbmInjectSqlBaseHash + + ", dbmPropagationMode=" + + dbmPropagationMode + + ", dbmTracePreparedStatements=" + + dbmTracePreparedStatements + ", splitByTags=" + splitByTags + ", jeeSplitByDeployment=" diff --git a/internal-api/src/main/java/datadog/trace/api/ProcessTags.java b/internal-api/src/main/java/datadog/trace/api/ProcessTags.java index b13adc60fb1..041159df652 100644 --- a/internal-api/src/main/java/datadog/trace/api/ProcessTags.java +++ b/internal-api/src/main/java/datadog/trace/api/ProcessTags.java @@ -168,6 +168,10 @@ static void calculate() { private ProcessTags() {} + public static boolean isEnabled() { + return enabled; + } + // need to be synchronized on writing. As optimization, it does not need to be sync on read. public static void addTag(String key, String value) { if (enabled) { diff --git a/internal-api/src/test/groovy/datadog/trace/api/BaseHashTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/BaseHashTest.groovy new file mode 100644 index 00000000000..6177e00ca7c --- /dev/null +++ b/internal-api/src/test/groovy/datadog/trace/api/BaseHashTest.groovy @@ -0,0 +1,62 @@ +package datadog.trace.api + +import datadog.trace.test.util.DDSpecification + +import static datadog.trace.api.config.GeneralConfig.EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED +import static datadog.trace.api.config.GeneralConfig.PRIMARY_TAG + +class BaseHashTest extends DDSpecification { + + def "Primary tag used in hash calculation"() { + when: + def firstBaseHash = BaseHash.getBaseHash("service", "env", null) + + injectSysConfig(PRIMARY_TAG, "region-2") + def secondBaseHash = BaseHash.getBaseHash("service", "env", null) + + then: + firstBaseHash != secondBaseHash + } + + def "Process Tags used in hash calculation"() { + when: + def firstBaseHash = BaseHash.getBaseHash("service", "env", null) + + injectSysConfig(EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED, "true") + ProcessTags.reset() + ProcessTags.addTag("000", "first") + def secondBaseHash = BaseHash.getBaseHash("service", "env", null) + + then: + firstBaseHash != secondBaseHash + assert ProcessTags.getTagsForSerialization().startsWithAny("000:first,") + cleanup: + injectSysConfig(EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED, "false") + ProcessTags.reset() + } + + def "ContainerTagsHash used in hash calculation when provided"() { + when: + injectSysConfig(EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED, propagateTagsEnabled.toString()) + ProcessTags.reset() + ProcessTags.addTag("000", "first") + def firstBaseHash = BaseHash.getBaseHash("service", "env", null) + + then: + def secondBaseHash = BaseHash.getBaseHash("service", "env", "") + + expect: + if (propagateTagsEnabled) { + assert secondBaseHash != firstBaseHash + } else { + assert secondBaseHash == firstBaseHash + } + + cleanup: + injectSysConfig(EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED, "false") + ProcessTags.reset() + + where: + propagateTagsEnabled << [true, false] + } +} From f9bf0459ded0444428edb2c8b97cab6c88960e2d Mon Sep 17 00:00:00 2001 From: Yury Gribkov Date: Mon, 18 Aug 2025 10:45:29 -0700 Subject: [PATCH 09/12] Clean up hashOfKnownTags leftovers #9151 --- .../datastreams/DataStreamsPropagator.java | 5 +- .../DefaultDataStreamsMonitoring.java | 12 ++--- .../datastreams/DefaultPathwayContext.java | 39 ++++++---------- .../DefaultPathwayContextTest.groovy | 46 +++++++++---------- 4 files changed, 43 insertions(+), 59 deletions(-) diff --git a/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DataStreamsPropagator.java b/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DataStreamsPropagator.java index 32d4a6b7bcc..3aba15aca42 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DataStreamsPropagator.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DataStreamsPropagator.java @@ -25,17 +25,14 @@ public class DataStreamsPropagator implements Propagator { private final DataStreamsMonitoring dataStreamsMonitoring; private final TimeSource timeSource; - private final long hashOfKnownTags; private final ThreadLocal serviceNameOverride; public DataStreamsPropagator( DataStreamsMonitoring dataStreamsMonitoring, TimeSource timeSource, - long hashOfKnownTags, ThreadLocal serviceNameOverride) { this.dataStreamsMonitoring = dataStreamsMonitoring; this.timeSource = timeSource; - this.hashOfKnownTags = hashOfKnownTags; this.serviceNameOverride = serviceNameOverride; } @@ -108,6 +105,6 @@ private TagContext getSpanContextOrNull(Context context) { private PathwayContext extractDsmPathwayContext(C carrier, CarrierVisitor visitor) { return DefaultPathwayContext.extract( - carrier, visitor, this.timeSource, this.hashOfKnownTags, serviceNameOverride.get()); + carrier, visitor, this.timeSource, serviceNameOverride.get()); } } diff --git a/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultDataStreamsMonitoring.java b/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultDataStreamsMonitoring.java index 342d0bdc0b9..95950f73f44 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultDataStreamsMonitoring.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultDataStreamsMonitoring.java @@ -119,7 +119,8 @@ public DefaultDataStreamsMonitoring( BaseHash.getBaseHash( wellKnownTags.getService(), wellKnownTags.getEnv(), - ContainerInfo.get().getContainerTagsHash()); + ContainerInfo.get() + .getContainerTagsHash()); // TODO container tags hash is not available yet this.payloadWriter = payloadWriter; this.bucketDurationNanos = bucketDurationNanos; @@ -127,10 +128,10 @@ public DefaultDataStreamsMonitoring( sink.register(this); schemaSamplers = new ConcurrentHashMap<>(); - this.propagator = - new DataStreamsPropagator(this, this.timeSource, this.hashOfKnownTags, serviceNameOverride); + this.propagator = new DataStreamsPropagator(this, this.timeSource, serviceNameOverride); // configure global tags behavior - DataStreamsTags.setGlobalBaseHash(this.hashOfKnownTags); + DataStreamsTags.setGlobalBaseHash( + this.hashOfKnownTags); // TODO has to be updated once containerTagsHash is available DataStreamsTags.setServiceNameOverride(serviceNameOverride); } @@ -194,7 +195,7 @@ private static String getThreadServiceName() { @Override public PathwayContext newPathwayContext() { if (configSupportsDataStreams) { - return new DefaultPathwayContext(timeSource, hashOfKnownTags, getThreadServiceName()); + return new DefaultPathwayContext(timeSource, getThreadServiceName()); } else { return NoopPathwayContext.INSTANCE; } @@ -213,7 +214,6 @@ public void mergePathwayContextIntoSpan(AgentSpan span, DataStreamsContextCarrie carrier, DataStreamsContextCarrierAdapter.INSTANCE, this.timeSource, - this.hashOfKnownTags, getThreadServiceName()); ((DDSpan) span).context().mergePathwayContext(pathwayContext); } diff --git a/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultPathwayContext.java b/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultPathwayContext.java index 6991a26dc9e..316c0bd83e6 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultPathwayContext.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultPathwayContext.java @@ -24,7 +24,6 @@ public class DefaultPathwayContext implements PathwayContext { private static final Logger log = LoggerFactory.getLogger(DefaultPathwayContext.class); - private final long hashOfKnownTags; private final TimeSource timeSource; private final String serviceNameOverride; private final GrowingByteArrayOutput outputBuffer = @@ -44,22 +43,19 @@ public class DefaultPathwayContext implements PathwayContext { private long closestOppositeDirectionHash; private DataStreamsTags.Direction previousDirection; - public DefaultPathwayContext( - TimeSource timeSource, long hashOfKnownTags, String serviceNameOverride) { + public DefaultPathwayContext(TimeSource timeSource, String serviceNameOverride) { this.timeSource = timeSource; - this.hashOfKnownTags = hashOfKnownTags; this.serviceNameOverride = serviceNameOverride; } private DefaultPathwayContext( TimeSource timeSource, - long hashOfKnownTags, long pathwayStartNanos, long pathwayStartNanoTicks, long edgeStartNanoTicks, long hash, String serviceNameOverride) { - this(timeSource, hashOfKnownTags, serviceNameOverride); + this(timeSource, serviceNameOverride); this.pathwayStartNanos = pathwayStartNanos; this.pathwayStartNanoTicks = pathwayStartNanoTicks; this.edgeStartNanoTicks = edgeStartNanoTicks; @@ -194,14 +190,11 @@ public synchronized String toString() { private static class PathwayContextExtractor implements BiConsumer { private final TimeSource timeSource; - private final long hashOfKnownTags; private final String serviceNameOverride; private DefaultPathwayContext extractedContext; - PathwayContextExtractor( - TimeSource timeSource, long hashOfKnownTags, String serviceNameOverride) { + PathwayContextExtractor(TimeSource timeSource, String serviceNameOverride) { this.timeSource = timeSource; - this.hashOfKnownTags = hashOfKnownTags; this.serviceNameOverride = serviceNameOverride; } @@ -209,7 +202,7 @@ private static class PathwayContextExtractor implements BiConsumer DefaultPathwayContext extract( - C carrier, - CarrierVisitor getter, - TimeSource timeSource, - long hashOfKnownTags, - String serviceNameOverride) { - PathwayContextExtractor pathwayContextExtractor = - new PathwayContextExtractor(timeSource, hashOfKnownTags, serviceNameOverride); - getter.forEachKeyValue(carrier, pathwayContextExtractor); - if (pathwayContextExtractor.extractedContext == null) { + C carrier, CarrierVisitor getter, TimeSource timeSource, String serviceNameOverride) { + PathwayContextExtractor extractor = + new PathwayContextExtractor(timeSource, serviceNameOverride); + getter.forEachKeyValue(carrier, extractor); + if (extractor.extractedContext == null) { log.debug("No context extracted"); } else { - log.debug("Extracted context: {} ", pathwayContextExtractor.extractedContext); + log.debug("Extracted context: {} ", extractor.extractedContext); } - return pathwayContextExtractor.extractedContext; + return extractor.extractedContext; } - private static DefaultPathwayContext decode( - TimeSource timeSource, long hashOfKnownTags, String serviceNameOverride, String base64) - throws IOException { + protected static DefaultPathwayContext decode( + TimeSource timeSource, String serviceNameOverride, String base64) throws IOException { byte[] base64Bytes = base64.getBytes(UTF_8); byte[] bytes = Base64.getDecoder().decode(base64Bytes); ByteArrayInput input = ByteArrayInput.wrap(bytes); @@ -257,7 +245,6 @@ private static DefaultPathwayContext decode( return new DefaultPathwayContext( timeSource, - hashOfKnownTags, pathwayStartNanos, pathwayStartNanoTicks, edgeStartNanoTicks, diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/datastreams/DefaultPathwayContextTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/datastreams/DefaultPathwayContextTest.groovy index 77d4db39ea6..8ea4c7ec23b 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/core/datastreams/DefaultPathwayContextTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/datastreams/DefaultPathwayContextTest.groovy @@ -47,7 +47,7 @@ class DefaultPathwayContextTest extends DDCoreSpecification { def "First Set checkpoint starts the context."() { given: def timeSource = new ControllableTimeSource() - def context = new DefaultPathwayContext(timeSource, baseHash, null) + def context = new DefaultPathwayContext(timeSource, null) when: timeSource.advance(50) @@ -62,7 +62,7 @@ class DefaultPathwayContextTest extends DDCoreSpecification { def "Checkpoint generated"() { given: def timeSource = new ControllableTimeSource() - def context = new DefaultPathwayContext(timeSource, baseHash, null) + def context = new DefaultPathwayContext(timeSource, null) when: timeSource.advance(50) @@ -91,7 +91,7 @@ class DefaultPathwayContextTest extends DDCoreSpecification { def "Checkpoint with payload size"() { given: def timeSource = new ControllableTimeSource() - def context = new DefaultPathwayContext(timeSource, baseHash, null) + def context = new DefaultPathwayContext(timeSource, null) when: timeSource.advance(25) @@ -115,7 +115,7 @@ class DefaultPathwayContextTest extends DDCoreSpecification { def "Multiple checkpoints generated"() { given: def timeSource = new ControllableTimeSource() - def context = new DefaultPathwayContext(timeSource, baseHash, null) + def context = new DefaultPathwayContext(timeSource, null) when: timeSource.advance(50) @@ -160,7 +160,7 @@ class DefaultPathwayContextTest extends DDCoreSpecification { def "Exception thrown when trying to encode unstarted context"() { given: def timeSource = new ControllableTimeSource() - def context = new DefaultPathwayContext(timeSource, baseHash, null) + def context = new DefaultPathwayContext(timeSource, null) when: context.encode() @@ -172,14 +172,14 @@ class DefaultPathwayContextTest extends DDCoreSpecification { def "Set checkpoint with dataset tags"() { given: def timeSource = new ControllableTimeSource() - def context = new DefaultPathwayContext(timeSource, baseHash, null) + def context = new DefaultPathwayContext(timeSource, null) when: timeSource.advance(MILLISECONDS.toNanos(50)) context.setCheckpoint(fromTags(DataStreamsTags.createWithDataset("s3", DataStreamsTags.Direction.Inbound, null, "my_object.csv", "my_bucket")), pointConsumer) def encoded = context.encode() timeSource.advance(MILLISECONDS.toNanos(2)) - def decodedContext = DefaultPathwayContext.decode(timeSource, baseHash, null, encoded) + def decodedContext = DefaultPathwayContext.decode(timeSource, null, encoded) timeSource.advance(MILLISECONDS.toNanos(25)) def tg = DataStreamsTags.createWithDataset("s3", DataStreamsTags.Direction.Outbound, null, "my_object.csv", "my_bucket") context.setCheckpoint(fromTags(tg), pointConsumer) @@ -199,14 +199,14 @@ class DefaultPathwayContextTest extends DDCoreSpecification { // Timesource needs to be advanced in milliseconds because encoding truncates to millis given: def timeSource = new ControllableTimeSource() - def context = new DefaultPathwayContext(timeSource, baseHash, null) + def context = new DefaultPathwayContext(timeSource, null) when: timeSource.advance(MILLISECONDS.toNanos(50)) context.setCheckpoint(fromTags(DataStreamsTags.create("internal", DataStreamsTags.Direction.Inbound)), pointConsumer) def encoded = context.encode() timeSource.advance(MILLISECONDS.toNanos(2)) - def decodedContext = DefaultPathwayContext.decode(timeSource, baseHash, null, encoded) + def decodedContext = DefaultPathwayContext.decode(timeSource, null, encoded) timeSource.advance(MILLISECONDS.toNanos(25)) context.setCheckpoint(fromTags(DataStreamsTags.create("kafka", null, "topic", "group", null)), pointConsumer) @@ -229,7 +229,7 @@ class DefaultPathwayContextTest extends DDCoreSpecification { def "Set checkpoint with timestamp"() { given: def timeSource = new ControllableTimeSource() - def context = new DefaultPathwayContext(timeSource, baseHash, null) + def context = new DefaultPathwayContext(timeSource, null) def timeFromQueue = timeSource.getCurrentTimeMillis() - 200 when: context.setCheckpoint(create(DataStreamsTags.create("internal", null), timeFromQueue, 0), pointConsumer) @@ -250,7 +250,7 @@ class DefaultPathwayContextTest extends DDCoreSpecification { // Timesource needs to be advanced in milliseconds because encoding truncates to millis given: def timeSource = new ControllableTimeSource() - def context = new DefaultPathwayContext(timeSource, baseHash, null) + def context = new DefaultPathwayContext(timeSource, null) when: timeSource.advance(MILLISECONDS.toNanos(50)) @@ -258,7 +258,7 @@ class DefaultPathwayContextTest extends DDCoreSpecification { def encoded = context.encode() timeSource.advance(MILLISECONDS.toNanos(1)) - def decodedContext = DefaultPathwayContext.decode(timeSource, baseHash, null, encoded) + def decodedContext = DefaultPathwayContext.decode(timeSource, null, encoded) timeSource.advance(MILLISECONDS.toNanos(25)) context.setCheckpoint(fromTags(DataStreamsTags.create("kafka", DataStreamsTags.Direction.Outbound, "topic", "group", null)), pointConsumer) @@ -280,7 +280,7 @@ class DefaultPathwayContextTest extends DDCoreSpecification { when: def secondEncode = decodedContext.encode() timeSource.advance(MILLISECONDS.toNanos(2)) - def secondDecode = DefaultPathwayContext.decode(timeSource, baseHash, null, secondEncode) + def secondDecode = DefaultPathwayContext.decode(timeSource, null, secondEncode) timeSource.advance(MILLISECONDS.toNanos(30)) context.setCheckpoint(fromTags(DataStreamsTags.create("kafka", DataStreamsTags.Direction.Inbound, "topicB", "group", null)), pointConsumer) @@ -304,7 +304,7 @@ class DefaultPathwayContextTest extends DDCoreSpecification { // Timesource needs to be advanced in milliseconds because encoding truncates to millis given: def timeSource = new ControllableTimeSource() - def context = new DefaultPathwayContext(timeSource, baseHash, null) + def context = new DefaultPathwayContext(timeSource, null) def contextVisitor = new Base64MapContextVisitor() when: @@ -314,7 +314,7 @@ class DefaultPathwayContextTest extends DDCoreSpecification { def encoded = context.encode() Map carrier = [(PROPAGATION_KEY_BASE64): encoded, "someotherkey": "someothervalue"] timeSource.advance(MILLISECONDS.toNanos(1)) - def decodedContext = DefaultPathwayContext.extract(carrier, contextVisitor, timeSource, baseHash, null) + def decodedContext = DefaultPathwayContext.extract(carrier, contextVisitor, timeSource, null) timeSource.advance(MILLISECONDS.toNanos(25)) context.setCheckpoint(fromTags(DataStreamsTags.create("kafka", DataStreamsTags.Direction.Outbound, "topic", "group", null)), pointConsumer) @@ -337,7 +337,7 @@ class DefaultPathwayContextTest extends DDCoreSpecification { def secondEncode = decodedContext.encode() carrier = [(PROPAGATION_KEY_BASE64): secondEncode] timeSource.advance(MILLISECONDS.toNanos(2)) - def secondDecode = DefaultPathwayContext.extract(carrier, contextVisitor, timeSource, baseHash, null) + def secondDecode = DefaultPathwayContext.extract(carrier, contextVisitor, timeSource, null) timeSource.advance(MILLISECONDS.toNanos(30)) context.setCheckpoint(fromTags(DataStreamsTags.create("kafka", DataStreamsTags.Direction.Inbound, "topicB", "group", null)), pointConsumer) @@ -361,7 +361,7 @@ class DefaultPathwayContextTest extends DDCoreSpecification { // Timesource needs to be advanced in milliseconds because encoding truncates to millis given: def timeSource = new ControllableTimeSource() - def context = new DefaultPathwayContext(timeSource, baseHash, null) + def context = new DefaultPathwayContext(timeSource, null) def contextVisitor = new Base64MapContextVisitor() when: @@ -371,7 +371,7 @@ class DefaultPathwayContextTest extends DDCoreSpecification { def encoded = context.encode() Map carrier = [(PROPAGATION_KEY_BASE64): encoded, "someotherkey": "someothervalue"] timeSource.advance(MILLISECONDS.toNanos(1)) - def decodedContext = DefaultPathwayContext.extract(carrier, contextVisitor, timeSource, baseHash, null) + def decodedContext = DefaultPathwayContext.extract(carrier, contextVisitor, timeSource, null) timeSource.advance(MILLISECONDS.toNanos(25)) context.setCheckpoint(fromTags(DataStreamsTags.create("sqs", DataStreamsTags.Direction.Outbound, "topic", null, null)), pointConsumer) @@ -393,7 +393,7 @@ class DefaultPathwayContextTest extends DDCoreSpecification { def secondEncode = decodedContext.encode() carrier = [(PROPAGATION_KEY_BASE64): secondEncode] timeSource.advance(MILLISECONDS.toNanos(2)) - def secondDecode = DefaultPathwayContext.extract(carrier, contextVisitor, timeSource, baseHash, null) + def secondDecode = DefaultPathwayContext.extract(carrier, contextVisitor, timeSource, null) timeSource.advance(MILLISECONDS.toNanos(30)) context.setCheckpoint(fromTags(DataStreamsTags.create("sqs", DataStreamsTags.Direction.Inbound, "topicB", null, null)), pointConsumer) @@ -414,7 +414,7 @@ class DefaultPathwayContextTest extends DDCoreSpecification { def "Empty tags not set"() { given: def timeSource = new ControllableTimeSource() - def context = new DefaultPathwayContext(timeSource, baseHash, null) + def context = new DefaultPathwayContext(timeSource, null) when: timeSource.advance(50) @@ -470,7 +470,7 @@ class DefaultPathwayContextTest extends DDCoreSpecification { def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { globalTraceConfig }, wellKnownTags, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) DataStreamsTags.setGlobalBaseHash(baseHash) - def context = new DefaultPathwayContext(timeSource, baseHash, null) + def context = new DefaultPathwayContext(timeSource, null) timeSource.advance(MILLISECONDS.toNanos(50)) context.setCheckpoint(fromTags(DataStreamsTags.create("internal", DataStreamsTags.Direction.Inbound)), pointConsumer) def encoded = context.encode() @@ -524,7 +524,7 @@ class DefaultPathwayContextTest extends DDCoreSpecification { def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { globalTraceConfig }, wellKnownTags, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) DataStreamsTags.setGlobalBaseHash(baseHash) - def context = new DefaultPathwayContext(timeSource, baseHash, null) + def context = new DefaultPathwayContext(timeSource, null) timeSource.advance(MILLISECONDS.toNanos(50)) context.setCheckpoint(fromTags(DataStreamsTags.create("internal", DataStreamsTags.Direction.Inbound)), pointConsumer) def encoded = context.encode() @@ -579,7 +579,7 @@ class DefaultPathwayContextTest extends DDCoreSpecification { wellKnownTags, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) DataStreamsTags.setGlobalBaseHash(baseHash) - def context = new DefaultPathwayContext(timeSource, baseHash, null) + def context = new DefaultPathwayContext(timeSource, null) timeSource.advance(MILLISECONDS.toNanos(50)) context.setCheckpoint(fromTags(DataStreamsTags.create("internal", DataStreamsTags.Direction.Inbound)), pointConsumer) def encoded = context.encode() From c72986532690a6b1536dfada06aa273c75e6c815 Mon Sep 17 00:00:00 2001 From: Yury Gribkov Date: Tue, 19 Aug 2025 13:10:57 -0700 Subject: [PATCH 10/12] BaseHash keeps a global hash that is updated when containerTagsHash is received --- .../ddagent/DDAgentFeaturesDiscovery.java | 10 ++++- .../instrumentation/jdbc/build.gradle | 1 - .../instrumentation/jdbc/SQLCommenter.java | 21 +++------- .../src/test/groovy/SQLCommenterTest.groovy | 38 ++++++++----------- .../trace/agent/test/AgentTestRunner.groovy | 4 +- .../DefaultDataStreamsMonitoring.java | 15 -------- .../DefaultDataStreamsMonitoringTest.groovy | 31 +++++++-------- .../DefaultPathwayContextTest.groovy | 19 ++++------ .../main/java/datadog/trace/api/BaseHash.java | 33 +++++++++++++--- .../api/datastreams/DataStreamsTags.java | 10 +---- .../datadog/trace/api/BaseHashTest.groovy | 36 +++++++++++++++--- .../datastreams/DataStreamsTagsTest.groovy | 4 +- 12 files changed, 113 insertions(+), 109 deletions(-) diff --git a/communication/src/main/java/datadog/communication/ddagent/DDAgentFeaturesDiscovery.java b/communication/src/main/java/datadog/communication/ddagent/DDAgentFeaturesDiscovery.java index b527b08e13f..4120c390aaa 100644 --- a/communication/src/main/java/datadog/communication/ddagent/DDAgentFeaturesDiscovery.java +++ b/communication/src/main/java/datadog/communication/ddagent/DDAgentFeaturesDiscovery.java @@ -15,6 +15,7 @@ import datadog.communication.monitor.DDAgentStatsDClientManager; import datadog.communication.monitor.Monitoring; import datadog.communication.monitor.Recording; +import datadog.trace.api.BaseHash; import datadog.trace.api.telemetry.LogCollector; import datadog.trace.util.Strings; import java.nio.ByteBuffer; @@ -230,7 +231,14 @@ private String probeTracesEndpoint(String[] endpoints) { } private void processInfoResponseHeaders(Response response) { - ContainerInfo.get().setContainerTagsHash(response.header(DATADOG_CONTAINER_TAGS_HASH)); + String newContainerTagsHash = response.header(DATADOG_CONTAINER_TAGS_HASH); + if (newContainerTagsHash != null) { + ContainerInfo containerInfo = ContainerInfo.get(); + if (!newContainerTagsHash.equals(containerInfo.getContainerTagsHash())) { + containerInfo.setContainerTagsHash(newContainerTagsHash); + BaseHash.recalcBaseHash(newContainerTagsHash); + } + } } @SuppressWarnings("unchecked") diff --git a/dd-java-agent/instrumentation/jdbc/build.gradle b/dd-java-agent/instrumentation/jdbc/build.gradle index 9fd8e2d6d8b..c7542d24e2b 100644 --- a/dd-java-agent/instrumentation/jdbc/build.gradle +++ b/dd-java-agent/instrumentation/jdbc/build.gradle @@ -22,7 +22,6 @@ addTestSuiteExtendingForDir('latestDepJava11Test', 'latestDepTest', 'test') dependencies { compileOnly group: 'com.zaxxer', name: 'HikariCP', version: '2.4.0' testImplementation(testFixtures(project(':dd-java-agent:agent-iast'))) - implementation project(':utils:container-utils') // jdbc unit testing testImplementation group: 'com.h2database', name: 'h2', version: '[1.3.168,1.3.169]'// first jdk 1.6 compatible diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java index 360155b567a..d9a409d2c29 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/SQLCommenter.java @@ -2,10 +2,8 @@ import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; -import datadog.common.container.ContainerInfo; import datadog.trace.api.BaseHash; import datadog.trace.api.Config; -import datadog.trace.api.ProcessTags; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.Tags; import java.io.UnsupportedEncodingException; @@ -102,17 +100,6 @@ public static String inject( } Config config = Config.get(); - String parentService = config.getServiceName(); - String env = config.getEnv(); - String serviceHash = null; - String containerTagsHash = ContainerInfo.get().getContainerTagsHash(); - // TODO so we only inject if both container tags and process tags are available? - if (config.isDbmInjectSqlBaseHash() - && containerTagsHash != null - && ProcessTags.getTagsForSerialization() != null) { - long baseHash = BaseHash.getBaseHash(parentService, env, containerTagsHash); - serviceHash = Long.toString(baseHash); - } StringBuilder sb = new StringBuilder(sql.length() + INJECTED_COMMENT_ESTIMATED_SIZE); if (appendComment) { @@ -121,15 +108,17 @@ public static String inject( } sb.append(OPEN_COMMENT); int initSize = sb.length(); - append(sb, PARENT_SERVICE, parentService, initSize); + append(sb, PARENT_SERVICE, config.getServiceName(), initSize); append(sb, DATABASE_SERVICE, dbService, initSize); append(sb, DD_HOSTNAME, hostname, initSize); append(sb, DD_DB_NAME, dbName, initSize); append(sb, DD_PEER_SERVICE, getPeerService(), initSize); - append(sb, DD_ENV, env, initSize); + append(sb, DD_ENV, config.getEnv(), initSize); append(sb, DD_VERSION, config.getVersion(), initSize); append(sb, TRACEPARENT, traceParent, initSize); - append(sb, DD_SERVICE_HASH, serviceHash, initSize); + if (config.isDbmInjectSqlBaseHash() && config.isExperimentalPropagateProcessTagsEnabled()) { + append(sb, DD_SERVICE_HASH, BaseHash.getBaseHashStr(), initSize); + } if (initSize == sb.length()) { // no comment was added return sql; diff --git a/dd-java-agent/instrumentation/jdbc/src/test/groovy/SQLCommenterTest.groovy b/dd-java-agent/instrumentation/jdbc/src/test/groovy/SQLCommenterTest.groovy index 36b9cd81b8d..ce516c91035 100644 --- a/dd-java-agent/instrumentation/jdbc/src/test/groovy/SQLCommenterTest.groovy +++ b/dd-java-agent/instrumentation/jdbc/src/test/groovy/SQLCommenterTest.groovy @@ -1,5 +1,5 @@ -import datadog.common.container.ContainerInfo import datadog.trace.agent.test.AgentTestRunner +import datadog.trace.api.BaseHash import datadog.trace.api.Config import datadog.trace.api.ProcessTags import datadog.trace.bootstrap.instrumentation.api.AgentSpan @@ -118,35 +118,27 @@ class SQLCommenterTest extends AgentTestRunner { injectSysConfig("dbm.inject.sql.basehash", Boolean.toString(injectHash)) injectSysConfig("dd.experimental.propagate.process.tags.enabled", Boolean.toString(processTagsEnabled)) ProcessTags.reset() - ContainerInfo.get().setContainerTagsHash(containerTagsHash) + BaseHash.updateBaseHash(baseHash) expect: - ContainerInfo.get().getContainerTagsHash() == containerTagsHash - and: Config.get().isExperimentalPropagateProcessTagsEnabled() == processTagsEnabled and: SQLCommenter.inject(query, "", "", "", "", "", false) == result where: - query | injectHash | containerTagsHash | processTagsEnabled | srv | result - "SELECT *" | true | null | false | "" | "SELECT *" - "SELECT *" | true | null | true | "" | "SELECT *" - "SELECT *" | true | "234563" | false | "" | "SELECT *" - "SELECT *" | true | "234563" | true | "" | "/*ddsh='5036687995954831329'*/ SELECT *" - "SELECT *" | true | "345342" | false | "" | "SELECT *" - "SELECT *" | true | "345342" | true | "" | "/*ddsh='9119195684516789447'*/ SELECT *" - "SELECT *" | true | null | false | "srv" | "/*ddps='srv'*/ SELECT *" - "SELECT *" | true | null | true | "srv" | "/*ddps='srv'*/ SELECT *" - "SELECT *" | true | "234563" | false | "srv" | "/*ddps='srv'*/ SELECT *" - "SELECT *" | true | "234563" | true | "srv" | "/*ddps='srv',ddsh='-4976804795059740068'*/ SELECT *" - "SELECT *" | true | "345342" | false | "srv" | "/*ddps='srv'*/ SELECT *" - "SELECT *" | true | "345342" | true | "srv" | "/*ddps='srv',ddsh='-221156394106738098'*/ SELECT *" - "SELECT *" | false | null | true | "" | "SELECT *" - "SELECT *" | false | "234563" | true | "" | "SELECT *" - "SELECT *" | false | "234563" | true | "srv" | "/*ddps='srv'*/ SELECT *" - "SELECT *" | false | "345342" | true | "srv" | "/*ddps='srv'*/ SELECT *" - "/*ddsh='-3750763034362895579'*/ SELECT *" | true | null | false | "" | "/*ddsh='-3750763034362895579'*/ SELECT *" - "/*ddsh='-3750763034362895579'*/ SELECT *" | true | "234563" | true | "" | "/*ddsh='-3750763034362895579'*/ SELECT *" + query | injectHash | baseHash | processTagsEnabled | srv | result + "SELECT *" | true | 234563 | false | "" | "SELECT *" + "SELECT *" | true | 234563 | true | "" | "/*ddsh='234563'*/ SELECT *" + "SELECT *" | true | 345342 | false | "" | "SELECT *" + "SELECT *" | true | 345342 | true | "" | "/*ddsh='345342'*/ SELECT *" + "SELECT *" | true | 234563 | false | "srv" | "/*ddps='srv'*/ SELECT *" + "SELECT *" | true | 234563 | true | "srv" | "/*ddps='srv',ddsh='234563'*/ SELECT *" + "SELECT *" | true | 345342 | false | "srv" | "/*ddps='srv'*/ SELECT *" + "SELECT *" | true | 345342 | true | "srv" | "/*ddps='srv',ddsh='345342'*/ SELECT *" + "SELECT *" | false | 234563 | true | "" | "SELECT *" + "SELECT *" | false | 234563 | true | "srv" | "/*ddps='srv'*/ SELECT *" + "SELECT *" | false | 345342 | true | "srv" | "/*ddps='srv'*/ SELECT *" + "/*ddsh='-3750763034362895579'*/ SELECT *" | true | 234563 | true | "" | "/*ddsh='-3750763034362895579'*/ SELECT *" } def "test encode Sql Comment with peer service"() { diff --git a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/AgentTestRunner.groovy b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/AgentTestRunner.groovy index 8c70e25d876..3d8c9eb808e 100644 --- a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/AgentTestRunner.groovy +++ b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/AgentTestRunner.groovy @@ -30,7 +30,6 @@ import datadog.trace.api.IdGenerationStrategy import datadog.trace.api.ProcessTags import datadog.trace.api.StatsDClient import datadog.trace.api.TraceConfig -import datadog.trace.api.WellKnownTags import datadog.trace.api.config.GeneralConfig import datadog.trace.api.config.TracerConfig import datadog.trace.api.gateway.RequestContext @@ -362,8 +361,7 @@ abstract class AgentTestRunner extends DDSpecification implements AgentBuilder.L // Fast enough so tests don't take forever long bucketDuration = dataStreamsBucketDuration() - WellKnownTags wellKnownTags = new WellKnownTags("runtimeid", "hostname", "my-env", "service", "version", "language") - TEST_DATA_STREAMS_MONITORING = new DefaultDataStreamsMonitoring(sink, features, SystemTimeSource.INSTANCE, { MOCK_DSM_TRACE_CONFIG }, wellKnownTags, TEST_DATA_STREAMS_WRITER, bucketDuration) + TEST_DATA_STREAMS_MONITORING = new DefaultDataStreamsMonitoring(sink, features, SystemTimeSource.INSTANCE, { MOCK_DSM_TRACE_CONFIG }, TEST_DATA_STREAMS_WRITER, bucketDuration) TEST_WRITER = new ListWriter() diff --git a/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultDataStreamsMonitoring.java b/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultDataStreamsMonitoring.java index 95950f73f44..c075f94b417 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultDataStreamsMonitoring.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultDataStreamsMonitoring.java @@ -7,14 +7,11 @@ import static datadog.trace.util.AgentThreadFactory.THREAD_JOIN_TIMOUT_MS; import static datadog.trace.util.AgentThreadFactory.newAgentThread; -import datadog.common.container.ContainerInfo; import datadog.communication.ddagent.DDAgentFeaturesDiscovery; import datadog.communication.ddagent.SharedCommunicationObjects; import datadog.context.propagation.Propagator; -import datadog.trace.api.BaseHash; import datadog.trace.api.Config; import datadog.trace.api.TraceConfig; -import datadog.trace.api.WellKnownTags; import datadog.trace.api.datastreams.*; import datadog.trace.api.experimental.DataStreamsContextCarrier; import datadog.trace.api.time.TimeSource; @@ -55,7 +52,6 @@ public class DefaultDataStreamsMonitoring implements DataStreamsMonitoring, Even private final DatastreamsPayloadWriter payloadWriter; private final DDAgentFeaturesDiscovery features; private final TimeSource timeSource; - private final long hashOfKnownTags; private final Supplier traceConfigSupplier; private final long bucketDurationNanos; private final Thread thread; @@ -98,7 +94,6 @@ public DefaultDataStreamsMonitoring( features, timeSource, traceConfigSupplier, - config.getWellKnownTags(), new MsgPackDatastreamsPayloadWriter( sink, config.getWellKnownTags(), DDTraceCoreInfo.VERSION, config.getPrimaryTag()), Config.get().getDataStreamsBucketDurationNanoseconds()); @@ -109,18 +104,11 @@ public DefaultDataStreamsMonitoring( DDAgentFeaturesDiscovery features, TimeSource timeSource, Supplier traceConfigSupplier, - WellKnownTags wellKnownTags, DatastreamsPayloadWriter payloadWriter, long bucketDurationNanos) { this.features = features; this.timeSource = timeSource; this.traceConfigSupplier = traceConfigSupplier; - this.hashOfKnownTags = - BaseHash.getBaseHash( - wellKnownTags.getService(), - wellKnownTags.getEnv(), - ContainerInfo.get() - .getContainerTagsHash()); // TODO container tags hash is not available yet this.payloadWriter = payloadWriter; this.bucketDurationNanos = bucketDurationNanos; @@ -129,9 +117,6 @@ public DefaultDataStreamsMonitoring( schemaSamplers = new ConcurrentHashMap<>(); this.propagator = new DataStreamsPropagator(this, this.timeSource, serviceNameOverride); - // configure global tags behavior - DataStreamsTags.setGlobalBaseHash( - this.hashOfKnownTags); // TODO has to be updated once containerTagsHash is available DataStreamsTags.setServiceNameOverride(serviceNameOverride); } diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/datastreams/DefaultDataStreamsMonitoringTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/datastreams/DefaultDataStreamsMonitoringTest.groovy index bf7de275af9..1a2a4c680c8 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/core/datastreams/DefaultDataStreamsMonitoringTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/datastreams/DefaultDataStreamsMonitoringTest.groovy @@ -3,7 +3,6 @@ package datadog.trace.core.datastreams import datadog.communication.ddagent.DDAgentFeaturesDiscovery import datadog.trace.api.Config import datadog.trace.api.TraceConfig -import datadog.trace.api.WellKnownTags import datadog.trace.api.datastreams.DataStreamsTags import datadog.trace.api.datastreams.StatsPoint import datadog.trace.api.experimental.DataStreamsContextCarrier @@ -20,8 +19,6 @@ import static DefaultDataStreamsMonitoring.FEATURE_CHECK_INTERVAL_NANOS import static java.util.concurrent.TimeUnit.SECONDS class DefaultDataStreamsMonitoringTest extends DDCoreSpecification { - def wellKnownTags = new WellKnownTags("runtimeid", "hostname", "testing", "service", "version", "java") - static final DEFAULT_BUCKET_DURATION_NANOS = Config.get().getDataStreamsBucketDurationNanoseconds() def "No payloads written if data streams not supported or not enabled"() { @@ -39,7 +36,7 @@ class DefaultDataStreamsMonitoringTest extends DDCoreSpecification { } when: - def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, wellKnownTags, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) + def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) dataStreams.start() dataStreams.add(new StatsPoint(DataStreamsTags.create("testType", null, "testTopic", "testGroup", null), 0, 0, 0, timeSource.currentTimeNanos, 0, 0, 0, null)) dataStreams.report() @@ -75,7 +72,7 @@ class DefaultDataStreamsMonitoringTest extends DDCoreSpecification { } when: - def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, wellKnownTags, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) + def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) then: // the first received schema is sampled, with a weight of one. @@ -129,7 +126,7 @@ class DefaultDataStreamsMonitoringTest extends DDCoreSpecification { } when: - def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, wellKnownTags, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) + def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) dataStreams.start() def tg = DataStreamsTags.create("testType", null, "testTopic", "testGroup", null) dataStreams.add(new StatsPoint(tg, 1, 2, 3, timeSource.currentTimeNanos, 0, 0, 0, null)) @@ -178,7 +175,7 @@ class DefaultDataStreamsMonitoringTest extends DDCoreSpecification { } when: - def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, wellKnownTags, payloadWriter, bucketDuration) + def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, payloadWriter, bucketDuration) dataStreams.start() def tg = DataStreamsTags.create("testType", null, "testTopic", "testGroup", null) dataStreams.add(new StatsPoint(tg, 1, 2, 3, timeSource.currentTimeNanos, 0, 0, 0, null)) @@ -224,7 +221,7 @@ class DefaultDataStreamsMonitoringTest extends DDCoreSpecification { } when: - def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, wellKnownTags, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) + def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) dataStreams.start() def tg = DataStreamsTags.create("testType", null, "testTopic", "testGroup", null) dataStreams.add(new StatsPoint(tg, 1, 2, 3, timeSource.currentTimeNanos, 0, 0, 0, null)) @@ -273,7 +270,7 @@ class DefaultDataStreamsMonitoringTest extends DDCoreSpecification { } when: - def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, wellKnownTags, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) + def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) dataStreams.start() def tg = DataStreamsTags.create("testType", null, "testTopic", "testGroup", null) def tg2 = DataStreamsTags.create("testType", null, "testTopic2", "testGroup", null) @@ -335,7 +332,7 @@ class DefaultDataStreamsMonitoringTest extends DDCoreSpecification { } when: - def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, wellKnownTags, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) + def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) dataStreams.start() dataStreams.trackBacklog(DataStreamsTags.createWithPartition("kafka_commit", "testTopic", "2", null, "testGroup"), 23) dataStreams.trackBacklog(DataStreamsTags.createWithPartition("kafka_commit", "testTopic", "2", null, "testGroup"), 24) @@ -389,7 +386,7 @@ class DefaultDataStreamsMonitoringTest extends DDCoreSpecification { } when: - def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, wellKnownTags, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) + def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) dataStreams.start() def tg = DataStreamsTags.create("testType", null, "testTopic", "testGroup", null) dataStreams.add(new StatsPoint(tg, 1, 2, 5, timeSource.currentTimeNanos, 0, 0, 0, null)) @@ -453,7 +450,7 @@ class DefaultDataStreamsMonitoringTest extends DDCoreSpecification { when: def tg = DataStreamsTags.create("testType", null, "testTopic", "testGroup", null) - def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, wellKnownTags, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) + def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) dataStreams.start() dataStreams.add(new StatsPoint(tg, 1, 2, 1, timeSource.currentTimeNanos, 0, 0, 0, null)) timeSource.advance(DEFAULT_BUCKET_DURATION_NANOS - 100l) @@ -533,7 +530,7 @@ class DefaultDataStreamsMonitoringTest extends DDCoreSpecification { } when: "reporting points when data streams is not supported" - def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, wellKnownTags, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) + def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) dataStreams.start() def tg = DataStreamsTags.create("testType", null, "testTopic", "testGroup", null) dataStreams.add(new StatsPoint(tg, 1, 2, 3, timeSource.currentTimeNanos, 0, 0, 0, null)) @@ -610,7 +607,7 @@ class DefaultDataStreamsMonitoringTest extends DDCoreSpecification { } when: "reporting points after a downgrade" - def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, wellKnownTags, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) + def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) dataStreams.start() supportsDataStreaming = false dataStreams.onEvent(EventListener.EventType.DOWNGRADED, "") @@ -678,7 +675,7 @@ class DefaultDataStreamsMonitoringTest extends DDCoreSpecification { when: "reporting points when data streams is not enabled" def tg = DataStreamsTags.create("testType", null, "testTopic", "testGroup", null) - def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, wellKnownTags, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) + def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) dataStreams.start() dataStreams.add(new StatsPoint(tg, 1, 2, 3, timeSource.currentTimeNanos, 0, 0, 0, null)) timeSource.advance(DEFAULT_BUCKET_DURATION_NANOS) @@ -763,7 +760,7 @@ class DefaultDataStreamsMonitoringTest extends DDCoreSpecification { } when: "reporting points when data streams is not supported" - def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, wellKnownTags, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) + def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) dataStreams.start() def tg = DataStreamsTags.create("testType", null, "testTopic", "testGroup", null) dataStreams.add(new StatsPoint(tg, 1, 2, 3, timeSource.currentTimeNanos, 0, 0, 0, null)) @@ -842,7 +839,7 @@ class DefaultDataStreamsMonitoringTest extends DDCoreSpecification { } when: "reporting points when data streams is not supported" - def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, wellKnownTags, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) + def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) dataStreams.start() def tg = DataStreamsTags.create("testType", null, "testTopic", "testGroup", null) dataStreams.add(new StatsPoint(tg, 1, 2, 3, timeSource.currentTimeNanos, 0, 0, 0, null)) diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/datastreams/DefaultPathwayContextTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/datastreams/DefaultPathwayContextTest.groovy index 8ea4c7ec23b..77b4fb574e4 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/core/datastreams/DefaultPathwayContextTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/datastreams/DefaultPathwayContextTest.groovy @@ -1,11 +1,11 @@ package datadog.trace.core.datastreams import datadog.communication.ddagent.DDAgentFeaturesDiscovery +import datadog.trace.api.BaseHash import datadog.trace.api.Config import datadog.trace.api.DDTraceId import datadog.trace.api.TagMap import datadog.trace.api.TraceConfig -import datadog.trace.api.WellKnownTags import datadog.trace.api.datastreams.DataStreamsTags import datadog.trace.api.datastreams.StatsPoint import datadog.trace.api.time.ControllableTimeSource @@ -24,7 +24,6 @@ import static datadog.trace.api.datastreams.PathwayContext.PROPAGATION_KEY_BASE6 import static java.util.concurrent.TimeUnit.MILLISECONDS class DefaultPathwayContextTest extends DDCoreSpecification { - def wellKnownTags = new WellKnownTags("runtimeid", "hostname", "testing", "service", "version", "java") long baseHash = 12 static final DEFAULT_BUCKET_DURATION_NANOS = Config.get().getDataStreamsBucketDurationNanoseconds() @@ -467,9 +466,9 @@ class DefaultPathwayContextTest extends DDCoreSpecification { AgentTracer.TracerAPI originalTracer = AgentTracer.get() AgentTracer.forceRegister(tracerApi) - def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { globalTraceConfig }, wellKnownTags, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) + def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { globalTraceConfig }, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) - DataStreamsTags.setGlobalBaseHash(baseHash) + BaseHash.updateBaseHash(baseHash) def context = new DefaultPathwayContext(timeSource, null) timeSource.advance(MILLISECONDS.toNanos(50)) context.setCheckpoint(fromTags(DataStreamsTags.create("internal", DataStreamsTags.Direction.Inbound)), pointConsumer) @@ -521,9 +520,9 @@ class DefaultPathwayContextTest extends DDCoreSpecification { AgentTracer.TracerAPI originalTracer = AgentTracer.get() AgentTracer.forceRegister(tracerApi) - def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { globalTraceConfig }, wellKnownTags, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) + def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { globalTraceConfig }, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) - DataStreamsTags.setGlobalBaseHash(baseHash) + BaseHash.updateBaseHash(baseHash) def context = new DefaultPathwayContext(timeSource, null) timeSource.advance(MILLISECONDS.toNanos(50)) context.setCheckpoint(fromTags(DataStreamsTags.create("internal", DataStreamsTags.Direction.Inbound)), pointConsumer) @@ -575,10 +574,9 @@ class DefaultPathwayContextTest extends DDCoreSpecification { AgentTracer.TracerAPI originalTracer = AgentTracer.get() AgentTracer.forceRegister(tracerApi) - def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { globalTraceConfig }, - wellKnownTags, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) + def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { globalTraceConfig }, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) - DataStreamsTags.setGlobalBaseHash(baseHash) + BaseHash.updateBaseHash(baseHash) def context = new DefaultPathwayContext(timeSource, null) timeSource.advance(MILLISECONDS.toNanos(50)) context.setCheckpoint(fromTags(DataStreamsTags.create("internal", DataStreamsTags.Direction.Inbound)), pointConsumer) @@ -630,8 +628,7 @@ class DefaultPathwayContextTest extends DDCoreSpecification { isDataStreamsEnabled() >> true } - def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, - wellKnownTags, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) + def dataStreams = new DefaultDataStreamsMonitoring(sink, features, timeSource, { traceConfig }, payloadWriter, DEFAULT_BUCKET_DURATION_NANOS) Map carrier = ["someotherkey": "someothervalue"] def contextVisitor = new Base64MapContextVisitor() diff --git a/internal-api/src/main/java/datadog/trace/api/BaseHash.java b/internal-api/src/main/java/datadog/trace/api/BaseHash.java index ffb8695a253..c3feedf3837 100644 --- a/internal-api/src/main/java/datadog/trace/api/BaseHash.java +++ b/internal-api/src/main/java/datadog/trace/api/BaseHash.java @@ -3,18 +3,39 @@ import datadog.trace.util.FNV64Hash; public final class BaseHash { + private static volatile long baseHash; + private static volatile String baseHashStr; - public static long getBaseHash( - CharSequence serviceName, CharSequence env, String containerTagsHash) { - return getBaseHash( - serviceName, - env, + private BaseHash() {} + + public static void recalcBaseHash(String containerTagsHash) { + long hash = calc(containerTagsHash); + updateBaseHash(hash); + } + + public static void updateBaseHash(long hash) { + baseHash = hash; + baseHashStr = Long.toString(hash); + } + + public static long getBaseHash() { + return baseHash; + } + + public static String getBaseHashStr() { + return baseHashStr; + } + + public static long calc(String containerTagsHash) { + return calc( + Config.get().getServiceName(), + Config.get().getEnv(), Config.get().getPrimaryTag(), ProcessTags.getTagsForSerialization(), containerTagsHash); } - private static long getBaseHash( + private static long calc( CharSequence serviceName, CharSequence env, String primaryTag, diff --git a/internal-api/src/main/java/datadog/trace/api/datastreams/DataStreamsTags.java b/internal-api/src/main/java/datadog/trace/api/datastreams/DataStreamsTags.java index 938d8d953f2..bcd0e7f70a3 100644 --- a/internal-api/src/main/java/datadog/trace/api/datastreams/DataStreamsTags.java +++ b/internal-api/src/main/java/datadog/trace/api/datastreams/DataStreamsTags.java @@ -1,5 +1,6 @@ package datadog.trace.api.datastreams; +import datadog.trace.api.BaseHash; import datadog.trace.util.FNV64Hash; import java.util.Objects; @@ -52,7 +53,6 @@ public enum Direction { public static final String KAFKA_CLUSTER_ID_TAG = "kafka_cluster_id"; private static volatile ThreadLocal serviceNameOverride; - private static volatile long baseHash; public static byte[] longToBytes(long val) { return new byte[] { @@ -260,10 +260,6 @@ public static void setServiceNameOverride(ThreadLocal serviceNameOverrid DataStreamsTags.serviceNameOverride = serviceNameOverride; } - public static void setGlobalBaseHash(long hash) { - DataStreamsTags.baseHash = hash; - } - public static DataStreamsTags createWithClusterId( String type, Direction direction, String topic, String clusterId) { return new DataStreamsTags( @@ -329,9 +325,7 @@ public DataStreamsTags( kafkaClusterId != null ? KAFKA_CLUSTER_ID_TAG + ":" + kafkaClusterId : null; this.partition = partition != null ? PARTITION_TAG + ":" + partition : null; - if (DataStreamsTags.baseHash != 0) { - this.hash = DataStreamsTags.baseHash; - } + this.hash = BaseHash.getBaseHash(); if (DataStreamsTags.serviceNameOverride != null) { String val = DataStreamsTags.serviceNameOverride.get(); diff --git a/internal-api/src/test/groovy/datadog/trace/api/BaseHashTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/BaseHashTest.groovy index 6177e00ca7c..f3de2b39045 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/BaseHashTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/BaseHashTest.groovy @@ -2,17 +2,41 @@ package datadog.trace.api import datadog.trace.test.util.DDSpecification +import static datadog.trace.api.config.GeneralConfig.ENV import static datadog.trace.api.config.GeneralConfig.EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED import static datadog.trace.api.config.GeneralConfig.PRIMARY_TAG +import static datadog.trace.api.config.GeneralConfig.SERVICE_NAME class BaseHashTest extends DDSpecification { + def "Service used in hash calculation"() { + when: + def firstBaseHash = BaseHash.calc(null) + + injectSysConfig(SERVICE_NAME, "service-1") + def secondBaseHash = BaseHash.calc(null) + + then: + firstBaseHash != secondBaseHash + } + + def "Env used in hash calculation"() { + when: + def firstBaseHash = BaseHash.calc(null) + + injectSysConfig(ENV, "env-1") + def secondBaseHash = BaseHash.calc(null) + + then: + firstBaseHash != secondBaseHash + } + def "Primary tag used in hash calculation"() { when: - def firstBaseHash = BaseHash.getBaseHash("service", "env", null) + def firstBaseHash = BaseHash.calc(null) injectSysConfig(PRIMARY_TAG, "region-2") - def secondBaseHash = BaseHash.getBaseHash("service", "env", null) + def secondBaseHash = BaseHash.calc(null) then: firstBaseHash != secondBaseHash @@ -20,12 +44,12 @@ class BaseHashTest extends DDSpecification { def "Process Tags used in hash calculation"() { when: - def firstBaseHash = BaseHash.getBaseHash("service", "env", null) + def firstBaseHash = BaseHash.calc(null) injectSysConfig(EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED, "true") ProcessTags.reset() ProcessTags.addTag("000", "first") - def secondBaseHash = BaseHash.getBaseHash("service", "env", null) + def secondBaseHash = BaseHash.calc(null) then: firstBaseHash != secondBaseHash @@ -40,10 +64,10 @@ class BaseHashTest extends DDSpecification { injectSysConfig(EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED, propagateTagsEnabled.toString()) ProcessTags.reset() ProcessTags.addTag("000", "first") - def firstBaseHash = BaseHash.getBaseHash("service", "env", null) + def firstBaseHash = BaseHash.calc(null) then: - def secondBaseHash = BaseHash.getBaseHash("service", "env", "") + def secondBaseHash = BaseHash.calc("") expect: if (propagateTagsEnabled) { diff --git a/internal-api/src/test/groovy/datadog/trace/api/datastreams/DataStreamsTagsTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/datastreams/DataStreamsTagsTest.groovy index ef73cfaae4c..e56279dbac1 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/datastreams/DataStreamsTagsTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/datastreams/DataStreamsTagsTest.groovy @@ -1,5 +1,6 @@ package datadog.trace.api.datastreams +import datadog.trace.api.BaseHash import spock.lang.Specification import java.nio.ByteBuffer @@ -15,7 +16,6 @@ class DataStreamsTagsTest extends Specification { setup: def tg = getTags(0) - expect: tg.getBus() == DataStreamsTags.BUS_TAG + ":bus0" tg.getDirection() == DataStreamsTags.DIRECTION_TAG + ":out" @@ -80,7 +80,7 @@ class DataStreamsTagsTest extends Specification { DataStreamsTags.setServiceNameOverride(serviceName) def two = getTags(0) - DataStreamsTags.setGlobalBaseHash(12) + BaseHash.updateBaseHash(12) def three = getTags(0) expect: From ac2eb86cf11845031075ae6373574c85cab92f35 Mon Sep 17 00:00:00 2001 From: Yury Gribkov Date: Fri, 29 Aug 2025 12:51:27 -0700 Subject: [PATCH 11/12] Sync when update containerTagsHash --- .../communication/ddagent/DDAgentFeaturesDiscovery.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/communication/src/main/java/datadog/communication/ddagent/DDAgentFeaturesDiscovery.java b/communication/src/main/java/datadog/communication/ddagent/DDAgentFeaturesDiscovery.java index d1b425e7d09..271b3f89254 100644 --- a/communication/src/main/java/datadog/communication/ddagent/DDAgentFeaturesDiscovery.java +++ b/communication/src/main/java/datadog/communication/ddagent/DDAgentFeaturesDiscovery.java @@ -232,9 +232,11 @@ private void processInfoResponseHeaders(Response response) { String newContainerTagsHash = response.header(DATADOG_CONTAINER_TAGS_HASH); if (newContainerTagsHash != null) { ContainerInfo containerInfo = ContainerInfo.get(); - if (!newContainerTagsHash.equals(containerInfo.getContainerTagsHash())) { - containerInfo.setContainerTagsHash(newContainerTagsHash); - BaseHash.recalcBaseHash(newContainerTagsHash); + synchronized (containerInfo) { + if (!newContainerTagsHash.equals(containerInfo.getContainerTagsHash())) { + containerInfo.setContainerTagsHash(newContainerTagsHash); + BaseHash.recalcBaseHash(newContainerTagsHash); + } } } } From 23ef6fd9d34c2caf07f01baa0faf16c221f5f976 Mon Sep 17 00:00:00 2001 From: Yury Gribkov Date: Wed, 3 Sep 2025 19:04:13 -0700 Subject: [PATCH 12/12] Fix DBMInjectionForkedTest --- ...BMCompatibleConnectionInstrumentation.java | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DBMCompatibleConnectionInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DBMCompatibleConnectionInstrumentation.java index c37546832c5..0e98e356935 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DBMCompatibleConnectionInstrumentation.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DBMCompatibleConnectionInstrumentation.java @@ -111,24 +111,26 @@ public static String onEnter( @Advice.This Connection connection, @Advice.Argument(value = 0, readOnly = false) String sql) { // Using INJECT_COMMENT fails to update when a test calls injectSysConfig - if (DECORATE.shouldInjectSQLComment()) { - final int callDepth = CallDepthThreadLocalMap.incrementCallDepth(Connection.class); - if (callDepth > 0) { - return null; - } - final DBInfo dbInfo = - JDBCDecorator.parseDBInfo( - connection, InstrumentationContext.get(Connection.class, DBInfo.class)); - String dbService = DECORATE.getDbService(dbInfo); - if (dbService != null) { - dbService = - traceConfig(activeSpan()).getServiceMapping().getOrDefault(dbService, dbService); - } - boolean append = "sqlserver".equals(dbInfo.getType()); - return SQLCommenter.inject( - sql, dbService, dbInfo.getType(), dbInfo.getHost(), dbInfo.getDb(), null, append); + if (!DECORATE.shouldInjectSQLComment()) { + return sql; } - return sql; + if (CallDepthThreadLocalMap.incrementCallDepth(Connection.class) > 0) { + return null; + } + final String inputSql = sql; + final DBInfo dbInfo = + JDBCDecorator.parseDBInfo( + connection, InstrumentationContext.get(Connection.class, DBInfo.class)); + String dbService = DECORATE.getDbService(dbInfo); + if (dbService != null) { + dbService = + traceConfig(activeSpan()).getServiceMapping().getOrDefault(dbService, dbService); + } + boolean append = "sqlserver".equals(dbInfo.getType()); + sql = + SQLCommenter.inject( + sql, dbService, dbInfo.getType(), dbInfo.getHost(), dbInfo.getDb(), null, append); + return inputSql; } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)