@@ -73,9 +73,7 @@ func injectTraceContext(sc SpanContext, opaqueCarrier interface{}) error {
73
73
}
74
74
}
75
75
76
- if trCtx , ok := sc .ForeignParent .(w3ctrace.Context ); ok {
77
- w3ctrace .Inject (trCtx , h )
78
- }
76
+ addW3CTraceContext (h , sc )
79
77
}
80
78
81
79
carrier .Set (exstfieldT , FormatID (sc .TraceID ))
@@ -85,6 +83,7 @@ func injectTraceContext(sc SpanContext, opaqueCarrier interface{}) error {
85
83
for k , v := range sc .Baggage {
86
84
carrier .Set (exstfieldB + k , v )
87
85
}
86
+
88
87
return nil
89
88
}
90
89
@@ -98,27 +97,17 @@ func extractTraceContext(opaqueCarrier interface{}) (SpanContext, error) {
98
97
return spanContext , ot .ErrInvalidCarrier
99
98
}
100
99
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
102
105
err := carrier .ForeachKey (func (k , v string ) error {
103
106
switch strings .ToLower (k ) {
104
107
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
113
109
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
122
111
case FieldL :
123
112
spanContext .Suppressed = parseLevel (v )
124
113
default :
@@ -134,21 +123,95 @@ func extractTraceContext(opaqueCarrier interface{}) (SpanContext, error) {
134
123
return spanContext , err
135
124
}
136
125
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 {
140
139
return spanContext , ot .ErrSpanContextCorrupted
141
140
}
142
141
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
147
145
}
148
146
149
147
return spanContext , nil
150
148
}
151
149
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
+
152
215
func parseLevel (s string ) bool {
153
216
return s == "0"
154
217
}
0 commit comments