Skip to content

Commit c8e9045

Browse files
committed
feat(browser): Add experimental parentlessRootSpans browserTracingIntegration option
1 parent 64e486d commit c8e9045

File tree

17 files changed

+388
-2
lines changed

17 files changed

+388
-2
lines changed

dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/interactions/test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
shouldSkipTracingTest,
88
} from '../../../../utils/helpers';
99

10-
sentryTest('should capture interaction transaction. @firefox', async ({ browserName, getLocalTestUrl, page }) => {
10+
sentryTest('captures interaction span @firefox', async ({ browserName, getLocalTestUrl, page }) => {
1111
const supportedBrowsers = ['chromium', 'firefox'];
1212

1313
if (shouldSkipTracingTest() || !supportedBrowsers.includes(browserName)) {
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
window.Sentry = Sentry;
4+
5+
Sentry.init({
6+
dsn: 'https://[email protected]/1337',
7+
integrations: [Sentry.browserTracingIntegration({ _experiments: { parentlessRootSpans: true } })],
8+
tracesSampleRate: 1,
9+
environment: 'staging',
10+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="sentry-trace" content="12312012123120121231201212312012-1121201211212012-1" />
6+
<meta
7+
name="baggage"
8+
content="sentry-release=2.1.12,sentry-public_key=public,sentry-trace_id=123,sentry-sample_rate=0.3232,sentry-sample_rand=0.42"
9+
/>
10+
</head>
11+
</html>
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { expect } from '@playwright/test';
2+
import type { Event, EventEnvelopeHeaders } from '@sentry/core';
3+
import { sentryTest } from '../../../../utils/fixtures';
4+
import {
5+
envelopeHeaderRequestParser,
6+
getFirstSentryEnvelopeRequest,
7+
shouldSkipTracingTest,
8+
} from '../../../../utils/helpers';
9+
10+
sentryTest(
11+
'creates a pageload span based on `sentry-trace` <meta> without parent span id if parentlessRootSpans is true',
12+
async ({ getLocalTestUrl, page }) => {
13+
if (shouldSkipTracingTest()) {
14+
sentryTest.skip();
15+
}
16+
17+
const url = await getLocalTestUrl({ testDir: __dirname });
18+
19+
const eventData = await getFirstSentryEnvelopeRequest<Event>(page, url);
20+
21+
expect(eventData.contexts?.trace).toMatchObject({
22+
op: 'pageload',
23+
trace_id: '12312012123120121231201212312012',
24+
});
25+
expect(eventData.contexts?.trace?.parent_span_id).toBeUndefined();
26+
27+
expect(eventData.spans?.length).toBeGreaterThan(0);
28+
},
29+
);
30+
31+
sentryTest(
32+
'picks up `baggage` <meta> tag, propagate the content in transaction and not add own data',
33+
async ({ getLocalTestUrl, page }) => {
34+
if (shouldSkipTracingTest()) {
35+
sentryTest.skip();
36+
}
37+
38+
const url = await getLocalTestUrl({ testDir: __dirname });
39+
40+
const envHeader = await getFirstSentryEnvelopeRequest<EventEnvelopeHeaders>(page, url, envelopeHeaderRequestParser);
41+
42+
expect(envHeader.trace).toBeDefined();
43+
expect(envHeader.trace).toEqual({
44+
release: '2.1.12',
45+
sample_rate: '0.3232',
46+
trace_id: '123',
47+
public_key: 'public',
48+
sample_rand: '0.42',
49+
});
50+
},
51+
);
52+
53+
sentryTest("creates a navigation that's not influenced by `sentry-trace` <meta>", async ({ getLocalTestUrl, page }) => {
54+
if (shouldSkipTracingTest()) {
55+
sentryTest.skip();
56+
}
57+
58+
const url = await getLocalTestUrl({ testDir: __dirname });
59+
60+
const pageloadRequest = await getFirstSentryEnvelopeRequest<Event>(page, url);
61+
const navigationRequest = await getFirstSentryEnvelopeRequest<Event>(page, `${url}#foo`);
62+
63+
expect(pageloadRequest.contexts?.trace).toMatchObject({
64+
op: 'pageload',
65+
trace_id: '12312012123120121231201212312012',
66+
});
67+
expect(pageloadRequest.contexts?.trace?.parent_span_id).toBeUndefined();
68+
69+
expect(navigationRequest.contexts?.trace?.op).toBe('navigation');
70+
expect(navigationRequest.contexts?.trace?.trace_id).toBeDefined();
71+
expect(navigationRequest.contexts?.trace?.trace_id).not.toBe(pageloadRequest.contexts?.trace?.trace_id);
72+
73+
const pageloadSpans = pageloadRequest.spans;
74+
const navigationSpans = navigationRequest.spans;
75+
76+
const pageloadSpanId = pageloadRequest.contexts?.trace?.span_id;
77+
const navigationSpanId = navigationRequest.contexts?.trace?.span_id;
78+
79+
expect(pageloadSpanId).toBeDefined();
80+
expect(navigationSpanId).toBeDefined();
81+
82+
pageloadSpans?.forEach(span =>
83+
expect(span).toMatchObject({
84+
parent_span_id: pageloadSpanId,
85+
}),
86+
);
87+
88+
navigationSpans?.forEach(span =>
89+
expect(span).toMatchObject({
90+
parent_span_id: navigationSpanId,
91+
}),
92+
);
93+
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
window.Sentry = Sentry;
4+
5+
Sentry.init({
6+
dsn: 'https://[email protected]/1337',
7+
integrations: integrations => {
8+
integrations.push(Sentry.browserTracingIntegration({ _experiments: { parentlessRootSpans: true } }));
9+
return integrations.filter(i => i.name !== 'BrowserSession');
10+
},
11+
tracesSampleRate: 0,
12+
});
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Sentry.captureException(new Error('test error'));
2+
Sentry.captureException(new Error('test error 2'));
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="sentry-trace" content="12312012123120121231201212312012-1121201211212012" />
6+
<meta
7+
name="baggage"
8+
content="sentry-release=2.1.12,sentry-public_key=public,sentry-trace_id=123"
9+
/>
10+
</head>
11+
</html>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { expect } from '@playwright/test';
2+
import type { Event } from '@sentry/browser';
3+
import { sentryTest } from '../../../../utils/fixtures';
4+
import { getMultipleSentryEnvelopeRequests, shouldSkipTracingTest } from '../../../../utils/helpers';
5+
6+
sentryTest('errors in TwP mode have same trace ID & span IDs', async ({ getLocalTestUrl, page }) => {
7+
if (shouldSkipTracingTest()) {
8+
sentryTest.skip();
9+
}
10+
11+
const META_TRACE_ID = '12312012123120121231201212312012';
12+
const META_PARENT_SPAN_ID = '1121201211212012';
13+
14+
const url = await getLocalTestUrl({ testDir: __dirname });
15+
const [event1, event2] = await getMultipleSentryEnvelopeRequests<Event>(page, 2, { url });
16+
17+
// Ensure these are the actual errors we care about
18+
expect(event1.exception?.values?.[0].value).toContain('test error');
19+
expect(event2.exception?.values?.[0].value).toContain('test error');
20+
21+
const contexts1 = event1.contexts;
22+
const { trace_id: traceId1, span_id: spanId1 } = contexts1?.trace || {};
23+
expect(traceId1).toEqual(META_TRACE_ID);
24+
25+
// Span ID is a virtual span in TwP mode, not the propagated one
26+
expect(spanId1).not.toEqual(META_PARENT_SPAN_ID);
27+
expect(spanId1).toMatch(/^[a-f0-9]{16}$/);
28+
29+
const contexts2 = event2.contexts;
30+
const { trace_id: traceId2, span_id: spanId2 } = contexts2?.trace || {};
31+
expect(traceId2).toEqual(META_TRACE_ID);
32+
expect(spanId2).toMatch(/^[a-f0-9]{16}$/);
33+
34+
expect(spanId2).toEqual(spanId1);
35+
});
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
window.Sentry = Sentry;
4+
5+
Sentry.init({
6+
dsn: 'https://[email protected]/1337',
7+
integrations: [
8+
Sentry.browserTracingIntegration({
9+
idleTimeout: 1000,
10+
enableLongTask: false,
11+
_experiments: {
12+
enableInteractions: true,
13+
parentlessRootSpans: true,
14+
},
15+
}),
16+
],
17+
tracesSampleRate: 1,
18+
});
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
const blockUI = e => {
2+
const startTime = Date.now();
3+
4+
function getElapsed() {
5+
const time = Date.now();
6+
return time - startTime;
7+
}
8+
9+
while (getElapsed() < 70) {
10+
//
11+
}
12+
13+
e.target.classList.add('clicked');
14+
};
15+
16+
document.querySelector('[data-test-id=interaction-button]').addEventListener('click', blockUI);
17+
document.querySelector('[data-test-id=annotated-button]').addEventListener('click', blockUI);
18+
document.querySelector('[data-test-id=styled-button]').addEventListener('click', blockUI);

0 commit comments

Comments
 (0)