Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
5b1eb35
Provide optimized writers for OpenTelemetry's "trace.proto" wire prot…
mcculls Apr 12, 2026
52fd676
Relax unboxing of number types in Otel attributes
mcculls Apr 15, 2026
aa4db5e
Only write W3CTracestate when available
mcculls Apr 15, 2026
d84ef11
Remove incorrect check which only exported spans with links
mcculls Apr 15, 2026
95e3fb7
Test OtlpTraceProto with various span data, including different numbe…
mcculls Apr 15, 2026
8eefedb
Extend test to check 128 trace-ids and span link attributes
mcculls Apr 15, 2026
084753f
Extend test to check link tracestate, traceflags, and span origin
mcculls Apr 15, 2026
1ed7619
Re-use writeSpanTag
mcculls Apr 15, 2026
dafb834
Use logging trace writer during OtlpTraceProtoTest
mcculls Apr 15, 2026
7cdfed7
Disable injection of span-links as tags when using OTLP since we can …
mcculls Apr 17, 2026
d5ce7d2
Cleanup
mcculls Apr 17, 2026
66fe66c
Review feedback: support collecting multiple traces into one payload
mcculls Apr 17, 2026
c1e2106
Add test to check multiple traces can be marshalled into a single pay…
mcculls Apr 17, 2026
a2b30d4
Spelling
mcculls Apr 17, 2026
f5eae6e
Map no span.kind to UNSPECIFIED
mcculls Apr 17, 2026
cddc85b
Review feedback: avoid NPE if value cache is turned off
mcculls Apr 17, 2026
dc3a2c8
Review feedback: avoid cast exception if span.kind set to non-string …
mcculls Apr 17, 2026
e77fe7e
Review feedback: avoid capturing lambda by using TagMap.forEach that …
mcculls Apr 17, 2026
397618f
Simple equality test is enough here
mcculls Apr 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ public final class ConfigDefaults {
public static final boolean DEFAULT_STARTUP_LOGS_ENABLED = true;

static final boolean DEFAULT_INJECT_DATADOG_ATTRIBUTE = true;
static final boolean DEFAULT_WRITER_BAGGAGE_INJECT = true;
static final String DEFAULT_SITE = "datadoghq.com";

static final boolean DEFAULT_CODE_ORIGIN_FOR_SPANS_INTERFACE_SUPPORT = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public final class TracerConfig {
public static final String ID_GENERATION_STRATEGY = "id.generation.strategy";
public static final String WRITER_TYPE = "writer.type";
public static final String WRITER_BAGGAGE_INJECT = "writer.baggage.inject";
public static final String WRITER_LINKS_INJECT = "writer.links.inject";

public static final String PRIORITIZATION_TYPE = "prioritization.type";
public static final String TRACE_AGENT_URL = "trace.agent.url";
Expand Down
16 changes: 15 additions & 1 deletion dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ public static final CoreTracerBuilder builder() {
private final TimeSource timeSource;
private final ProfilingContextIntegration profilingContextIntegration;
private final boolean injectBaggageAsTags;
private final boolean injectLinksAsTags;
private final boolean flushOnClose;
private final Collection<Runnable> shutdownListeners = new CopyOnWriteArrayList<>();

Expand Down Expand Up @@ -326,6 +327,7 @@ public static class CoreTracerBuilder {
private boolean reportInTracerFlare;
private boolean pollForTracingConfiguration;
private boolean injectBaggageAsTags;
private boolean injectLinksAsTags;
private boolean flushOnClose;

public CoreTracerBuilder serviceName(String serviceName) {
Expand Down Expand Up @@ -471,6 +473,11 @@ public CoreTracerBuilder injectBaggageAsTags(boolean injectBaggageAsTags) {
return this;
}

public CoreTracerBuilder injectLinksAsTags(boolean injectLinksAsTags) {
this.injectLinksAsTags = injectLinksAsTags;
return this;
}

public CoreTracerBuilder flushOnClose(boolean flushOnClose) {
this.flushOnClose = flushOnClose;
return this;
Expand Down Expand Up @@ -506,6 +513,7 @@ public CoreTracerBuilder config(final Config config) {
partialFlushMinSpans(config.getPartialFlushMinSpans());
strictTraceWrites(config.isTraceStrictWritesEnabled());
injectBaggageAsTags(config.isInjectBaggageAsTagsEnabled());
injectLinksAsTags(config.isInjectLinksAsTagsEnabled());
flushOnClose(config.isCiVisibilityEnabled());
return this;
}
Expand Down Expand Up @@ -538,6 +546,7 @@ public CoreTracer build() {
reportInTracerFlare,
pollForTracingConfiguration,
injectBaggageAsTags,
injectLinksAsTags,
flushOnClose);
}
}
Expand Down Expand Up @@ -569,6 +578,7 @@ private CoreTracer(
final boolean reportInTracerFlare,
final boolean pollForTracingConfiguration,
final boolean injectBaggageAsTags,
final boolean injectLinksAsTags,
final boolean flushOnClose) {
this(
config,
Expand Down Expand Up @@ -597,6 +607,7 @@ private CoreTracer(
reportInTracerFlare,
pollForTracingConfiguration,
injectBaggageAsTags,
injectLinksAsTags,
flushOnClose);
}

Expand Down Expand Up @@ -628,6 +639,7 @@ private CoreTracer(
final boolean reportInTracerFlare,
final boolean pollForTracingConfiguration,
final boolean injectBaggageAsTags,
final boolean injectLinksAsTags,
final boolean flushOnClose) {

assert localRootSpanTags != null;
Expand Down Expand Up @@ -864,6 +876,7 @@ private CoreTracer(
propagationTagsFactory = PropagationTags.factory(config);
this.profilingContextIntegration = profilingContextIntegration;
this.injectBaggageAsTags = injectBaggageAsTags;
this.injectLinksAsTags = injectLinksAsTags;
this.flushOnClose = flushOnClose;
this.allowInferredServices = SpanNaming.instance().namingSchema().allowInferredServices();
if (profilingContextIntegration != ProfilingContextIntegration.NoOp.INSTANCE) {
Expand Down Expand Up @@ -2119,7 +2132,8 @@ protected static final DDSpanContext buildSpanContext(
tracer.disableSamplingMechanismValidation,
propagationTags,
tracer.profilingContextIntegration,
tracer.injectBaggageAsTags);
tracer.injectBaggageAsTags,
tracer.injectLinksAsTags);

// By setting the tags on the context we apply decorators to any tags that have been set via
// the builder. This is the order that the tags were added previously, but maybe the `tags`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -883,7 +883,7 @@ public TraceConfig traceConfig() {
return context.getTraceCollector().getTraceConfig();
}

List<? extends AgentSpanLink> getLinks() {
public List<? extends AgentSpanLink> getLinks() {
return this.links;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ public class DDSpanContext

private final ProfilingContextIntegration profilingContextIntegration;
private final boolean injectBaggageAsTags;
private final boolean injectLinksAsTags;
private volatile int encodedOperationName;
private volatile int encodedResourceName;

Expand Down Expand Up @@ -238,6 +239,7 @@ public DDSpanContext(
disableSamplingMechanismValidation,
propagationTags,
ProfilingContextIntegration.NoOp.INSTANCE,
true,
true);
}

Expand All @@ -261,7 +263,8 @@ public DDSpanContext(
final PathwayContext pathwayContext,
final boolean disableSamplingMechanismValidation,
final PropagationTags propagationTags,
final boolean injectBaggageAsTags) {
final boolean injectBaggageAsTags,
final boolean injectLinksAsTags) {
this(
traceId,
spanId,
Expand All @@ -286,7 +289,8 @@ public DDSpanContext(
disableSamplingMechanismValidation,
propagationTags,
ProfilingContextIntegration.NoOp.INSTANCE,
injectBaggageAsTags);
injectBaggageAsTags,
injectLinksAsTags);
}

public DDSpanContext(
Expand All @@ -313,7 +317,8 @@ public DDSpanContext(
final boolean disableSamplingMechanismValidation,
final PropagationTags propagationTags,
final ProfilingContextIntegration profilingContextIntegration,
final boolean injectBaggageAsTags) {
final boolean injectBaggageAsTags,
final boolean injectLinksAsTags) {

assert traceCollector != null;
this.traceCollector = traceCollector;
Expand Down Expand Up @@ -370,6 +375,7 @@ public DDSpanContext(
: traceCollector.getTracer().getPropagationTagsFactory().empty();
this.propagationTags.updateTraceIdHighOrderBits(this.traceId.toHighOrderLong());
this.injectBaggageAsTags = injectBaggageAsTags;
this.injectLinksAsTags = injectLinksAsTags;
if (origin != null) {
setOrigin(origin);
}
Expand Down Expand Up @@ -1177,10 +1183,14 @@ void processTagsAndBaggage(
// Tags
TagsPostProcessorFactory.lazyProcessor().processTags(unsafeTags, this, restrictedSpan);

String linksTag = DDSpanLink.toTag(restrictedSpan.getLinks());
if (linksTag != null) {
unsafeTags.put(SPAN_LINKS, linksTag);
// Links
if (injectLinksAsTags) {
String linksTag = DDSpanLink.toTag(restrictedSpan.getLinks());
if (linksTag != null) {
unsafeTags.set(SPAN_LINKS, linksTag);
}
}

// Baggage
Map<String, String> baggageItemsWithPropagationTags;
if (injectBaggageAsTags) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import datadog.communication.serialization.SimpleUtf8Cache;
import datadog.communication.serialization.StreamingBuffer;
import datadog.trace.api.Config;
import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString;
import datadog.trace.bootstrap.otel.common.OtelInstrumentationScope;
import java.nio.ByteBuffer;
import java.util.List;
Expand Down Expand Up @@ -45,6 +46,12 @@ private OtlpCommonProto() {}
? new GenerationalUtf8Cache(Config.get().getTagValueUtf8CacheSize())
: null;

public static void recalibrateCaches() {
if (VALUE_CACHE != null) {
VALUE_CACHE.recalibrate();
}
}

public static int sizeVarInt(int value) {
return 1 + (31 - Integer.numberOfLeadingZeros(value)) / 7;
}
Expand Down Expand Up @@ -153,8 +160,13 @@ public static void writeInstrumentationScope(
}

@SuppressWarnings("unchecked")
public static void writeAttribute(StreamingBuffer buf, int type, String key, Object value) {
byte[] keyUtf8 = keyUtf8(key);
public static void writeAttribute(StreamingBuffer buf, int type, CharSequence key, Object value) {
byte[] keyUtf8;
if (key instanceof UTF8BytesString) {
keyUtf8 = ((UTF8BytesString) key).getUtf8Bytes();
} else {
keyUtf8 = keyUtf8(key.toString());
}
switch (type) {
case STRING:
writeStringAttribute(buf, keyUtf8, valueUtf8((String) value));
Expand All @@ -163,10 +175,10 @@ public static void writeAttribute(StreamingBuffer buf, int type, String key, Obj
writeBooleanAttribute(buf, keyUtf8, (boolean) value);
break;
case LONG:
writeLongAttribute(buf, keyUtf8, (long) value);
writeLongAttribute(buf, keyUtf8, ((Number) value).longValue());
break;
case DOUBLE:
writeDoubleAttribute(buf, keyUtf8, (double) value);
writeDoubleAttribute(buf, keyUtf8, ((Number) value).doubleValue());
break;
case STRING_ARRAY:
writeStringArrayAttribute(buf, keyUtf8, (List<String>) value);
Expand All @@ -175,16 +187,29 @@ public static void writeAttribute(StreamingBuffer buf, int type, String key, Obj
writeBooleanArrayAttribute(buf, keyUtf8, (List<Boolean>) value);
break;
case LONG_ARRAY:
writeLongArrayAttribute(buf, keyUtf8, (List<Long>) value);
writeLongArrayAttribute(buf, keyUtf8, (List<? extends Number>) value);
break;
case DOUBLE_ARRAY:
writeDoubleArrayAttribute(buf, keyUtf8, (List<Double>) value);
writeDoubleArrayAttribute(buf, keyUtf8, (List<? extends Number>) value);
break;
default:
throw new IllegalArgumentException("Unknown attribute type: " + type);
}
}

public static void writeAttribute(
StreamingBuffer buf, UTF8BytesString key, UTF8BytesString value) {
writeStringAttribute(buf, key.getUtf8Bytes(), value.getUtf8Bytes());
}

public static void writeAttribute(StreamingBuffer buf, UTF8BytesString key, String value) {
writeStringAttribute(buf, key.getUtf8Bytes(), valueUtf8(value));
}

public static void writeAttribute(StreamingBuffer buf, UTF8BytesString key, long value) {
writeLongAttribute(buf, key.getUtf8Bytes(), value);
}

private static byte[] keyUtf8(String key) {
return KEY_CACHE != null ? KEY_CACHE.getUtf8(key) : key.getBytes(UTF_8);
}
Expand Down Expand Up @@ -301,10 +326,10 @@ private static void writeBooleanArrayAttribute(
}

private static void writeLongArrayAttribute(
StreamingBuffer buf, byte[] keyUtf8, List<Long> values) {
StreamingBuffer buf, byte[] keyUtf8, List<? extends Number> values) {
long[] longValues = new long[values.size()];
for (int i = 0; i < longValues.length; i++) {
longValues[i] = values.get(i); // avoid repeated unboxing later
longValues[i] = values.get(i).longValue(); // avoid repeated unboxing later
}
int arraySize = 0;
for (long longValue : longValues) {
Expand Down Expand Up @@ -332,7 +357,7 @@ private static void writeLongArrayAttribute(
}

private static void writeDoubleArrayAttribute(
StreamingBuffer buf, byte[] keyUtf8, List<Double> values) {
StreamingBuffer buf, byte[] keyUtf8, List<? extends Number> values) {
int arraySize = 11 * values.size();
int valueSize = 1 + sizeVarInt(arraySize) + arraySize;
int keyValueSize =
Expand All @@ -345,11 +370,11 @@ private static void writeDoubleArrayAttribute(
writeVarInt(buf, valueSize);
writeTag(buf, 5, LEN_WIRE_TYPE);
writeVarInt(buf, arraySize);
for (double value : values) {
for (Number value : values) {
writeTag(buf, 1, LEN_WIRE_TYPE);
buf.put((byte) 9);
writeTag(buf, 4, I64_WIRE_TYPE);
writeI64(buf, value);
writeI64(buf, value.doubleValue());
}
}
}
Loading
Loading