-
Notifications
You must be signed in to change notification settings - Fork 219
/
Copy pathpropagator.go
131 lines (108 loc) · 4.5 KB
/
propagator.go
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//go:build go1.18
package sentryotel
import (
"context"
"fmt"
"github.com/getsentry/sentry-go"
"go.opentelemetry.io/otel/baggage"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/trace"
)
type sentryPropagator struct{}
// Inject set tracecontext from the Context into the carrier.
func (p sentryPropagator) Inject(ctx context.Context, carrier propagation.TextMapCarrier) {
fmt.Printf("\n--- Propagator Inject\nContext: %#v\nCarrier: %#v\n", ctx, carrier)
spanContext := trace.SpanContextFromContext(ctx)
var sentrySpan *sentry.Span
if spanContext.IsValid() {
sentrySpan, _ = sentrySpanMap.Get(spanContext.SpanID())
} else {
sentrySpan = nil
}
// Propagate sentry-trace header
if sentrySpan == nil {
// No span => propagate the incoming sentry-trace header, if exists
sentryTraceHeader, _ := ctx.Value(sentryTraceHeaderContextKey{}).(string)
if sentryTraceHeader != "" {
carrier.Set(sentry.SentryTraceHeader, sentryTraceHeader)
}
} else {
// Sentry span exists => generate "sentry-trace" from it
carrier.Set(sentry.SentryTraceHeader, sentrySpan.ToSentryTrace())
}
// Propagate baggage header
sentryBaggageStr := ""
if sentrySpan != nil && sentrySpan.IsTransaction() {
// TODO(anton): Normally, this should return the DSC baggage from the transaction
// (not necessarily the current span). So this might break things in some cases.
sentryBaggageStr = sentrySpan.ToBaggage()
}
fmt.Printf("sentrySpan: %#v, baggage: %#v\n", sentrySpan, sentryBaggageStr)
// FIXME: We're basically reparsing the header again, because internally in sentry-go
// we currently use a vendored version of "otel/baggage" package.
// This is not optimal and we should consider other approaches.
sentryBaggage, _ := baggage.Parse(sentryBaggageStr)
// Merge the baggage values
finalBaggage := baggage.FromContext(ctx)
for _, member := range sentryBaggage.Members() {
var err error
finalBaggage, err = finalBaggage.SetMember(member)
if err != nil {
continue
}
}
if finalBaggage.Len() > 0 {
carrier.Set(sentry.SentryBaggageHeader, finalBaggage.String())
}
fmt.Printf("sentry-trace header: '%s'\n", carrier.Get(sentry.SentryTraceHeader))
fmt.Printf("baggage header: '%s'\n", carrier.Get(sentry.SentryBaggageHeader))
}
// Extract reads cross-cutting concerns from the carrier into a Context.
func (p sentryPropagator) Extract(ctx context.Context, carrier propagation.TextMapCarrier) context.Context {
fmt.Printf("\n--- Propagator Extract\nContext: %#v\nCarrier: %#v\n", ctx, carrier)
sentryTraceHeader := carrier.Get(sentry.SentryTraceHeader)
fmt.Printf("sentry-trace header: '%s'\n", sentryTraceHeader)
if sentryTraceHeader != "" {
ctx = context.WithValue(ctx, sentryTraceHeaderContextKey{}, sentryTraceHeader)
if traceParentContext, valid := sentry.ParseTraceParentContext([]byte(sentryTraceHeader)); valid {
// Save traceParentContext because we'll at least need to know the original "sampled"
// value in the span processor.
ctx = context.WithValue(ctx, sentryTraceParentContextKey{}, traceParentContext)
spanContextConfig := trace.SpanContextConfig{
TraceID: trace.TraceID(traceParentContext.TraceID),
SpanID: trace.SpanID(traceParentContext.ParentSpanID),
TraceFlags: trace.FlagsSampled,
Remote: true,
}
ctx = trace.ContextWithSpanContext(ctx, trace.NewSpanContext(spanContextConfig))
}
}
baggageHeader := carrier.Get(sentry.SentryBaggageHeader)
fmt.Printf("baggage header: '%s'\n", baggageHeader)
if baggageHeader != "" {
// Preserve the original baggage
parsedBaggage, err := baggage.Parse(baggageHeader)
if err == nil {
ctx = baggage.ContextWithBaggage(ctx, parsedBaggage)
}
}
// The following cases should be already covered below:
// * We can extract a valid dynamic sampling context (DSC) from the baggage
// * No baggage header is present
// * No Sentry-related values are present
// * We cannot parse the baggage header for whatever reason
dynamicSamplingContext, err := sentry.DynamicSamplingContextFromHeader([]byte(baggageHeader))
if err != nil {
// If there are any errors, create a new non-frozen one.
dynamicSamplingContext = sentry.DynamicSamplingContext{Frozen: false}
}
ctx = context.WithValue(ctx, dynamicSamplingContextKey{}, dynamicSamplingContext)
fmt.Printf("DSC: %#v\n", dynamicSamplingContext)
return ctx
}
func (p sentryPropagator) Fields() []string {
return []string{sentry.SentryTraceHeader, sentry.SentryBaggageHeader}
}
func NewSentryPropagator() propagation.TextMapPropagator {
return sentryPropagator{}
}