Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions ddtrace/opentelemetry/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ func (t *oteltracer) Start(ctx context.Context, spanName string, opts ...oteltra
// if the span doesn't originate from the Datadog tracer,
// use SpanContextW3C implementation struct to pass span context information
ddopts = append(ddopts, tracer.ChildOf(tracer.FromGenericCtx(&otelCtxToDDCtx{sctx})))
if sctx.IsSampled() {
ddopts = append(ddopts, tracer.Tag(ext.ManualKeep, true))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't look right.

If the parent span is sampled, the new span shouldn't need to get force-sampled to get sampled. This will incorrectly set the ingestion_reason span metadata to manual instead of rule (relevant doc).

Also, this doesn't cover the case when the parent span is not sampled. In that case, the child span shouldn't be sampled either. However, with this code, the child span will independently decide its sampling decision, so it might be sampled.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. Closing this in favour of #3718 (in progress).

}
}
}
if t := ssConfig.Timestamp(); !t.IsZero() {
Expand Down
25 changes: 25 additions & 0 deletions ddtrace/opentelemetry/tracer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,31 @@ func TestSpanContext(t *testing.T) {
assert.Equal(true, sctx.IsRemote())
}

func TestSamplingDecision(t *testing.T) {
assert := assert.New(t)
tp := NewTracerProvider(
tracer.WithSamplingRules([]tracer.SamplingRule{
{Rate: 0}, // This should be applied only when a brand new root span is started and should be ignored for a non-root span
}),
)
defer tp.Shutdown()
otel.SetTracerProvider(tp)
tr := otel.Tracer("")

parentSpanContext := oteltrace.NewSpanContext(oteltrace.SpanContextConfig{
TraceID: oteltrace.TraceID{0xAB},
SpanID: oteltrace.SpanID{0x01},
TraceFlags: oteltrace.FlagsSampled, // the parent span is sampled, so its child spans should be sampled too
})
ctx := oteltrace.ContextWithSpanContext(context.Background(), parentSpanContext)
_, span := tr.Start(ctx, "test")
span.End()

childSpanContext := span.SpanContext()
assert.Equal(parentSpanContext.TraceID(), childSpanContext.TraceID())
assert.True(childSpanContext.IsSampled(), "parent span is sampled, but child span is not sampled")
}

func TestForceFlush(t *testing.T) {
const (
UNSET = iota
Expand Down
Loading