forked from goadesign/clue
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontext.go
More file actions
107 lines (91 loc) · 3.18 KB
/
context.go
File metadata and controls
107 lines (91 loc) · 3.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package trace
import (
"context"
"errors"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
"go.opentelemetry.io/otel/trace"
)
type (
// ctxKey is a private type used to store the tracer provider in the context.
ctxKey int
// stateBag tracks the provider, tracer and active span sequence for a request.
stateBag struct {
svc string
provider trace.TracerProvider
propagator propagation.TextMapPropagator
tracer trace.Tracer
spans []trace.Span
}
)
const (
// InstrumentationLibraryName is the name of the instrumentation library.
InstrumentationLibraryName = "goa.design/clue"
// AttributeRequestID is the name of the span attribute that contains the
// request ID.
AttributeRequestID = "request.id"
)
const (
// stateKey is used to store the tracing state the context.
stateKey ctxKey = iota + 1
)
// Context initializes the context so it can be used to create traces.
func Context(ctx context.Context, svc string, opts ...TraceOption) (context.Context, error) {
options := defaultOptions()
for _, o := range opts {
err := o(ctx, options)
if err != nil {
return nil, err
}
}
if options.disabled {
return withProvider(ctx, trace.NewNoopTracerProvider(), options.propagator, svc), nil
}
if options.exporter == nil {
return nil, errors.New("missing exporter")
}
res := options.resource
if res == nil {
res = resource.NewWithAttributes(semconv.SchemaURL, semconv.ServiceNameKey.String(svc))
}
rootSampler := adaptiveSampler(options.maxSamplingRate, options.sampleSize)
provider := sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.ParentBased(rootSampler, options.parentSamplerOptions...)),
sdktrace.WithResource(res),
sdktrace.WithBatcher(options.exporter),
)
return withProvider(ctx, provider, options.propagator, svc), nil
}
// IsTraced returns true if the current request is traced.
func IsTraced(ctx context.Context) bool {
span := trace.SpanFromContext(ctx)
return span.IsRecording() && span.SpanContext().IsSampled()
}
// TraceProvider returns the underlying otel trace provider.
func TraceProvider(ctx context.Context) trace.TracerProvider {
sb := ctx.Value(stateKey).(*stateBag)
return sb.provider
}
// withProvider stores the tracer provider in the context.
func withProvider(ctx context.Context, provider trace.TracerProvider, propagator propagation.TextMapPropagator, svc string) context.Context {
return context.WithValue(ctx, stateKey, &stateBag{provider: provider, propagator: propagator, svc: svc})
}
// withTracing initializes the tracing context, ctx must have been initialized
// with withProvider and the request must be traced by otel.
func withTracing(traceCtx, ctx context.Context) context.Context {
state := traceCtx.Value(stateKey).(*stateBag)
svc := state.svc
provider := state.provider
propagator := state.propagator
tracer := provider.Tracer(InstrumentationLibraryName)
spans := []trace.Span{trace.SpanFromContext(ctx)}
return context.WithValue(ctx, stateKey, &stateBag{
svc: svc,
provider: provider,
propagator: propagator,
tracer: tracer,
spans: spans,
})
}