Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ function registerSuite(w3cTraceCorrelationDisabled) {
const responseBody = response.body;
verifyHttpHeadersOnDownstreamRequest(testDefinition, valuesForPlaceholders, responseBody);

const suppressed = testDefinition['X-INSTANA-L in'] === '0';
const suppressed = testDefinition.suppressed === true;
Copy link
Copy Markdown
Contributor Author

@kirrg001 kirrg001 Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expected output is now defined in the JSON files.
Checking X-INSTANA-L is no longer enough, we need to also test if no X-INSTANA-L value is received.

if (suppressed) {
await delay(500);
const spans = await control.getSpans();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ module.exports = function () {

headers = { ...headers, ...parseHeaderList(testDefinition['request headers in']) };

const suppressed = testDefinition['X-INSTANA-L in'] === '0';
const suppressed = testDefinition.suppressed === true;

const basePath = '/start';
const query = testDefinition['query in'];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,35 +231,39 @@
},
{
"Scenario": "only X-INSTANA-L=0",
"What to do?": "Dont create spans, send X-INSTANA-L=0 and spec headers downstream with sampled=0",
"What to do?": "Don't create spans, send X-INSTANA-L=0 and spec headers downstream with sampled=0",
"X-INSTANA-L in": "0",
"suppressed": true,
"X-INSTANA-L out": "0",
"traceparent out": "00-0000000000000000$new_64_bit_trace_id-$new_span_id-02",
"index": 12
},
{
"Scenario": "X-INSTANA-L=0 plus -T and -S",
"What to do?": "Dont create spans, send X-INSTANA-L=0 and spec headers downstream with sampled=0",
"What to do?": "Don't create spans, send X-INSTANA-L=0 and spec headers downstream with sampled=0",
"X-INSTANA-T in": "fa2375d711a4ca0f",
"X-INSTANA-S in": "37cb2d6e9b1c078a",
"X-INSTANA-L in": "0",
"suppressed": true,
"X-INSTANA-L out": "0",
"traceparent out": "00-0000000000000000$new_64_bit_trace_id-$new_span_id-02",
"index": 13
},
{
"Scenario": "X-INSTANA-L=0 plus traceparent",
"What to do?": "Dont create spans, send X-INSTANA-L=0 and spec headers downstream with sampled=0",
"What to do?": "Don't create spans, send X-INSTANA-L=0 and spec headers downstream with sampled=0",
"X-INSTANA-L in": "0",
"suppressed": true,
"traceparent in": "00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01",
"X-INSTANA-L out": "0",
"traceparent out": "00-0af7651916cd43dd8448eb211c80319c-$new_span_id-00",
"index": 14
},
{
"Scenario": "X-INSTANA-L=0 plus traceparent and tracestate",
"What to do?": "Dont create spans, send X-INSTANA-L=0 and spec headers downstream with sampled=0",
"What to do?": "Don't create spans, send X-INSTANA-L=0 and spec headers downstream with sampled=0",
"X-INSTANA-L in": "0",
"suppressed": true,
"traceparent in": "00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01",
"tracestate in": "congo=ucfJifl5GOE,rojo=00f067aa0ba902b7",
"X-INSTANA-L out": "0",
Expand Down Expand Up @@ -515,39 +519,43 @@
},
{
"Scenario": "w3c off, only X-INSTANA-L=0",
"What to do?": "Dont create spans, send X-INSTANA-L=0 and spec headers downstream with sampled=0",
"What to do?": "Don't create spans, send X-INSTANA-L=0 and spec headers downstream with sampled=0",
"INSTANA_DISABLE_W3C_TRACE_CORRELATION": "yes_please",
"X-INSTANA-L in": "0",
"suppressed": true,
"X-INSTANA-L out": "0",
"traceparent out": "00-0000000000000000$new_64_bit_trace_id-$new_span_id-02",
"index": 28
},
{
"Scenario": "w3c off, X-INSTANA-L=0 plus -T and -S",
"What to do?": "Dont create spans, send X-INSTANA-L=0 and spec headers downstream with sampled=0",
"What to do?": "Don't create spans, send X-INSTANA-L=0 and spec headers downstream with sampled=0",
"INSTANA_DISABLE_W3C_TRACE_CORRELATION": "w3c_trace_correlation_stinks",
"X-INSTANA-T in": "fa2375d711a4ca0f",
"X-INSTANA-S in": "37cb2d6e9b1c078a",
"X-INSTANA-L in": "0",
"suppressed": true,
"X-INSTANA-L out": "0",
"traceparent out": "00-0000000000000000$new_64_bit_trace_id-$new_span_id-02",
"index": 29
},
{
"Scenario": "w3c off, X-INSTANA-L=0 plus traceparent",
"What to do?": "Dont create spans, send X-INSTANA-L=0 and spec headers downstream with sampled=0",
"What to do?": "Don't create spans, send X-INSTANA-L=0 and spec headers downstream with sampled=0",
"INSTANA_DISABLE_W3C_TRACE_CORRELATION": "true",
"X-INSTANA-L in": "0",
"suppressed": true,
"traceparent in": "00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01",
"X-INSTANA-L out": "0",
"traceparent out": "00-0af7651916cd43dd8448eb211c80319c-$new_span_id-00",
"index": 30
},
{
"Scenario": "w3c off, X-INSTANA-L=0 plus traceparent and tracestate",
"What to do?": "Dont create spans, send X-INSTANA-L=0 and spec headers downstream with sampled=0",
"What to do?": "Don't create spans, send X-INSTANA-L=0 and spec headers downstream with sampled=0",
"INSTANA_DISABLE_W3C_TRACE_CORRELATION": "yes",
"X-INSTANA-L in": "0",
"suppressed": true,
"traceparent in": "00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01",
"tracestate in": "congo=ucfJifl5GOE,rojo=00f067aa0ba902b7",
"X-INSTANA-L out": "0",
Expand Down Expand Up @@ -591,22 +599,11 @@
},
{
"Scenario": "traceparent but no tracestate, sampled flag is 0",
"What to do?": "Ignore the sampled flag, continue the trace from traceparent, set span.lt and span.tp, but not span.ia",
"What to do?": "Respect the sampled=0 flag, suppress tracing, pass sampled=0 downstream",
"traceparent in": "00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-00",
"Server-Timing": "intid;desc=8448eb211c80319c",
"entrySpan.t": "8448eb211c80319c",
"entrySpan.p": "b9c7c989f97918e1",
"entrySpan.s": "$new_span_id_1",
"entrySpan.tp": true,
"entrySpan.lt": "0af7651916cd43dd8448eb211c80319c",
"exitSpan.t": "8448eb211c80319c",
"exitSpan.p": "$new_span_id_1",
"exitSpan.s": "$new_span_id_2",
"X-INSTANA-T out": "8448eb211c80319c",
"X-INSTANA-S out": "$new_span_id_2",
"X-INSTANA-L out": "1",
"traceparent out": "00-0af7651916cd43dd8448eb211c80319c-$new_span_id_2-01",
"tracestate out": "in=8448eb211c80319c;$new_span_id_2",
"suppressed": true,
"X-INSTANA-L out": "0",
"traceparent out": "00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-00",
"index": 34
},
{
Expand Down Expand Up @@ -774,4 +771,4 @@
"tracestate out": "in=fa2375d711a4ca0f;$new_span_id_2",
"index": 42
}
]
]
Original file line number Diff line number Diff line change
Expand Up @@ -169,21 +169,73 @@ module.exports = function () {
})
);

// First request to Instana already has spec headers with sampled=0, simulating a (spec) trace in progress where
// the most recent upstream service did not record tracing data. We still expect Instana to continue the W3C
// trace with the W3C trace ID from traceparent (the parent element has not been recorded, but other ancestor
// elements might have been recorded). We also expect the correct spec headers to be passed downstream by the
// Instana service. In particular, it should keep the same trace ID it received when passing down spec headers.
// Furthermore, the random trace ID flag should be set since it was set in the incoming header.
it('Instana continues a spec trace with sampled=0 (upstream sets the random trace ID flag)', () =>
// W3C sampled=0 (flag 02: sampled=0, random-trace-id=1), no X-INSTANA-L
it('Instana respects W3C sampled=0 flag (with random-trace-id flag)', () =>
startRequest({
app: instanaAppControls,
depth: 1,
withSpecHeaders: 'valid-not-sampled-with-random-trace-id'
})
.then(response => {
response = response && response.body ? JSON.parse(response.body) : response;
expect(response.instanaHeaders).to.be.an('object');
expect(response.instanaHeaders.t).to.not.exist;
expect(response.instanaHeaders.s).to.not.exist;
expect(response.instanaHeaders.l).to.equal('0');
const traceparent = response.w3cTraceContext.receivedHeaders.traceparent;
const tracestate = response.w3cTraceContext.receivedHeaders.tracestate;
// sampled=0 is passed down, random-trace-id flag is preserved (flag 02)
expect(traceparent).to.match(new RegExp(`00-${foreignTraceId}-${foreignParentId}-02`));
expect(tracestate).to.equal('thing=foo,bar=baz');
})
.then(() => delay(500))
.then(() =>
agentControls.getSpans().then(spans => {
expect(spans).to.have.lengthOf(0);
})
));

// W3C sampled=0 (flag 00: sampled=0, random-trace-id=0), no X-INSTANA-L
it('Instana respects W3C sampled=0 flag (without random-trace-id flag)', () =>
startRequest({
app: instanaAppControls,
depth: 1,
withSpecHeaders: 'valid-not-sampled-no-random-trace-id'
})
.then(response => {
response = response && response.body ? JSON.parse(response.body) : response;
expect(response.instanaHeaders).to.be.an('object');
expect(response.instanaHeaders.t).to.not.exist;
expect(response.instanaHeaders.s).to.not.exist;
// X-INSTANA-L: 0 is passed down (derived from W3C sampled=0)
expect(response.instanaHeaders.l).to.equal('0');
expect(response.w3cTraceContext).to.be.an('object');
expect(response.w3cTraceContext.receivedHeaders).to.be.an('object');
const traceparent = response.w3cTraceContext.receivedHeaders.traceparent;
const tracestate = response.w3cTraceContext.receivedHeaders.tracestate;
// sampled=0 is passed down (flag stays 00)
expect(traceparent).to.match(new RegExp(`00-${foreignTraceId}-${foreignParentId}-00`));
expect(tracestate).to.equal('thing=foo,bar=baz');
})
// give spans a chance to come in
.then(() => delay(500))
.then(() =>
// verify there are no spans
agentControls.getSpans().then(spans => {
expect(spans).to.have.lengthOf(0);
})
));

// W3C sampled=1, no X-INSTANA-L: Should trace normally
it('Instana respects incoming W3C sampled=1 flag and traces (no X-INSTANA-L)', () =>
startRequest({
app: instanaAppControls,
depth: 1,
withSpecHeaders: 'valid-sampled-no-random-trace-id'
}).then(response => {
const { traceparent, tracestate } = getSpecHeadersFromFinalHttpRequest(response);
return retryUntilSpansMatch(agentControls, spans => {
const instanaHttpEntryRoot = verifyHttpEntry({
const instanaHttpEntry = verifyHttpEntry({
spans,
instanaAppControls,
parentSpan: {
Expand All @@ -194,44 +246,117 @@ module.exports = function () {
usedTraceParent: true,
longTraceId: foreignTraceId
});
const instanaHttpExit = verifyHttpExit(spans, instanaHttpEntryRoot, '/end');
const instanaHttpExit = verifyHttpExit(spans, instanaHttpEntry, '/end');

// W3C sampled=1 is respected: spans created, sampled=1 passed downstream
const instanaExitSpanId = instanaHttpExit.s;
expect(traceparent).to.match(new RegExp(`00-${foreignTraceId}-${instanaExitSpanId}-03`));
expect(traceparent).to.match(new RegExp(`00-${foreignTraceId}-${instanaExitSpanId}-01`));
expect(tracestate).to.match(new RegExp(`in=${foreignTraceIdRightHalf};${instanaExitSpanId}`));
});
}));

// First request to Instana already has spec headers with sampled=0, simulating a (spec) trace in progress where
// the most recent upstream service did not record tracing data. We still expect Instana to continue the W3C
// trace with the W3C trace ID from traceparent (the parent element has not been recorded, but other ancestor
// elements might have been recorded). We also expect the correct spec headers to be passed downstream by the
// Instana service. In particular, it should keep the same trace ID it received when passing down spec headers.
// Furthermore, the random trace ID flag should be unset since it was unset in the incoming header.
it('Instana continues a spec trace with sampled=0 (upstream does not set the random trace ID flag)', () =>
// W3C sampled=0 + X-INSTANA-L: 0: Both say suppress, should suppress
it('W3C sampled=0 + X-INSTANA-L=0: suppresses tracing (both agree)', () =>
startRequest({
app: instanaAppControls,
depth: 1,
withSpecHeaders: 'valid-not-sampled-no-random-trace-id'
withSpecHeaders: 'valid-not-sampled-no-random-trace-id',
withInstanaHeaders: 'suppress'
})
.then(response => {
response = response && response.body ? JSON.parse(response.body) : response;
expect(response.instanaHeaders.t).to.not.exist;
expect(response.instanaHeaders.s).to.not.exist;
expect(response.instanaHeaders.l).to.equal('0');
const traceparent = response.w3cTraceContext.receivedHeaders.traceparent;
expect(traceparent).to.match(new RegExp(`00-${foreignTraceId}-${foreignParentId}-00`));
})
.then(() => delay(500))
.then(() =>
agentControls.getSpans().then(spans => {
expect(spans).to.have.lengthOf(0);
})
));

// W3C sampled=0 + X-INSTANA-L: 1: X-INSTANA-L wins, should trace
it('W3C sampled=0 + X-INSTANA-L=1: traces anyway (X-INSTANA-L has priority)', () =>
startRequest({
app: instanaAppControls,
depth: 1,
withSpecHeaders: 'valid-not-sampled-no-random-trace-id',
withInstanaHeaders: 'trace-in-progress'
}).then(response => {
const { traceparent, tracestate } = getSpecHeadersFromFinalHttpRequest(response);
return retryUntilSpansMatch(agentControls, spans => {
const instanaHttpEntryRoot = verifyHttpEntry({
const instanaHttpEntry = verifyHttpEntry({
instanaAppControls,
spans,
parentSpan: {
t: upstreamInstanaTraceId,
s: upstreamInstanaParentId
},
url: '/start'
});
const instanaHttpExit = verifyHttpExit(spans, instanaHttpEntry, '/end');

// X-INSTANA-L: 1 overrides W3C sampled=0, so sampled=1 is passed down
const instanaExitSpanId = instanaHttpExit.s;
expect(traceparent).to.match(new RegExp(`00-${foreignTraceId}-${instanaExitSpanId}-01`));
expect(tracestate).to.match(new RegExp(`in=${upstreamInstanaTraceId};${instanaExitSpanId}`));
});
}));

// W3C sampled=1 + X-INSTANA-L: 0: X-INSTANA-L wins, should suppress
it('W3C sampled=1 + X-INSTANA-L=0: suppresses tracing (X-INSTANA-L has priority)', () =>
startRequest({
app: instanaAppControls,
depth: 1,
withSpecHeaders: 'valid-sampled-no-random-trace-id',
withInstanaHeaders: 'suppress'
})
.then(response => {
response = response && response.body ? JSON.parse(response.body) : response;
expect(response.instanaHeaders.t).to.not.exist;
expect(response.instanaHeaders.s).to.not.exist;
expect(response.instanaHeaders.l).to.equal('0');
const traceparent = response.w3cTraceContext.receivedHeaders.traceparent;
// X-INSTANA-L: 0 overrides W3C sampled=1, so sampled=0 is passed down
const traceParentMatch = new RegExp(`00-${foreignTraceId}-([0-9a-f]{16})-00`).exec(traceparent);
expect(traceParentMatch).to.exist;
expect(traceParentMatch[1]).to.not.equal(foreignParentId);
})
.then(() => delay(500))
.then(() =>
agentControls.getSpans().then(spans => {
expect(spans).to.have.lengthOf(0);
})
));

// W3C sampled=1 + X-INSTANA-L: 1: Both say trace, should trace
it('W3C sampled=1 + X-INSTANA-L=1: traces (both agree)', () =>
startRequest({
app: instanaAppControls,
depth: 1,
withSpecHeaders: 'valid-sampled-no-random-trace-id',
withInstanaHeaders: 'trace-in-progress'
}).then(response => {
const { traceparent, tracestate } = getSpecHeadersFromFinalHttpRequest(response);
return retryUntilSpansMatch(agentControls, spans => {
const instanaHttpEntry = verifyHttpEntry({
instanaAppControls,
spans,
parentSpan: {
t: foreignTraceIdRightHalf,
s: foreignParentId
t: upstreamInstanaTraceId,
s: upstreamInstanaParentId
},
url: '/start',
usedTraceParent: true,
longTraceId: foreignTraceId
url: '/start'
});
const instanaHttpExit = verifyHttpExit(spans, instanaHttpEntryRoot, '/end');
const instanaHttpExit = verifyHttpExit(spans, instanaHttpEntry, '/end');

// Both agree on tracing, sampled=1 is passed down
const instanaExitSpanId = instanaHttpExit.s;
expect(traceparent).to.match(new RegExp(`00-${foreignTraceId}-${instanaExitSpanId}-01`));
expect(tracestate).to.match(new RegExp(`in=${foreignTraceIdRightHalf};${instanaExitSpanId}`));
expect(tracestate).to.match(new RegExp(`in=${upstreamInstanaTraceId};${instanaExitSpanId}`));
});
}));

Expand Down
Loading