@@ -169,21 +169,73 @@ module.exports = function () {
169169 } )
170170 ) ;
171171
172- // First request to Instana already has spec headers with sampled=0, simulating a (spec) trace in progress where
173- // the most recent upstream service did not record tracing data. We still expect Instana to continue the W3C
174- // trace with the W3C trace ID from traceparent (the parent element has not been recorded, but other ancestor
175- // elements might have been recorded). We also expect the correct spec headers to be passed downstream by the
176- // Instana service. In particular, it should keep the same trace ID it received when passing down spec headers.
177- // Furthermore, the random trace ID flag should be set since it was set in the incoming header.
178- it ( 'Instana continues a spec trace with sampled=0 (upstream sets the random trace ID flag)' , ( ) =>
172+ // W3C sampled=0 (flag 02: sampled=0, random-trace-id=1), no X-INSTANA-L
173+ it ( 'Instana respects W3C sampled=0 flag (with random-trace-id flag)' , ( ) =>
179174 startRequest ( {
180175 app : instanaAppControls ,
181176 depth : 1 ,
182177 withSpecHeaders : 'valid-not-sampled-with-random-trace-id'
178+ } )
179+ . then ( response => {
180+ response = response && response . body ? JSON . parse ( response . body ) : response ;
181+ expect ( response . instanaHeaders ) . to . be . an ( 'object' ) ;
182+ expect ( response . instanaHeaders . t ) . to . not . exist ;
183+ expect ( response . instanaHeaders . s ) . to . not . exist ;
184+ expect ( response . instanaHeaders . l ) . to . equal ( '0' ) ;
185+ const traceparent = response . w3cTraceContext . receivedHeaders . traceparent ;
186+ const tracestate = response . w3cTraceContext . receivedHeaders . tracestate ;
187+ // sampled=0 is passed down, random-trace-id flag is preserved (flag 02)
188+ expect ( traceparent ) . to . match ( new RegExp ( `00-${ foreignTraceId } -${ foreignParentId } -02` ) ) ;
189+ expect ( tracestate ) . to . equal ( 'thing=foo,bar=baz' ) ;
190+ } )
191+ . then ( ( ) => delay ( 500 ) )
192+ . then ( ( ) =>
193+ agentControls . getSpans ( ) . then ( spans => {
194+ expect ( spans ) . to . have . lengthOf ( 0 ) ;
195+ } )
196+ ) ) ;
197+
198+ // W3C sampled=0 (flag 00: sampled=0, random-trace-id=0), no X-INSTANA-L
199+ it ( 'Instana respects W3C sampled=0 flag (without random-trace-id flag)' , ( ) =>
200+ startRequest ( {
201+ app : instanaAppControls ,
202+ depth : 1 ,
203+ withSpecHeaders : 'valid-not-sampled-no-random-trace-id'
204+ } )
205+ . then ( response => {
206+ response = response && response . body ? JSON . parse ( response . body ) : response ;
207+ expect ( response . instanaHeaders ) . to . be . an ( 'object' ) ;
208+ expect ( response . instanaHeaders . t ) . to . not . exist ;
209+ expect ( response . instanaHeaders . s ) . to . not . exist ;
210+ // X-INSTANA-L: 0 is passed down (derived from W3C sampled=0)
211+ expect ( response . instanaHeaders . l ) . to . equal ( '0' ) ;
212+ expect ( response . w3cTraceContext ) . to . be . an ( 'object' ) ;
213+ expect ( response . w3cTraceContext . receivedHeaders ) . to . be . an ( 'object' ) ;
214+ const traceparent = response . w3cTraceContext . receivedHeaders . traceparent ;
215+ const tracestate = response . w3cTraceContext . receivedHeaders . tracestate ;
216+ // sampled=0 is passed down (flag stays 00)
217+ expect ( traceparent ) . to . match ( new RegExp ( `00-${ foreignTraceId } -${ foreignParentId } -00` ) ) ;
218+ expect ( tracestate ) . to . equal ( 'thing=foo,bar=baz' ) ;
219+ } )
220+ // give spans a chance to come in
221+ . then ( ( ) => delay ( 500 ) )
222+ . then ( ( ) =>
223+ // verify there are no spans
224+ agentControls . getSpans ( ) . then ( spans => {
225+ expect ( spans ) . to . have . lengthOf ( 0 ) ;
226+ } )
227+ ) ) ;
228+
229+ // W3C sampled=1, no X-INSTANA-L: Should trace normally
230+ it ( 'Instana respects incoming W3C sampled=1 flag and traces (no X-INSTANA-L)' , ( ) =>
231+ startRequest ( {
232+ app : instanaAppControls ,
233+ depth : 1 ,
234+ withSpecHeaders : 'valid-sampled-no-random-trace-id'
183235 } ) . then ( response => {
184236 const { traceparent, tracestate } = getSpecHeadersFromFinalHttpRequest ( response ) ;
185237 return retryUntilSpansMatch ( agentControls , spans => {
186- const instanaHttpEntryRoot = verifyHttpEntry ( {
238+ const instanaHttpEntry = verifyHttpEntry ( {
187239 spans,
188240 instanaAppControls,
189241 parentSpan : {
@@ -194,44 +246,117 @@ module.exports = function () {
194246 usedTraceParent : true ,
195247 longTraceId : foreignTraceId
196248 } ) ;
197- const instanaHttpExit = verifyHttpExit ( spans , instanaHttpEntryRoot , '/end' ) ;
249+ const instanaHttpExit = verifyHttpExit ( spans , instanaHttpEntry , '/end' ) ;
198250
251+ // W3C sampled=1 is respected: spans created, sampled=1 passed downstream
199252 const instanaExitSpanId = instanaHttpExit . s ;
200- expect ( traceparent ) . to . match ( new RegExp ( `00-${ foreignTraceId } -${ instanaExitSpanId } -03 ` ) ) ;
253+ expect ( traceparent ) . to . match ( new RegExp ( `00-${ foreignTraceId } -${ instanaExitSpanId } -01 ` ) ) ;
201254 expect ( tracestate ) . to . match ( new RegExp ( `in=${ foreignTraceIdRightHalf } ;${ instanaExitSpanId } ` ) ) ;
202255 } ) ;
203256 } ) ) ;
204257
205- // First request to Instana already has spec headers with sampled=0, simulating a (spec) trace in progress where
206- // the most recent upstream service did not record tracing data. We still expect Instana to continue the W3C
207- // trace with the W3C trace ID from traceparent (the parent element has not been recorded, but other ancestor
208- // elements might have been recorded). We also expect the correct spec headers to be passed downstream by the
209- // Instana service. In particular, it should keep the same trace ID it received when passing down spec headers.
210- // Furthermore, the random trace ID flag should be unset since it was unset in the incoming header.
211- it ( 'Instana continues a spec trace with sampled=0 (upstream does not set the random trace ID flag)' , ( ) =>
258+ // W3C sampled=0 + X-INSTANA-L: 0: Both say suppress, should suppress
259+ it ( 'W3C sampled=0 + X-INSTANA-L=0: suppresses tracing (both agree)' , ( ) =>
212260 startRequest ( {
213261 app : instanaAppControls ,
214262 depth : 1 ,
215- withSpecHeaders : 'valid-not-sampled-no-random-trace-id'
263+ withSpecHeaders : 'valid-not-sampled-no-random-trace-id' ,
264+ withInstanaHeaders : 'suppress'
265+ } )
266+ . then ( response => {
267+ response = response && response . body ? JSON . parse ( response . body ) : response ;
268+ expect ( response . instanaHeaders . t ) . to . not . exist ;
269+ expect ( response . instanaHeaders . s ) . to . not . exist ;
270+ expect ( response . instanaHeaders . l ) . to . equal ( '0' ) ;
271+ const traceparent = response . w3cTraceContext . receivedHeaders . traceparent ;
272+ expect ( traceparent ) . to . match ( new RegExp ( `00-${ foreignTraceId } -${ foreignParentId } -00` ) ) ;
273+ } )
274+ . then ( ( ) => delay ( 500 ) )
275+ . then ( ( ) =>
276+ agentControls . getSpans ( ) . then ( spans => {
277+ expect ( spans ) . to . have . lengthOf ( 0 ) ;
278+ } )
279+ ) ) ;
280+
281+ // W3C sampled=0 + X-INSTANA-L: 1: X-INSTANA-L wins, should trace
282+ it ( 'W3C sampled=0 + X-INSTANA-L=1: traces anyway (X-INSTANA-L has priority)' , ( ) =>
283+ startRequest ( {
284+ app : instanaAppControls ,
285+ depth : 1 ,
286+ withSpecHeaders : 'valid-not-sampled-no-random-trace-id' ,
287+ withInstanaHeaders : 'trace-in-progress'
216288 } ) . then ( response => {
217289 const { traceparent, tracestate } = getSpecHeadersFromFinalHttpRequest ( response ) ;
218290 return retryUntilSpansMatch ( agentControls , spans => {
219- const instanaHttpEntryRoot = verifyHttpEntry ( {
291+ const instanaHttpEntry = verifyHttpEntry ( {
292+ instanaAppControls,
220293 spans,
294+ parentSpan : {
295+ t : upstreamInstanaTraceId ,
296+ s : upstreamInstanaParentId
297+ } ,
298+ url : '/start'
299+ } ) ;
300+ const instanaHttpExit = verifyHttpExit ( spans , instanaHttpEntry , '/end' ) ;
301+
302+ // X-INSTANA-L: 1 overrides W3C sampled=0, so sampled=1 is passed down
303+ const instanaExitSpanId = instanaHttpExit . s ;
304+ expect ( traceparent ) . to . match ( new RegExp ( `00-${ foreignTraceId } -${ instanaExitSpanId } -01` ) ) ;
305+ expect ( tracestate ) . to . match ( new RegExp ( `in=${ upstreamInstanaTraceId } ;${ instanaExitSpanId } ` ) ) ;
306+ } ) ;
307+ } ) ) ;
308+
309+ // W3C sampled=1 + X-INSTANA-L: 0: X-INSTANA-L wins, should suppress
310+ it ( 'W3C sampled=1 + X-INSTANA-L=0: suppresses tracing (X-INSTANA-L has priority)' , ( ) =>
311+ startRequest ( {
312+ app : instanaAppControls ,
313+ depth : 1 ,
314+ withSpecHeaders : 'valid-sampled-no-random-trace-id' ,
315+ withInstanaHeaders : 'suppress'
316+ } )
317+ . then ( response => {
318+ response = response && response . body ? JSON . parse ( response . body ) : response ;
319+ expect ( response . instanaHeaders . t ) . to . not . exist ;
320+ expect ( response . instanaHeaders . s ) . to . not . exist ;
321+ expect ( response . instanaHeaders . l ) . to . equal ( '0' ) ;
322+ const traceparent = response . w3cTraceContext . receivedHeaders . traceparent ;
323+ // X-INSTANA-L: 0 overrides W3C sampled=1, so sampled=0 is passed down
324+ const traceParentMatch = new RegExp ( `00-${ foreignTraceId } -([0-9a-f]{16})-00` ) . exec ( traceparent ) ;
325+ expect ( traceParentMatch ) . to . exist ;
326+ expect ( traceParentMatch [ 1 ] ) . to . not . equal ( foreignParentId ) ;
327+ } )
328+ . then ( ( ) => delay ( 500 ) )
329+ . then ( ( ) =>
330+ agentControls . getSpans ( ) . then ( spans => {
331+ expect ( spans ) . to . have . lengthOf ( 0 ) ;
332+ } )
333+ ) ) ;
334+
335+ // W3C sampled=1 + X-INSTANA-L: 1: Both say trace, should trace
336+ it ( 'W3C sampled=1 + X-INSTANA-L=1: traces (both agree)' , ( ) =>
337+ startRequest ( {
338+ app : instanaAppControls ,
339+ depth : 1 ,
340+ withSpecHeaders : 'valid-sampled-no-random-trace-id' ,
341+ withInstanaHeaders : 'trace-in-progress'
342+ } ) . then ( response => {
343+ const { traceparent, tracestate } = getSpecHeadersFromFinalHttpRequest ( response ) ;
344+ return retryUntilSpansMatch ( agentControls , spans => {
345+ const instanaHttpEntry = verifyHttpEntry ( {
221346 instanaAppControls,
347+ spans,
222348 parentSpan : {
223- t : foreignTraceIdRightHalf ,
224- s : foreignParentId
349+ t : upstreamInstanaTraceId ,
350+ s : upstreamInstanaParentId
225351 } ,
226- url : '/start' ,
227- usedTraceParent : true ,
228- longTraceId : foreignTraceId
352+ url : '/start'
229353 } ) ;
230- const instanaHttpExit = verifyHttpExit ( spans , instanaHttpEntryRoot , '/end' ) ;
354+ const instanaHttpExit = verifyHttpExit ( spans , instanaHttpEntry , '/end' ) ;
231355
356+ // Both agree on tracing, sampled=1 is passed down
232357 const instanaExitSpanId = instanaHttpExit . s ;
233358 expect ( traceparent ) . to . match ( new RegExp ( `00-${ foreignTraceId } -${ instanaExitSpanId } -01` ) ) ;
234- expect ( tracestate ) . to . match ( new RegExp ( `in=${ foreignTraceIdRightHalf } ;${ instanaExitSpanId } ` ) ) ;
359+ expect ( tracestate ) . to . match ( new RegExp ( `in=${ upstreamInstanaTraceId } ;${ instanaExitSpanId } ` ) ) ;
235360 } ) ;
236361 } ) ) ;
237362
0 commit comments