diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/AbstractConnectionInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/AbstractConnectionInstrumentation.java index a19e2cd345d..1baf5a38499 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/AbstractConnectionInstrumentation.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/AbstractConnectionInstrumentation.java @@ -33,7 +33,7 @@ public Map contextStore() { @Override public String[] helperClassNames() { return new String[] { - packageName + ".JDBCDecorator", + "datadog.trace.core.propagation.W3CTraceParent", packageName + ".JDBCDecorator", }; } diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/AbstractPreparedStatementInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/AbstractPreparedStatementInstrumentation.java index 016e1ed8d88..a8e94fae86a 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/AbstractPreparedStatementInstrumentation.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/AbstractPreparedStatementInstrumentation.java @@ -40,7 +40,7 @@ public AbstractPreparedStatementInstrumentation( @Override public String[] helperClassNames() { return new String[] { - packageName + ".JDBCDecorator", + "datadog.trace.core.propagation.W3CTraceParent", packageName + ".JDBCDecorator", }; } 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 1b52f827bda..4d0de9e3b27 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 @@ -78,6 +78,7 @@ public DBMCompatibleConnectionInstrumentation() { @Override public String[] helperClassNames() { return new String[] { + "datadog.trace.core.propagation.W3CTraceParent", packageName + ".JDBCDecorator", packageName + ".SQLCommenter", "datadog.trace.bootstrap.instrumentation.dbm.SharedDBCommenter", diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DriverInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DriverInstrumentation.java index c5c266ed312..27fc191fbed 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DriverInstrumentation.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DriverInstrumentation.java @@ -49,7 +49,7 @@ public Map contextStore() { @Override public String[] helperClassNames() { return new String[] { - packageName + ".JDBCDecorator", + "datadog.trace.core.propagation.W3CTraceParent", packageName + ".JDBCDecorator", }; } 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 db38734d252..0a1630572ea 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 @@ -8,7 +8,6 @@ import static datadog.trace.bootstrap.instrumentation.api.Tags.*; import datadog.trace.api.Config; -import datadog.trace.api.DDSpanId; import datadog.trace.api.DDTraceId; import datadog.trace.api.naming.SpanNaming; import datadog.trace.api.telemetry.LogCollector; @@ -23,6 +22,7 @@ import datadog.trace.bootstrap.instrumentation.jdbc.DBInfo; import datadog.trace.bootstrap.instrumentation.jdbc.DBQueryInfo; import datadog.trace.bootstrap.instrumentation.jdbc.JDBCConnectionUrlParser; +import datadog.trace.core.propagation.W3CTraceParent; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.sql.Connection; @@ -257,16 +257,6 @@ private AgentSpan withQueryInfo(AgentSpan span, DBQueryInfo info, CharSequence c return span.setTag(Tags.COMPONENT, component); } - public String traceParent(AgentSpan span, int samplingPriority) { - StringBuilder sb = new StringBuilder(55); - sb.append("00-"); - sb.append(span.getTraceId().toHexString()); - sb.append('-'); - sb.append(DDSpanId.toHexStringPadded(span.getSpanId())); - sb.append(samplingPriority > 0 ? "-01" : "-00"); - return sb.toString(); - } - public boolean isOracle(final DBInfo dbInfo) { return "oracle".equals(dbInfo.getType()); } @@ -294,7 +284,7 @@ public void setAction(AgentSpan span, Connection connection) { if (priority == null) { return; } - final String traceContext = DD_INSTRUMENTATION_PREFIX + DECORATE.traceParent(span, priority); + final String traceContext = DD_INSTRUMENTATION_PREFIX + W3CTraceParent.from(span); connection.setClientInfo("OCSID.ACTION", traceContext); @@ -380,7 +370,7 @@ public void setApplicationName(AgentSpan span, Connection connection) { if (priority == null) { return; } - final String traceParent = DECORATE.traceParent(span, priority); + final String traceParent = W3CTraceParent.from(span); final String traceContext = "_DD_" + traceParent; connection.setClientInfo("ApplicationName", traceContext); 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 0de1423884a..5ff309de3cd 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 @@ -23,6 +23,7 @@ import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.AgentTracer; import datadog.trace.bootstrap.instrumentation.jdbc.DBInfo; +import datadog.trace.core.propagation.W3CTraceParent; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; @@ -59,6 +60,7 @@ public Map contextStore() { @Override public String[] helperClassNames() { return new String[] { + "datadog.trace.core.propagation.W3CTraceParent", packageName + ".JDBCDecorator", packageName + ".SQLCommenter", "datadog.trace.bootstrap.instrumentation.dbm.SharedDBCommenter", @@ -119,7 +121,7 @@ public static AgentScope onEnter( Integer priority = span.forceSamplingDecision(); if (priority != null) { if (!isSqlServer) { - traceParent = DECORATE.traceParent(span, priority); + traceParent = W3CTraceParent.from(span); } // set the dbm trace injected tag on the span span.setTag(DBM_TRACE_INJECTED, true); diff --git a/dd-java-agent/instrumentation/mongo/common/src/main/java/datadog/trace/instrumentation/mongo/MongoCommentInjector.java b/dd-java-agent/instrumentation/mongo/common/src/main/java/datadog/trace/instrumentation/mongo/MongoCommentInjector.java index a9ac9cf04c4..4028a059795 100644 --- a/dd-java-agent/instrumentation/mongo/common/src/main/java/datadog/trace/instrumentation/mongo/MongoCommentInjector.java +++ b/dd-java-agent/instrumentation/mongo/common/src/main/java/datadog/trace/instrumentation/mongo/MongoCommentInjector.java @@ -4,9 +4,9 @@ import static datadog.trace.bootstrap.instrumentation.api.InstrumentationTags.DBM_TRACE_INJECTED; import datadog.trace.api.Config; -import datadog.trace.api.DDSpanId; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.dbm.SharedDBCommenter; +import datadog.trace.core.propagation.W3CTraceParent; import org.bson.BsonArray; import org.bson.BsonDocument; import org.bson.BsonString; @@ -75,7 +75,7 @@ public static String buildComment(AgentSpan dbSpan, String hostname, String dbNa String dbService = dbSpan.getServiceName(); String traceParent = Config.get().getDbmPropagationMode().equals(DBM_PROPAGATION_MODE_FULL) - ? buildTraceParent(dbSpan) + ? W3CTraceParent.from(dbSpan) : null; // Use shared comment builder directly @@ -112,13 +112,4 @@ private static BsonValue mergeComment(BsonValue existingComment, String dbmComme // Incompatible type, preserve existing comment unchanged return existingComment; } - - static String buildTraceParent(AgentSpan span) { - // W3C traceparent format: version-traceId-spanId-flags - return "00-" // version - + span.getTraceId().toHexString() // traceId - + '-' - + DDSpanId.toHexStringPadded(span.getSpanId()) // spanId - + (span.context().getSamplingPriority() > 0 ? "-01" : "-00"); - } } diff --git a/dd-java-agent/instrumentation/mongo/common/src/test/groovy/MongoCommentInjectorTest.groovy b/dd-java-agent/instrumentation/mongo/common/src/test/groovy/MongoCommentInjectorTest.groovy index e3643609905..e562cfe6b74 100644 --- a/dd-java-agent/instrumentation/mongo/common/src/test/groovy/MongoCommentInjectorTest.groovy +++ b/dd-java-agent/instrumentation/mongo/common/src/test/groovy/MongoCommentInjectorTest.groovy @@ -1,6 +1,5 @@ import datadog.trace.agent.test.InstrumentationSpecification import datadog.trace.api.config.TraceInstrumentationConfig -import datadog.trace.api.sampling.PrioritySampling import datadog.trace.instrumentation.mongo.MongoCommentInjector import org.bson.BsonDocument import org.bson.BsonString @@ -18,38 +17,6 @@ abstract class BaseMongoCommentInjectorTest extends InstrumentationSpecification } class MongoCommentInjectorTest extends BaseMongoCommentInjectorTest { - def "buildTraceParent with sampled flag (SAMPLER_KEEP)"() { - setup: - def span = TEST_TRACER.buildSpan("test-op").start() - span.setSamplingPriority(PrioritySampling.SAMPLER_KEEP, 0) - - when: - String traceParent = MongoCommentInjector.buildTraceParent(span) - - then: - traceParent != null - traceParent ==~ /00-[0-9a-f]{32}-[0-9a-f]{16}-01/ - - cleanup: - span?.finish() - } - - def "buildTraceParent with not sampled flag (SAMPLER_DROP)"() { - setup: - def span = TEST_TRACER.buildSpan("test-op").start() - span.setSamplingPriority(PrioritySampling.SAMPLER_DROP, 0) - - when: - String traceParent = MongoCommentInjector.buildTraceParent(span) - - then: - traceParent != null - traceParent ==~ /00-[0-9a-f]{32}-[0-9a-f]{16}-00/ - - cleanup: - span?.finish() - } - def "injectComment returns null when event is null"() { when: BsonDocument result = MongoCommentInjector.injectComment("test-comment", null) diff --git a/dd-java-agent/instrumentation/mongo/driver-3.6/src/main/java/datadog/trace/instrumentation/mongo/DefaultServerConnection36Instrumentation.java b/dd-java-agent/instrumentation/mongo/driver-3.6/src/main/java/datadog/trace/instrumentation/mongo/DefaultServerConnection36Instrumentation.java index 894eac74b2b..bdf93a0febe 100644 --- a/dd-java-agent/instrumentation/mongo/driver-3.6/src/main/java/datadog/trace/instrumentation/mongo/DefaultServerConnection36Instrumentation.java +++ b/dd-java-agent/instrumentation/mongo/driver-3.6/src/main/java/datadog/trace/instrumentation/mongo/DefaultServerConnection36Instrumentation.java @@ -32,6 +32,7 @@ public String instrumentedType() { @Override public String[] helperClassNames() { return new String[] { + "datadog.trace.core.propagation.W3CTraceParent", packageName + ".BsonScrubber", packageName + ".MongoCommentInjector", packageName + ".MongoDecorator", diff --git a/dd-java-agent/instrumentation/mongo/driver-3.8/src/main/java/datadog/trace/instrumentation/mongo/DefaultServerConnection38Instrumentation.java b/dd-java-agent/instrumentation/mongo/driver-3.8/src/main/java/datadog/trace/instrumentation/mongo/DefaultServerConnection38Instrumentation.java index 14453fa8204..7512e30173e 100644 --- a/dd-java-agent/instrumentation/mongo/driver-3.8/src/main/java/datadog/trace/instrumentation/mongo/DefaultServerConnection38Instrumentation.java +++ b/dd-java-agent/instrumentation/mongo/driver-3.8/src/main/java/datadog/trace/instrumentation/mongo/DefaultServerConnection38Instrumentation.java @@ -33,6 +33,7 @@ public String instrumentedType() { public String[] helperClassNames() { return new String[] { "datadog.trace.bootstrap.instrumentation.dbm.SharedDBCommenter", + "datadog.trace.core.propagation.W3CTraceParent", packageName + ".MongoDecorator", packageName + ".MongoCommentInjector", packageName + ".BsonScrubber", diff --git a/dd-trace-core/src/main/java/datadog/trace/core/propagation/W3CHttpCodec.java b/dd-trace-core/src/main/java/datadog/trace/core/propagation/W3CHttpCodec.java index c201047fd01..1e1d442575e 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/propagation/W3CHttpCodec.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/propagation/W3CHttpCodec.java @@ -70,13 +70,8 @@ public void inject( } private void injectTraceParent(DDSpanContext context, C carrier, CarrierSetter setter) { - StringBuilder sb = new StringBuilder(TRACE_PARENT_LENGTH); - sb.append("00-"); - sb.append(context.getTraceId().toHexString()); - sb.append('-'); - sb.append(DDSpanId.toHexStringPadded(context.getSpanId())); - sb.append(context.getSamplingPriority() > 0 ? "-01" : "-00"); - setter.set(carrier, TRACE_PARENT_KEY, sb.toString()); + String traceparent = W3CTraceParent.from(context); + setter.set(carrier, TRACE_PARENT_KEY, traceparent); } private void injectTraceState(DDSpanContext context, C carrier, CarrierSetter setter) { diff --git a/dd-trace-core/src/main/java/datadog/trace/core/propagation/W3CTraceParent.java b/dd-trace-core/src/main/java/datadog/trace/core/propagation/W3CTraceParent.java new file mode 100644 index 00000000000..4a1b6eb822c --- /dev/null +++ b/dd-trace-core/src/main/java/datadog/trace/core/propagation/W3CTraceParent.java @@ -0,0 +1,48 @@ +package datadog.trace.core.propagation; + +import datadog.trace.api.DDSpanId; +import datadog.trace.api.DDTraceId; +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import datadog.trace.core.DDSpanContext; + +/** + * Utility class for building W3C traceparent headers. + * + * @see W3C Trace Context + */ +public final class W3CTraceParent { + + private static final int TRACE_PARENT_LENGTH = 55; + + private W3CTraceParent() {} + + /** + * Builds a W3C traceparent header value from the given trace context components. + * + *

Format: {@code ---} + * + * @param traceId the trace id + * @param spanId the span id + * @param isSampled whether the trace was sampled or not + * @return the W3C traceparent header value + */ + public static String from(DDTraceId traceId, long spanId, boolean isSampled) { + StringBuilder sb = new StringBuilder(TRACE_PARENT_LENGTH); + sb.append("00-"); + sb.append(traceId.toHexString()); + sb.append('-'); + sb.append(DDSpanId.toHexStringPadded(spanId)); + sb.append(isSampled ? "-01" : "-00"); + + return sb.toString(); + } + + public static String from(AgentSpan span) { + return from(span.getTraceId(), span.getSpanId(), span.context().getSamplingPriority() > 0); + } + + public static String from(DDSpanContext spanContext) { + return from( + spanContext.getTraceId(), spanContext.getSpanId(), spanContext.getSamplingPriority() > 0); + } +} diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/propagation/W3CTraceParentTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/propagation/W3CTraceParentTest.groovy new file mode 100644 index 00000000000..1e9ae585903 --- /dev/null +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/propagation/W3CTraceParentTest.groovy @@ -0,0 +1,32 @@ +package datadog.trace.core.propagation + +import datadog.trace.api.DDTraceId +import datadog.trace.test.util.DDSpecification + +class W3CTraceParentTest extends DDSpecification { + + def "build produces correct format with isSampled=#isSampled"() { + when: + def result = W3CTraceParent.from(traceId, spanId, isSampled) + + then: + result == expected + + where: + traceId | spanId | isSampled | expected + DDTraceId.from(1) | 2 | true | "00-00000000000000000000000000000001-0000000000000002-01" + DDTraceId.from(1) | 2 | false | "00-00000000000000000000000000000001-0000000000000002-00" + DDTraceId.from(1) | 2 | true | "00-00000000000000000000000000000001-0000000000000002-01" + DDTraceId.fromHex("0af7651916cd43dd8448eb211c80319c") | 0x00f067aa0ba902b7L | true | "00-0af7651916cd43dd8448eb211c80319c-00f067aa0ba902b7-01" + DDTraceId.from(Long.MAX_VALUE) | Long.MAX_VALUE | true | "00-00000000000000007fffffffffffffff-7fffffffffffffff-01" + } + + def "build matches W3C traceparent format"() { + when: + def result = W3CTraceParent.from(DDTraceId.from(123456789L), 987654321L, true) + + then: + // W3C format: version-traceId(32 hex)-spanId(16 hex)-flags(2 hex) + result ==~ /00-[0-9a-f]{32}-[0-9a-f]{16}-(00|01)/ + } +}