DataDog / dd-trace-go

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

proposal: Allow setting explicit trace ID when starting a span. #965

Closed tsvtitan closed 2 years ago

tsvtitan commented 3 years ago

We want propagate trace ID from our business applications via HTTP headers or in a custom TCP protocol, thus we need to have an option to set custom Trace ID for a root span.

So, we covered the possibility here => https://github.com/DataDog/dd-trace-go/pull/964

gbbr commented 3 years ago

This is already done automatically by the tracer. Please read the package documentation (section on injecting a span context).

To make use of distributed tracing, a span's context may be injected via a carrier into a transport (HTTP, RPC, etc.) to be extracted on the other end and used to create spans that are direct descendants of it. [...]

Source: https://pkg.go.dev/gopkg.in/DataDog/dd-trace-go.v1@v1.31.0/ddtrace/tracer

You can also create other carriers yourself, besides HTTP headers by implementing TextMapReader and TextMapWriter.

knusbaum commented 3 years ago

@tsvtitan If you can describe your use case, we might be able to figure something out to support it.

As it is, this proposal does not fit with our supported use cases and is likely to cause problems.

tsvtitan commented 3 years ago

@tsvtitan If you can describe your use case, we might be able to figure something out to support it.

As it is, this proposal does not fit with our supported use cases and is likely to cause problems.

It would be great to have an example of TextMapReader usage between 2 apps that work over custom TCP protocol to propagate TraceID. Bare in mind that the first app generates TraceID (has no DataDog integration), the second one consumes it and push traces to DataDog.

By the way, there is the custom TraceID support in Jaeger or OpenTelemetry, as well as custom SpanID, which is also supported by DataDog, but not TraceID

knusbaum commented 3 years ago

Hi, @tsvtitan The TextMapCarrier can be used to carry trace information over any transport you like. It is just a map[string]string that can be serialized using whatever format you like and transported over whatever protocol you use.

On the other end, it can be deserialized and used to create child spans.

Alternatively, TextMapReader and TextMapWriter can be implemented by you if you would like to use some custom type to carry the trace information. The interfaces are simple and documented here

Here's an example using the TextMapCarrier:

    // Create the parent span
    s := tracer.StartSpan("parent.span")
    defer s.Finish()

    // Inject the span's state into the carrier
    carrier := tracer.TextMapCarrier(make(map[string]string))
    tracer.Inject(s.Context(), carrier)

    // Serialize the carrier as you choose and send it over your transport
    var bs []byte = serializeCarrier(carrier)
    // ... send bs through the transport

    // ... on the other end, deserialize the carrier from the bytes.
    // Extract the span context from the carrier.
    carrier = deserializeCarrier(bs)
    sctx, err := tracer.Extract(carrier)
    if err != nil {
        // ...
    }

    // Start a child span from the parent's transported context.
    span := tracer.StartSpan("child.span", tracer.ChildOf(sctx))

It is highly discouraged, but it is possible to create a TextMapCarrier manually using the keys specified here and subsequently extract a span context from it. Datadog expects spans to be linked in a specific way which Inject and Extract ensure, so using the TextMapReader and TextMapWriter interfaces along with Inject and Extract is your best bet for doing custom distributed tracing.

knusbaum commented 2 years ago

I am going to close this issue now as stale.

Please reopen this if we can help or discuss further.

CodapeWild commented 2 years ago

// WithSpanID sets the SpanID on the started span, instead of using a random number. // If there is no parent Span (eg from ChildOf), then the TraceID will also be set to the // value given here. func WithSpanID(id uint64) StartSpanOption

I think this is the solution for certain trace id while starting new span.