Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
8f7f60f
Allow Config to resolve traceURL; pass this as a field into httptrans…
mtoffl01 Mar 23, 2026
3e3fec8
Fix otlp protocol resolution and add tests for all new logic
mtoffl01 Mar 23, 2026
c559f8f
Implement OTEL_EXPORTER_OTLP_TRACES_HEADERS
mtoffl01 Mar 23, 2026
cb6908e
Fix superfluous referecne to unsupport OTLP header config
mtoffl01 Mar 23, 2026
a85fedf
Introduce otlpExportMode on Config; use this instead of traceProtocol…
mtoffl01 Mar 23, 2026
33a9a37
fix relationship between otlpexportmode and protocol
mtoffl01 Mar 23, 2026
3e51fdd
replace tracer.config.otlpExportMode with internalconfig otlpExportMode
mtoffl01 Mar 23, 2026
5e252be
Clean up resolveOTLPHeaders
mtoffl01 Mar 23, 2026
51f72a2
cleanup
mtoffl01 Mar 23, 2026
b71eec7
more cleanup and remove OTEL_EXPORTER_OTLP_ENDPOINT
mtoffl01 Mar 23, 2026
f48d44f
Store otlpTraceURL instead of traceURL on Config; let tracer resolve …
mtoffl01 Mar 23, 2026
f4360b4
Make DD_TRACE_AGENT_PROTOCOL_VERSION override OTEL_TRACES_EXPORTER
mtoffl01 Mar 23, 2026
49d0937
Merge branch 'main' into mtoff/otlp-export-config
kakkoyun Mar 24, 2026
a88b7b2
Use GetMap to resolve OTEL_EXPORTER_OTLP_TRACES_HEADERS and change co…
mtoffl01 Mar 24, 2026
d475920
give OTEL_EXPORTER_OTLP_TRACES_ENDPOINT default value of null
mtoffl01 Mar 24, 2026
8188bbe
Merge branch 'main' into mtoff/otlp-export-config
kakkoyun Mar 25, 2026
af909c3
flesh out traceWriterOtlp
mtoffl01 Mar 24, 2026
9246084
add new otlpSender for transporting otlp traces specifically; build o…
mtoffl01 Mar 24, 2026
a934fdd
rename file payload_otlp_convert.go -> span_to_otlp.go; and introduce…
mtoffl01 Mar 24, 2026
2cfa217
introduce otlp_writer_test.go: basic otlp writer tests
mtoffl01 Mar 24, 2026
7bba29d
Fix: only export sampled spans, and correct telemetry.sdk.version value
mtoffl01 Mar 24, 2026
89cb7e6
Test buildResource
mtoffl01 Mar 24, 2026
da1efd4
implement edge case: add 'service.name' attribute to span when span's…
mtoffl01 Mar 24, 2026
49053c1
add comment about s.metaStruct
mtoffl01 Mar 25, 2026
378639f
fix(ddtrace/tracer): pre-compute `_dd.p.dm` numeric value at write-ti…
darccio Mar 25, 2026
97a2bf9
fix(ddtrace/tracer): check `DD_TRACE_128_BIT_TRACEID_GENERATION_ENABL…
darccio Mar 25, 2026
ffbea4e
chore: disable automated dependency updater config [incident-51602]
moezein0 Mar 25, 2026
9882338
merge conflicts
mtoffl01 Mar 25, 2026
5072b2a
merge conflicts
mtoffl01 Mar 25, 2026
78e160f
Apply suggestion from @genesor
mtoffl01 Mar 25, 2026
f0c6f00
address PR review comments
mtoffl01 Mar 25, 2026
5ca4d0e
Merge branch 'mtoff/otlp-export-config' into mtoff/otlp-export-traces
mtoffl01 Mar 25, 2026
6deec12
Merge branch 'main' into mtoff/otlp-export-traces
mtoffl01 Mar 25, 2026
996c4d7
rename transport to ddtransport: be clear
mtoffl01 Mar 25, 2026
697c2ba
remove otlpSender; make otlpTraceWriter handle its own http client
mtoffl01 Mar 25, 2026
d7749bb
introduce new otlpTransport, plus tests
mtoffl01 Mar 25, 2026
dcd8a10
cleanup setting transport on tracer.config in non-otlp conditions
mtoffl01 Mar 25, 2026
6dbab08
fix imports
mtoffl01 Mar 25, 2026
d0765c8
fix lint errors
mtoffl01 Mar 25, 2026
acc9688
Add comment reminder about benchmarking protobuf
mtoffl01 Mar 25, 2026
490d6f1
implement flush condition if hit payloadMaxSize
mtoffl01 Mar 25, 2026
c07bf3c
Write benchmarks for otlp trace writer
mtoffl01 Mar 25, 2026
90dccdd
fix nits from CI
mtoffl01 Mar 26, 2026
99ef3c8
Add last span atttributes and attribute limit, as well as tracestate …
mtoffl01 Mar 26, 2026
47a01a2
disable stats concentrator in otlp mode
mtoffl01 Mar 26, 2026
ddfc0e2
fix checklocks on buffer
mtoffl01 Mar 26, 2026
c371138
fix gofmt otlp_writer.go
mtoffl01 Mar 26, 2026
ac556e6
Merge branch 'main' into mtoff/otlp-export-traces
mtoffl01 Mar 27, 2026
0e4f52b
Merge branch 'mtoff/otlp-export-traces' into mtoff/stats-disabled-otlp
mtoffl01 Mar 27, 2026
cd63872
Fix converSpanAttribute
mtoffl01 Mar 27, 2026
12d75b3
Apply suggestions from code review
mtoffl01 Mar 27, 2026
af69c6b
Make sure newBenchOTLPWriter has scope
mtoffl01 Mar 27, 2026
35cf849
Address agent UDS url issue: have otlp writer create its own client
mtoffl01 Mar 30, 2026
6480f53
PR comments: promote service.name and operation.name attributes; omit…
mtoffl01 Apr 3, 2026
20c74c4
Merge branch 'mtoff/otlp-export-traces' into mtoff/stats-disabled-otlp
mtoffl01 Apr 6, 2026
e8aab3a
Add new benchmarks to BENCHMARK_TARGETS
mtoffl01 Apr 7, 2026
4223bd3
Merge branch 'main' into mtoff/otlp-export-traces
mtoffl01 Apr 7, 2026
037eec3
Fix: Capture response body in otlpTransport.send, in order to reuse t…
mtoffl01 Apr 7, 2026
ca17d6a
fix lint problem in otlp_transport_test
mtoffl01 Apr 7, 2026
63bc9ea
Fix race condition in TestOTLPTransportConnectionReuse
mtoffl01 Apr 7, 2026
f9ae432
Merge branch 'main' into mtoff/otlp-export-traces
kakkoyun Apr 8, 2026
91fac2a
drain otlpTransport response body after reading status code
mtoffl01 Apr 9, 2026
7c12988
Cache base TracesData size
mtoffl01 Apr 9, 2026
f577ca2
Use Span_SPAN_KIND_UNSPECIFIED for unknown span types
mtoffl01 Apr 9, 2026
ceea3dd
wrap error in otlpTransport.send
mtoffl01 Apr 9, 2026
b3a521d
enforce Content-Type header at the otlpTransport.send level
mtoffl01 Apr 9, 2026
9b8e37f
Merge branch 'mtoff/otlp-export-traces' into mtoff/stats-disabled-otlp
mtoffl01 Apr 10, 2026
8d6156e
Merge branch 'main' into mtoff/otlp-export-traces
kakkoyun Apr 14, 2026
6ec6405
Address codex feedback on span_to_otlp
mtoffl01 Apr 14, 2026
df091b3
Fix nil check on otlpArrayValue converter
mtoffl01 Apr 14, 2026
92de62c
Document maxAttributesCount
mtoffl01 Apr 14, 2026
016cb71
Restore default traceWriter test
mtoffl01 Apr 14, 2026
b19d2aa
Merge branch 'mtoff/otlp-export-traces' into mtoff/stats-disabled-otlp
mtoffl01 Apr 14, 2026
3bb0a70
Use noopConcentrator instead of nil checks
mtoffl01 Apr 14, 2026
87989c6
modernize for loop to range
mtoffl01 Apr 14, 2026
75e2a69
merge conflicts
mtoffl01 Apr 15, 2026
71deeda
Change stats logic to do newConcentrator by default with a conditiona…
mtoffl01 Apr 15, 2026
af089cc
Merge branch 'main' into mtoff/stats-disabled-otlp
kakkoyun 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
32 changes: 32 additions & 0 deletions ddtrace/tracer/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ var tracerObfuscationVersion = 1
// covered in one stats bucket.
var defaultStatsBucketSize = (10 * time.Second).Nanoseconds()

// statsConcentrator abstracts the stats-computation lifecycle so that callers
// don't need nil checks when stats are disabled (e.g. OTLP export mode).
type statsConcentrator interface {
Start()
Stop()
flushAndSend(now time.Time, includeCurrent bool)
newTracerStatSpan(s *Span, obfuscator *obfuscate.Obfuscator) (*tracerStatSpan, bool)
trySendSpan(s *tracerStatSpan)
}

// concentrator aggregates and stores statistics on incoming spans in time buckets,
// flushing them occasionally to the underlying transport located in the given
// tracer config.
Expand Down Expand Up @@ -269,3 +279,25 @@ func (c *concentrator) flushAndSend(timenow time.Time, includeCurrent bool) {
}
c.statsd().Incr("datadog.tracer.stats.flush_buckets", nil, float64(flushedBuckets))
}

// trySendSpan attempts a non-blocking send of the stat span to the
// concentrator's input channel.
func (c *concentrator) trySendSpan(s *tracerStatSpan) {
select {
case c.In <- s:
default:
log.Error("Stats channel full, disregarding span.")
}
}

// noopConcentrator is a no-op implementation of statsConcentrator used when
// client-side stats are disabled (e.g. OTLP export mode).
type noopConcentrator struct{}

func (c *noopConcentrator) Start() {}
func (c *noopConcentrator) Stop() {}
func (c *noopConcentrator) flushAndSend(_ time.Time, _ bool) {}
func (c *noopConcentrator) newTracerStatSpan(_ *Span, _ *obfuscate.Obfuscator) (*tracerStatSpan, bool) {
return nil, false
}
func (c *noopConcentrator) trySendSpan(_ *tracerStatSpan) {}
34 changes: 34 additions & 0 deletions ddtrace/tracer/stats_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -476,3 +476,37 @@ func TestStatsFlushRetries(t *testing.T) {
})
}
}

func TestNoopConcentrator(t *testing.T) {
var c statsConcentrator = &noopConcentrator{}

t.Run("Start", func(t *testing.T) {
assert.NotPanics(t, func() { c.Start() })
})

t.Run("Stop", func(t *testing.T) {
assert.NotPanics(t, func() { c.Stop() })
})

t.Run("flushAndSend", func(t *testing.T) {
assert.NotPanics(t, func() { c.flushAndSend(time.Now(), false) })
})

t.Run("newTracerStatSpan", func(t *testing.T) {
s := &Span{
name: "test.op",
service: "test-service",
resource: "/test",
spanType: "web",
start: time.Now().UnixNano(),
duration: 1,
}
ss, ok := c.newTracerStatSpan(s, obfuscate.NewObfuscator(obfuscate.Config{}))
assert.Nil(t, ss)
assert.False(t, ok)
})

t.Run("trySendSpan", func(t *testing.T) {
assert.NotPanics(t, func() { c.trySendSpan(&tracerStatSpan{}) })
})
}
18 changes: 8 additions & 10 deletions ddtrace/tracer/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ type tracer struct {
config *config

// stats specifies the concentrator used to compute statistics, when client-side
// stats are enabled.
stats *concentrator
// stats are enabled. In OTLP export mode this is a noopConcentrator.
stats statsConcentrator

// traceWriter is responsible for sending finished traces to their
// destination, such as the Trace Agent or Datadog Forwarder.
Expand Down Expand Up @@ -497,6 +497,10 @@ func newUnstartedTracer(opts ...StartOption) (t *tracer, err error) {
c.internalConfig.SetLogDirectory("", telemetry.OriginCalculated)
}
}
var sc statsConcentrator = newConcentrator(c, defaultStatsBucketSize, statsd)
if c.internalConfig.OTLPExportMode() {
sc = &noopConcentrator{}
}
t = &tracer{
config: c,
traceWriter: writer,
Expand All @@ -507,7 +511,7 @@ func newUnstartedTracer(opts ...StartOption) (t *tracer, err error) {
defaultSampler: dfltSampler,
pid: os.Getpid(),
logDroppedTraces: time.NewTicker(1 * time.Second),
stats: newConcentrator(c, defaultStatsBucketSize, statsd),
stats: sc,
spansStarted: *globalinternal.NewXSyncMapCounterMap(),
spansFinished: *globalinternal.NewXSyncMapCounterMap(),
obfuscator: obfuscate.NewObfuscator(func() obfuscate.Config {
Expand Down Expand Up @@ -1163,13 +1167,7 @@ func (t *tracer) submit(s *Span) {
if !shouldCalc {
return
}
// the agent supports computed stats
select {
case t.stats.In <- statSpan:
// ok
default:
log.Error("Stats channel full, disregarding span.")
}
t.stats.trySendSpan(statSpan)
}

func (t *tracer) submitAbandonedSpan(s *Span, finished bool) {
Expand Down
58 changes: 58 additions & 0 deletions ddtrace/tracer/tracer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ import (
"testing/synctest"
"time"

otlptrace "go.opentelemetry.io/proto/otlp/trace/v1"
"go.uber.org/goleak"
"google.golang.org/protobuf/proto"

"github.com/DataDog/dd-trace-go/v2/ddtrace"
"github.com/DataDog/dd-trace-go/v2/ddtrace/ext"
Expand Down Expand Up @@ -1495,6 +1497,7 @@ func TestOTLPExportMode(t *testing.T) {
assert.True(isOTLPWriter, "expected otlpTraceWriter in OTLP export mode")
_, isAlwaysOn := tracer.defaultSampler.(*otelParentBasedAlwaysOnSampler)
assert.True(isAlwaysOn, "expected otelParentBasedAlwaysOnSampler in OTLP export mode")
assert.IsType(&noopConcentrator{}, tracer.stats, "expected noopConcentrator in OTLP export mode")
})

t.Run("OTEL_TRACES_EXPORTER=otlp env var enables OTLP mode", func(t *testing.T) {
Expand All @@ -1510,6 +1513,61 @@ func TestOTLPExportMode(t *testing.T) {
})
}

func TestOTLPExportModeStatsSkipped(t *testing.T) {
srv := newTestOTLPServer()
defer srv.Close()

tick := make(chan time.Time)
trc, err := newTracer(
func(c *config) {
c.internalConfig.SetOTLPExportMode(true, internalconfig.OriginCode)
c.ddTransport = newDummyTransport()
c.tickChan = tick
},
)
require.NoError(t, err)

w := trc.traceWriter.(*otlpTraceWriter)
w.transport = newOTLPTransport(srv.Client(), srv.URL, map[string]string{"Content-Type": "application/x-protobuf"})

// Enable canDropP0s so submit() reaches the noopConcentrator
// rather than short-circuiting.
af := trc.config.agent.load()
af.Stats = true
af.DropP0s = true
trc.config.agent.store(af)
trc.config.internalConfig.SetFeatureFlags([]string{"discovery"}, internalconfig.OriginCode)

setGlobalTracer(trc)

assert.IsType(t, &noopConcentrator{}, trc.stats, "concentrator must be noop in OTLP mode")
assert.True(t, trc.config.canDropP0s(), "canDropP0s must be true for this test to exercise submit()")

const spanCount = 5
for range spanCount {
span := trc.newRootSpan("test.op", "test-service", "/test")
span.Finish()
}

// Stop drains t.out, flushes the writer, and waits for in-flight sends.
trc.Stop()

payloads := srv.getPayloads()
require.NotEmpty(t, payloads, "expected at least one OTLP payload")

totalSpans := 0
for _, p := range payloads {
var td otlptrace.TracesData
require.NoError(t, proto.Unmarshal(p, &td))
for _, rs := range td.ResourceSpans {
for _, ss := range rs.ScopeSpans {
totalSpans += len(ss.Spans)
}
}
}
assert.Equal(t, spanCount, totalSpans, "all spans should be retained in OTLP mode, not dropped by nil concentrator")
}

func TestTracerConcurrent(t *testing.T) {
assert := assert.New(t)
tracer, transport, flush, stop, err := startTestTracer(t)
Expand Down
Loading