blob: 08c00c04e82ae304b41704c7d0074cb879034792 [file] [log] [blame]
Matteo Scandoloa4285862020-12-01 18:10:10 -08001package opentracing
2
3import "context"
4
5type contextKey struct{}
6
7var activeSpanKey = contextKey{}
8
9// ContextWithSpan returns a new `context.Context` that holds a reference to
10// `span`'s SpanContext.
11func ContextWithSpan(ctx context.Context, span Span) context.Context {
12 return context.WithValue(ctx, activeSpanKey, span)
13}
14
15// SpanFromContext returns the `Span` previously associated with `ctx`, or
16// `nil` if no such `Span` could be found.
17//
18// NOTE: context.Context != SpanContext: the former is Go's intra-process
19// context propagation mechanism, and the latter houses OpenTracing's per-Span
20// identity and baggage information.
21func SpanFromContext(ctx context.Context) Span {
22 val := ctx.Value(activeSpanKey)
23 if sp, ok := val.(Span); ok {
24 return sp
25 }
26 return nil
27}
28
29// StartSpanFromContext starts and returns a Span with `operationName`, using
30// any Span found within `ctx` as a ChildOfRef. If no such parent could be
31// found, StartSpanFromContext creates a root (parentless) Span.
32//
33// The second return value is a context.Context object built around the
34// returned Span.
35//
36// Example usage:
37//
38// SomeFunction(ctx context.Context, ...) {
39// sp, ctx := opentracing.StartSpanFromContext(ctx, "SomeFunction")
40// defer sp.Finish()
41// ...
42// }
43func StartSpanFromContext(ctx context.Context, operationName string, opts ...StartSpanOption) (Span, context.Context) {
44 return StartSpanFromContextWithTracer(ctx, GlobalTracer(), operationName, opts...)
45}
46
47// StartSpanFromContextWithTracer starts and returns a span with `operationName`
48// using a span found within the context as a ChildOfRef. If that doesn't exist
49// it creates a root span. It also returns a context.Context object built
50// around the returned span.
51//
52// It's behavior is identical to StartSpanFromContext except that it takes an explicit
53// tracer as opposed to using the global tracer.
54func StartSpanFromContextWithTracer(ctx context.Context, tracer Tracer, operationName string, opts ...StartSpanOption) (Span, context.Context) {
55 if parentSpan := SpanFromContext(ctx); parentSpan != nil {
56 opts = append(opts, ChildOf(parentSpan.Context()))
57 }
58 span := tracer.StartSpan(operationName, opts...)
59 return span, ContextWithSpan(ctx, span)
60}