Skip to content

Commit a86d29d

Browse files
author
Andrew Slotin
authored
Merge pull request #118 from instana/participate_in_w3c_context
Participate in w3c context
2 parents 19a7d10 + 53862fc commit a86d29d

File tree

6 files changed

+376
-98
lines changed

6 files changed

+376
-98
lines changed

propagation.go

Lines changed: 90 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,7 @@ func injectTraceContext(sc SpanContext, opaqueCarrier interface{}) error {
7373
}
7474
}
7575

76-
if trCtx, ok := sc.ForeignParent.(w3ctrace.Context); ok {
77-
w3ctrace.Inject(trCtx, h)
78-
}
76+
addW3CTraceContext(h, sc)
7977
}
8078

8179
carrier.Set(exstfieldT, FormatID(sc.TraceID))
@@ -85,6 +83,7 @@ func injectTraceContext(sc SpanContext, opaqueCarrier interface{}) error {
8583
for k, v := range sc.Baggage {
8684
carrier.Set(exstfieldB+k, v)
8785
}
86+
8887
return nil
8988
}
9089

@@ -98,27 +97,17 @@ func extractTraceContext(opaqueCarrier interface{}) (SpanContext, error) {
9897
return spanContext, ot.ErrInvalidCarrier
9998
}
10099

101-
var fieldCount int
100+
if c, ok := opaqueCarrier.(ot.HTTPHeadersCarrier); ok {
101+
pickupW3CTraceContext(http.Header(c), &spanContext)
102+
}
103+
104+
var traceID, spanID string
102105
err := carrier.ForeachKey(func(k, v string) error {
103106
switch strings.ToLower(k) {
104107
case FieldT:
105-
fieldCount++
106-
107-
traceID, err := ParseID(v)
108-
if err != nil {
109-
return ot.ErrSpanContextCorrupted
110-
}
111-
112-
spanContext.TraceID = traceID
108+
traceID = v
113109
case FieldS:
114-
fieldCount++
115-
116-
spanID, err := ParseID(v)
117-
if err != nil {
118-
return ot.ErrSpanContextCorrupted
119-
}
120-
121-
spanContext.SpanID = spanID
110+
spanID = v
122111
case FieldL:
123112
spanContext.Suppressed = parseLevel(v)
124113
default:
@@ -134,21 +123,95 @@ func extractTraceContext(opaqueCarrier interface{}) (SpanContext, error) {
134123
return spanContext, err
135124
}
136125

137-
if fieldCount == 0 {
138-
return spanContext, ot.ErrSpanContextNotFound
139-
} else if fieldCount < 2 {
126+
if traceID == "" && spanID == "" {
127+
// there was no trace context provided in Instana headers, but we still
128+
// need to check if we found it earlier in W3C trace context state before
129+
// claiming that it was not found
130+
if spanContext.TraceID == 0 && spanContext.SpanID == 0 {
131+
return spanContext, ot.ErrSpanContextNotFound
132+
}
133+
134+
return spanContext, nil
135+
}
136+
137+
spanContext.TraceID, err = ParseID(traceID)
138+
if err != nil {
140139
return spanContext, ot.ErrSpanContextCorrupted
141140
}
142141

143-
if c, ok := opaqueCarrier.(ot.HTTPHeadersCarrier); ok {
144-
if trCtx, err := w3ctrace.Extract(http.Header(c)); err == nil {
145-
spanContext.ForeignParent = trCtx
146-
}
142+
spanContext.SpanID, err = ParseID(spanID)
143+
if err != nil {
144+
return spanContext, ot.ErrSpanContextCorrupted
147145
}
148146

149147
return spanContext, nil
150148
}
151149

150+
func addW3CTraceContext(h http.Header, sc SpanContext) {
151+
traceID, spanID := FormatID(sc.TraceID), FormatID(sc.SpanID)
152+
153+
// check for an existing w3c trace
154+
trCtx, ok := sc.ForeignParent.(w3ctrace.Context)
155+
if !ok {
156+
// initiate trace if none
157+
trCtx = w3ctrace.New(w3ctrace.Parent{
158+
Version: w3ctrace.Version_Max,
159+
TraceID: traceID,
160+
ParentID: spanID,
161+
Flags: w3ctrace.Flags{
162+
Sampled: !sc.Suppressed,
163+
},
164+
})
165+
}
166+
167+
// update the traceparent parent ID if any of trace contexts enable tracing
168+
p := trCtx.Parent()
169+
if !sc.Suppressed || p.Flags.Sampled {
170+
p.ParentID = spanID
171+
}
172+
173+
// sync the traceparent `sampled` flags with the X-Instana-L value
174+
p.Flags.Sampled = !sc.Suppressed
175+
176+
// participate in w3c trace context if tracing is enabled
177+
if !sc.Suppressed {
178+
trCtx.RawState = trCtx.State().Add(w3ctrace.VendorInstana, traceID+";"+spanID).String()
179+
}
180+
181+
trCtx.RawParent = p.String()
182+
w3ctrace.Inject(trCtx, h)
183+
}
184+
185+
func pickupW3CTraceContext(h http.Header, sc *SpanContext) {
186+
trCtx, err := w3ctrace.Extract(h)
187+
if err != nil {
188+
return
189+
}
190+
sc.ForeignParent = trCtx
191+
192+
vd, ok := trCtx.State().Fetch(w3ctrace.VendorInstana)
193+
if !ok {
194+
return
195+
}
196+
197+
i := strings.Index(vd, ";")
198+
if i < 0 {
199+
return
200+
}
201+
202+
traceID, err := ParseID(vd[:i])
203+
if err != nil {
204+
return
205+
}
206+
207+
spanID, err := ParseID(vd[i+1:])
208+
if err != nil {
209+
return
210+
}
211+
212+
sc.TraceID, sc.SpanID = traceID, spanID
213+
}
214+
152215
func parseLevel(s string) bool {
153216
return s == "0"
154217
}

0 commit comments

Comments
 (0)