DataDog / dd-trace-go

Datadog Go Library including APM tracing, profiling, and security monitoring.
https://docs.datadoghq.com/tracing/
Other
660 stars 435 forks source link

mocktracer: unable to add parent span #1373

Open ryan-yalo opened 2 years ago

ryan-yalo commented 2 years ago

I'd like to set the option to add a parent span and then in my test suite assert that it was set correctly. Unfortunately due to this bit of code in the mocktracer package it appears to be impossible to do so.

https://github.com/DataDog/dd-trace-go/blob/main/ddtrace/mocktracer/mockspan.go#L74

I cannot create an instance of this private struct so that the cast will succeed, I can only set the parent to something that implements the SpanContext interface. Is there another recommended approach for testing using this package that parent spans are set correctly? Right now it seems that even when a valid ChildOf setting is passed in with the config, that information just gets lost.

ajgajg1134 commented 2 years ago

👋 Hi @ryan-yalo, this does seem to be a bug/limitation. Can you provide some example code of what you're looking to do that doesn't work?

rclark commented 5 months ago

Hi, also encountering this problem. This happens when I need my own implementation of the ddtrace.SpanContext interface. In my situation that comes up in a distributed context where I need to perform serialization and deserialization of the parent span before starting the child span.

Can you provide some example code of what you're looking to do that doesn't work?

// spanContext implements ddtrace.SpanContext.
type spanContext struct {
    traceID uint64
    spanID  uint64
}

func (s spanContext) SpanID() uint64 {
    return s.spanID
}
func (s spanContext) TraceID() uint64 {
    return s.traceID
}

func (s spanContext) ForeachBaggageItem(handler func(k, v string) bool) {}

func TestMockTracerParent(t *testing.T) {
    t.Run("success, since we use your ddtrace.SpanContext", func(t *testing.T) {
        mt := mocktracer.Start()
        defer mt.Stop()

        parent, _ := tracer.StartSpanFromContext(context.Background(), "parent")
        child, _ := tracer.StartSpanFromContext(context.Background(), "child", tracer.ChildOf(parent.Context()))

        child.Finish()
        parent.Finish()

        spans := mt.FinishedSpans()
        if spans[0].ParentID() != spans[1].SpanID() {
            t.Fatalf("parent span ID should match child's parent ID")
        }
    })

    t.Run("fail, since I brought my own SpanContext implementation", func(t *testing.T) {
        mt := mocktracer.Start()
        defer mt.Stop()

        parent, _ := tracer.StartSpanFromContext(context.Background(), "parent")
        customImpl := spanContext{
            traceID: parent.Context().TraceID(),
            spanID:  parent.Context().SpanID(),
        }
        child, _ := tracer.StartSpanFromContext(context.Background(), "child", tracer.ChildOf(customImpl))

        child.Finish()
        parent.Finish()

        spans := mt.FinishedSpans()
        if spans[0].ParentID() != spans[1].SpanID() {
            t.Fatalf("parent span ID should match child's parent ID")
        }
    })
}
rclark commented 5 months ago

The same bug exists in the real tracer package.

https://github.com/DataDog/dd-trace-go/blob/dfa02a30ff701163a0d40511c57fdf59fdc044f4/ddtrace/tracer/tracer.go#L472

Do you provide some alternative mechanism through which I could set the parent of a span, when all I have available is the parent's trace ID and span ID?