diff --git a/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java b/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java index 4bc10d31054..8dbc38dc67c 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java @@ -1949,7 +1949,7 @@ protected static final AgentSpan startSpan( if (parentSpanContext != null && parentSpanContext.isRemote()) { // Preserve AppSec/IAST request context before dropping the remote parent: when // extract=IGNORE or RESTART the TagContext parent is nulled before buildSpanContext - // can copy requestContextDataAppSec/Iast into DDSpanContext. + // can copy requestContextDataAppSec/Iast onto the trace collector. if (parentSpanContext instanceof TagContext) { TagContext tc = (TagContext) parentSpanContext; if (builderRequestContextDataAppSec == null) { diff --git a/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/PTagsCodec.java b/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/PTagsCodec.java index 29867d08d83..c1e6c908a8e 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/PTagsCodec.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/PTagsCodec.java @@ -361,8 +361,20 @@ protected int appendSuffix(StringBuilder sb, PTags ptags, int size, SamplingStat protected abstract boolean isEmpty(StringBuilder sb, int size); + /** + * Whether values of {@code tagKey} are validated. {@link #validateTagValue} checks only these, so + * a key missing here goes unvalidated everywhere rather than only where this is consulted. + */ + static boolean hasValidatedValues(TagKey tagKey) { + return tagKey.equals(DECISION_MAKER_TAG) + || tagKey.equals(TRACE_ID_TAG) + || tagKey.equals(TRACE_SOURCE_TAG); + } + protected static boolean validateTagValue(TagKey tagKey, TagValue tagValue) { - if (tagKey.equals(DECISION_MAKER_TAG) && !validateDecisionMakerTag(tagValue)) { + if (!hasValidatedValues(tagKey)) { + return true; + } else if (tagKey.equals(DECISION_MAKER_TAG) && !validateDecisionMakerTag(tagValue)) { return false; } else if (tagKey.equals(TRACE_ID_TAG) && !validateTraceId(tagValue)) { return false; diff --git a/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/PTagsFactory.java b/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/PTagsFactory.java index 9add16a41e0..997fada2b3b 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/PTagsFactory.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/PTagsFactory.java @@ -955,7 +955,8 @@ public void updateW3CTracestate(String tracestate) { @Override public void updateW3CTracestateFrom(W3CTracestate source, int overridingPriority) { if (source.rawOtelTraceState == null) { - setW3CTracestate(source.tracestate, W3CPTagsCodec.extractOtelTraceState(source.tracestate)); + // the parse already looked for an otel member, so there is none + setW3CTracestate(source.tracestate, null); return; } // Keep the otel member unparsed; its consistency checks wait for the first read diff --git a/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/W3CPTagsCodec.java b/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/W3CPTagsCodec.java index 9f292518b89..96c341a3fdf 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/W3CPTagsCodec.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/W3CPTagsCodec.java @@ -199,6 +199,11 @@ private static R parse(String value, Result result) { } else { TagKey tagKey = TagKey.from(Encoding.W3C, value, tagPos, tagKeyEndsAt); if (tagKey != null) { + if (!result.keepsDatadogTags() && !hasValidatedValues(tagKey)) { + // Its value is never read, and it can't be invalid, so it changes nothing + tagPos = nextTagPos; + continue; + } TagValue tagValue = tagValue(Encoding.W3C, tagKey, value, tagValuePos, tagValueEndsAt); if (!tagKey.equals(UPSTREAM_SERVICES_DEPRECATED_TAG)) { if (!validateTagValue(tagKey, tagValue)) { @@ -1027,6 +1032,12 @@ private static int memberContributionSize( /** What a parse of a tracestate header turns into, at each of its outcomes. */ private interface Result { + /** + * Whether the {@code dd} member's tags are kept. If not, they're only checked for validity, + * which decides between {@link #parsed} and {@link #withoutDatadogTags}. + */ + boolean keepsDatadogTags(); + /** The header is malformed, so nothing from it is kept. */ R rejected(); @@ -1068,6 +1079,11 @@ private static final class PTagsResult implements Result { this.tagsFactory = tagsFactory; } + @Override + public boolean keepsDatadogTags() { + return true; + } + @Override public PropagationTags rejected() { return tagsFactory.empty(); @@ -1137,6 +1153,11 @@ public PropagationTags parsed( private static final Result MERGE_RESULT = new Result() { + @Override + public boolean keepsDatadogTags() { + return false; + } + @Override public W3CTracestate rejected() { return W3CTracestate.NONE;