Skip to content
Draft
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
20 changes: 20 additions & 0 deletions ddtrace/tracer/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ func ContextWithSpan(ctx context.Context, s *Span) context.Context {
return orchestrion.CtxWithValue(ctx, internal.ActiveSpanKey, s)
}

// contextWithSpanContext returns a copy of the given context which includes the span context sctx.
func contextWithSpanContext(ctx context.Context, sctx *SpanContext) context.Context {
return orchestrion.CtxWithValue(ctx, internal.ActiveSpanContextKey, sctx)
}

// SpanFromContext returns the span contained in the given context. A second return
// value indicates if a span was found in the context. If no span is found, a no-op
// span is returned.
Expand All @@ -35,6 +40,19 @@ func SpanFromContext(ctx context.Context) (*Span, bool) {
return nil, false
}

// spanContextFromContext returns the span context contained in the given context. A second return
// value indicates if a span context was found in the context. If no span context is found, a nil is returned.
func spanContextFromContext(ctx context.Context) (*SpanContext, bool) {
if ctx == nil {
return nil, false
}
v := orchestrion.WrapContext(ctx).Value(internal.ActiveSpanContextKey)
if sctx, ok := v.(*SpanContext); ok {
return sctx, true
}
return nil, false
}

// StartSpanFromContext returns a new span with the given operation name and options. If a span
// is found in the context, it will be used as the parent of the resulting span. If the ChildOf
// option is passed, it will only be used as the parent if there is no span found in `ctx`.
Expand All @@ -47,6 +65,8 @@ func StartSpanFromContext(ctx context.Context, operationName string, opts ...Sta
ctx = context.Background()
} else if s, ok := SpanFromContext(ctx); ok {
optsLocal = append(optsLocal, ChildOf(s.Context()))
} else if sctx, ok := spanContextFromContext(ctx); ok {
optsLocal = append(optsLocal, ChildOf(sctx))
}
optsLocal = append(optsLocal, withContext(ctx))
s := StartSpan(operationName, optsLocal...)
Expand Down
13 changes: 13 additions & 0 deletions ddtrace/tracer/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,19 @@ func Extract(carrier interface{}) (*SpanContext, error) {
return getGlobalTracer().Extract(carrier)
}

// ExtractCtx extracts a span context from the carrier and returns a copy of
// the given context which includes the span context.
func ExtractCtx(ctx gocontext.Context, carrier interface{}) (gocontext.Context, error) {
sctx, err := Extract(carrier)
if err != nil {
return nil, err
}
if sctx == nil {
return ctx, nil
}
return contextWithSpanContext(ctx, sctx), nil
Copy link
Contributor

@mtoffl01 mtoffl01 Aug 12, 2025

Choose a reason for hiding this comment

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

If Extract returns a nil sctx, then we set nil on the context at the key. Is that ok?

Copy link
Member Author

@darccio darccio Aug 13, 2025

Choose a reason for hiding this comment

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

Uhm, you are totally right, and I think it's not ok. We should avoid setting any nil value.

Copy link
Member Author

Choose a reason for hiding this comment

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

Improved. Thanks!

}

// Inject injects the given SpanContext into the carrier. The carrier is
// expected to implement TextMapWriter, otherwise an error is returned.
// If the tracer is not started, calling this function is a no-op.
Expand Down
3 changes: 3 additions & 0 deletions internal/active_span_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ type contextKey struct{}

// ActiveSpanKey is used to set tracer context on a context.Context objects with a unique key
var ActiveSpanKey = contextKey{}

// ActiveSpanContextKey is used to set span context on a context.Context objects with a unique key
var ActiveSpanContextKey = contextKey{}
Loading