-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test: Add tests to demonstrate root trace ID behavior (#14426)
This adds node & browser integration tests to demonstrate the current behavior of "trace propagation" based on the current scope. It shows that the behavior is not really consistent and we should probably adjust it, but for now this PR does no changes. ## Browser In browser, the propagation context of the current scope is always picked up. This means that if you call `startSpan` multiple times in the root, both started spans will have the same trace ID, and possibly the same `parentSpanId` if there was an incoming trace. ## Node In node, the propagation context is ignored for the root context. So in the root, started spans will have different traces, and will also ignore parentSpanId (which is only theoretical, there will never really be a parentSpanId on the root scope in node, realistically). Outside of the root (so e.g. within any route handler, or even any `withScope` call), the behavior is the same as in browser - any started spans will share the same trace ID/parent span ID. ## What should we take away from this? In node, I would align the behavior to ignore the trace ID when we have no incoming trace (so no parentSpanId), and always use the traceId & parentSpanId if there is a parentSpanId on the scope (even the root scope, to be consistent). In browser, we cannot make this change because we rely on this behavior for the extended traces after pageload/navigation spans have ended.
- Loading branch information
Showing
14 changed files
with
313 additions
and
3 deletions.
There are no files selected for viewing
4 changes: 4 additions & 0 deletions
4
...ser-integration-tests/suites/public-api/startSpan/parallel-root-spans-in-scope/subject.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
Sentry.withScope(() => { | ||
Sentry.startSpan({ name: 'test_span_1' }, () => undefined); | ||
Sentry.startSpan({ name: 'test_span_2' }, () => undefined); | ||
}); |
41 changes: 41 additions & 0 deletions
41
...rowser-integration-tests/suites/public-api/startSpan/parallel-root-spans-in-scope/test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { expect } from '@playwright/test'; | ||
|
||
import type { TransactionEvent } from '@sentry/types'; | ||
import { sentryTest } from '../../../../utils/fixtures'; | ||
import { envelopeRequestParser, shouldSkipTracingTest, waitForTransactionRequest } from '../../../../utils/helpers'; | ||
|
||
sentryTest( | ||
'should send manually started parallel root spans outside of root context', | ||
async ({ getLocalTestUrl, page }) => { | ||
if (shouldSkipTracingTest()) { | ||
sentryTest.skip(); | ||
} | ||
|
||
const url = await getLocalTestUrl({ testDir: __dirname }); | ||
|
||
const transaction1ReqPromise = waitForTransactionRequest(page, event => event.transaction === 'test_span_1'); | ||
const transaction2ReqPromise = waitForTransactionRequest(page, event => event.transaction === 'test_span_2'); | ||
|
||
await page.goto(url); | ||
|
||
const [transaction1Req, transaction2Req] = await Promise.all([transaction1ReqPromise, transaction2ReqPromise]); | ||
|
||
const transaction1 = envelopeRequestParser<TransactionEvent>(transaction1Req); | ||
const transaction2 = envelopeRequestParser<TransactionEvent>(transaction2Req); | ||
|
||
expect(transaction1).toBeDefined(); | ||
expect(transaction2).toBeDefined(); | ||
|
||
const trace1Id = transaction1.contexts?.trace?.trace_id; | ||
const trace2Id = transaction2.contexts?.trace?.trace_id; | ||
|
||
expect(trace1Id).toBeDefined(); | ||
expect(trace2Id).toBeDefined(); | ||
|
||
// We use the same traceID from the root propagation context here | ||
expect(trace1Id).toBe(trace2Id); | ||
|
||
expect(transaction1.contexts?.trace?.parent_span_id).toBeUndefined(); | ||
expect(transaction2.contexts?.trace?.parent_span_id).toBeUndefined(); | ||
}, | ||
); |
8 changes: 8 additions & 0 deletions
8
...ration-tests/suites/public-api/startSpan/parallel-root-spans-with-parentSpanId/subject.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
Sentry.getCurrentScope().setPropagationContext({ | ||
parentSpanId: '1234567890123456', | ||
spanId: '123456789012345x', | ||
traceId: '12345678901234567890123456789012', | ||
}); | ||
|
||
Sentry.startSpan({ name: 'test_span_1' }, () => undefined); | ||
Sentry.startSpan({ name: 'test_span_2' }, () => undefined); |
38 changes: 38 additions & 0 deletions
38
...tegration-tests/suites/public-api/startSpan/parallel-root-spans-with-parentSpanId/test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { expect } from '@playwright/test'; | ||
|
||
import type { TransactionEvent } from '@sentry/types'; | ||
import { sentryTest } from '../../../../utils/fixtures'; | ||
import { envelopeRequestParser, shouldSkipTracingTest, waitForTransactionRequest } from '../../../../utils/helpers'; | ||
|
||
sentryTest( | ||
'should send manually started parallel root spans in root context with parentSpanId', | ||
async ({ getLocalTestUrl, page }) => { | ||
if (shouldSkipTracingTest()) { | ||
sentryTest.skip(); | ||
} | ||
|
||
const url = await getLocalTestUrl({ testDir: __dirname }); | ||
|
||
const transaction1ReqPromise = waitForTransactionRequest(page, event => event.transaction === 'test_span_1'); | ||
const transaction2ReqPromise = waitForTransactionRequest(page, event => event.transaction === 'test_span_2'); | ||
|
||
await page.goto(url); | ||
|
||
const [transaction1Req, transaction2Req] = await Promise.all([transaction1ReqPromise, transaction2ReqPromise]); | ||
|
||
const transaction1 = envelopeRequestParser<TransactionEvent>(transaction1Req); | ||
const transaction2 = envelopeRequestParser<TransactionEvent>(transaction2Req); | ||
|
||
expect(transaction1).toBeDefined(); | ||
expect(transaction2).toBeDefined(); | ||
|
||
const trace1Id = transaction1.contexts?.trace?.trace_id; | ||
const trace2Id = transaction2.contexts?.trace?.trace_id; | ||
|
||
expect(trace1Id).toBe('12345678901234567890123456789012'); | ||
expect(trace2Id).toBe('12345678901234567890123456789012'); | ||
|
||
expect(transaction1.contexts?.trace?.parent_span_id).toBe('1234567890123456'); | ||
expect(transaction2.contexts?.trace?.parent_span_id).toBe('1234567890123456'); | ||
}, | ||
); |
2 changes: 2 additions & 0 deletions
2
...ages/browser-integration-tests/suites/public-api/startSpan/parallel-root-spans/subject.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
Sentry.startSpan({ name: 'test_span_1' }, () => undefined); | ||
Sentry.startSpan({ name: 'test_span_2' }, () => undefined); |
38 changes: 38 additions & 0 deletions
38
...ackages/browser-integration-tests/suites/public-api/startSpan/parallel-root-spans/test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { expect } from '@playwright/test'; | ||
|
||
import type { TransactionEvent } from '@sentry/types'; | ||
import { sentryTest } from '../../../../utils/fixtures'; | ||
import { envelopeRequestParser, shouldSkipTracingTest, waitForTransactionRequest } from '../../../../utils/helpers'; | ||
|
||
sentryTest('should send manually started parallel root spans in root context', async ({ getLocalTestUrl, page }) => { | ||
if (shouldSkipTracingTest()) { | ||
sentryTest.skip(); | ||
} | ||
|
||
const url = await getLocalTestUrl({ testDir: __dirname }); | ||
|
||
const transaction1ReqPromise = waitForTransactionRequest(page, event => event.transaction === 'test_span_1'); | ||
const transaction2ReqPromise = waitForTransactionRequest(page, event => event.transaction === 'test_span_2'); | ||
|
||
await page.goto(url); | ||
|
||
const [transaction1Req, transaction2Req] = await Promise.all([transaction1ReqPromise, transaction2ReqPromise]); | ||
|
||
const transaction1 = envelopeRequestParser<TransactionEvent>(transaction1Req); | ||
const transaction2 = envelopeRequestParser<TransactionEvent>(transaction2Req); | ||
|
||
expect(transaction1).toBeDefined(); | ||
expect(transaction2).toBeDefined(); | ||
|
||
const trace1Id = transaction1.contexts?.trace?.trace_id; | ||
const trace2Id = transaction2.contexts?.trace?.trace_id; | ||
|
||
expect(trace1Id).toBeDefined(); | ||
expect(trace2Id).toBeDefined(); | ||
|
||
// We use the same traceID from the root propagation context here | ||
expect(trace1Id).toBe(trace2Id); | ||
|
||
expect(transaction1.contexts?.trace?.parent_span_id).toBeUndefined(); | ||
expect(transaction2.contexts?.trace?.parent_span_id).toBeUndefined(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
...ckages/node-integration-tests/suites/public-api/startSpan/parallel-root-spans/scenario.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { loggingTransport } from '@sentry-internal/node-integration-tests'; | ||
import * as Sentry from '@sentry/node'; | ||
|
||
Sentry.init({ | ||
dsn: 'https://[email protected]/1337', | ||
release: '1.0', | ||
tracesSampleRate: 1.0, | ||
transport: loggingTransport, | ||
}); | ||
|
||
Sentry.getCurrentScope().setPropagationContext({ | ||
parentSpanId: '1234567890123456', | ||
spanId: '123456789012345x', | ||
traceId: '12345678901234567890123456789012', | ||
}); | ||
|
||
const spanIdTraceId = Sentry.startSpan( | ||
{ | ||
name: 'test_span_1', | ||
}, | ||
span1 => span1.spanContext().traceId, | ||
); | ||
|
||
Sentry.startSpan( | ||
{ | ||
name: 'test_span_2', | ||
attributes: { spanIdTraceId }, | ||
}, | ||
() => undefined, | ||
); |
29 changes: 29 additions & 0 deletions
29
dev-packages/node-integration-tests/suites/public-api/startSpan/parallel-root-spans/test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { cleanupChildProcesses, createRunner } from '../../../../utils/runner'; | ||
|
||
afterAll(() => { | ||
cleanupChildProcesses(); | ||
}); | ||
|
||
test('should send manually started parallel root spans in root context', done => { | ||
expect.assertions(7); | ||
|
||
createRunner(__dirname, 'scenario.ts') | ||
.expect({ transaction: { transaction: 'test_span_1' } }) | ||
.expect({ | ||
transaction: transaction => { | ||
expect(transaction).toBeDefined(); | ||
const traceId = transaction.contexts?.trace?.trace_id; | ||
expect(traceId).toBeDefined(); | ||
|
||
// It ignores propagation context of the root context | ||
expect(traceId).not.toBe('12345678901234567890123456789012'); | ||
expect(transaction.contexts?.trace?.parent_span_id).toBeUndefined(); | ||
|
||
// Different trace ID than the first span | ||
const trace1Id = transaction.contexts?.trace?.data?.spanIdTraceId; | ||
expect(trace1Id).toBeDefined(); | ||
expect(trace1Id).not.toBe(traceId); | ||
}, | ||
}) | ||
.start(done); | ||
}); |
20 changes: 20 additions & 0 deletions
20
...n-tests/suites/public-api/startSpan/parallel-spans-in-scope-with-parentSpanId/scenario.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { loggingTransport } from '@sentry-internal/node-integration-tests'; | ||
import * as Sentry from '@sentry/node'; | ||
|
||
Sentry.init({ | ||
dsn: 'https://[email protected]/1337', | ||
release: '1.0', | ||
tracesSampleRate: 1.0, | ||
transport: loggingTransport, | ||
}); | ||
|
||
Sentry.withScope(scope => { | ||
scope.setPropagationContext({ | ||
parentSpanId: '1234567890123456', | ||
spanId: '123456789012345x', | ||
traceId: '12345678901234567890123456789012', | ||
}); | ||
|
||
Sentry.startSpan({ name: 'test_span_1' }, () => undefined); | ||
Sentry.startSpan({ name: 'test_span_2' }, () => undefined); | ||
}); |
34 changes: 34 additions & 0 deletions
34
...ation-tests/suites/public-api/startSpan/parallel-spans-in-scope-with-parentSpanId/test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { cleanupChildProcesses, createRunner } from '../../../../utils/runner'; | ||
|
||
afterAll(() => { | ||
cleanupChildProcesses(); | ||
}); | ||
|
||
test('should send manually started parallel root spans outside of root context with parentSpanId', done => { | ||
createRunner(__dirname, 'scenario.ts') | ||
.expect({ | ||
transaction: { | ||
transaction: 'test_span_1', | ||
contexts: { | ||
trace: { | ||
span_id: expect.any(String), | ||
parent_span_id: '1234567890123456', | ||
trace_id: '12345678901234567890123456789012', | ||
}, | ||
}, | ||
}, | ||
}) | ||
.expect({ | ||
transaction: { | ||
transaction: 'test_span_2', | ||
contexts: { | ||
trace: { | ||
span_id: expect.any(String), | ||
parent_span_id: '1234567890123456', | ||
trace_id: '12345678901234567890123456789012', | ||
}, | ||
}, | ||
}, | ||
}) | ||
.start(done); | ||
}); |
26 changes: 26 additions & 0 deletions
26
...es/node-integration-tests/suites/public-api/startSpan/parallel-spans-in-scope/scenario.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { loggingTransport } from '@sentry-internal/node-integration-tests'; | ||
import * as Sentry from '@sentry/node'; | ||
|
||
Sentry.init({ | ||
dsn: 'https://[email protected]/1337', | ||
release: '1.0', | ||
tracesSampleRate: 1.0, | ||
transport: loggingTransport, | ||
}); | ||
|
||
Sentry.withScope(() => { | ||
const spanIdTraceId = Sentry.startSpan( | ||
{ | ||
name: 'test_span_1', | ||
}, | ||
span1 => span1.spanContext().traceId, | ||
); | ||
|
||
Sentry.startSpan( | ||
{ | ||
name: 'test_span_2', | ||
attributes: { spanIdTraceId }, | ||
}, | ||
() => undefined, | ||
); | ||
}); |
27 changes: 27 additions & 0 deletions
27
...ckages/node-integration-tests/suites/public-api/startSpan/parallel-spans-in-scope/test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { cleanupChildProcesses, createRunner } from '../../../../utils/runner'; | ||
|
||
afterAll(() => { | ||
cleanupChildProcesses(); | ||
}); | ||
|
||
test('should send manually started parallel root spans outside of root context', done => { | ||
expect.assertions(6); | ||
|
||
createRunner(__dirname, 'scenario.ts') | ||
.expect({ transaction: { transaction: 'test_span_1' } }) | ||
.expect({ | ||
transaction: transaction => { | ||
expect(transaction).toBeDefined(); | ||
const traceId = transaction.contexts?.trace?.trace_id; | ||
expect(traceId).toBeDefined(); | ||
expect(transaction.contexts?.trace?.parent_span_id).toBeUndefined(); | ||
|
||
const trace1Id = transaction.contexts?.trace?.data?.spanIdTraceId; | ||
expect(trace1Id).toBeDefined(); | ||
|
||
// Same trace ID as the first span | ||
expect(trace1Id).toBe(traceId); | ||
}, | ||
}) | ||
.start(done); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters