Skip to content

Commit dcb208a

Browse files
authored
Merge branch 'develop' into instrument-genai-google-stream
2 parents b9446de + 0e0c711 commit dcb208a

File tree

34 files changed

+719
-514
lines changed

34 files changed

+719
-514
lines changed

dev-packages/browser-integration-tests/suites/public-api/logger/integration/subject.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,12 @@ console.log('Mixed:', 'prefix', { obj: true }, [4, 5, 6], 'suffix');
1313

1414
console.log('');
1515

16+
// Test console substitution patterns (should NOT generate template attributes)
17+
console.log('String substitution %s %d', 'test', 42);
18+
console.log('Object substitution %o', { key: 'value' });
19+
20+
// Test multiple arguments without substitutions (should generate template attributes)
21+
console.log('first', 0, 1, 2);
22+
console.log('hello', true, null, undefined);
23+
1624
Sentry.flush();

dev-packages/browser-integration-tests/suites/public-api/logger/integration/test.ts

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ sentryTest('should capture console object calls', async ({ getLocalTestUrl, page
1818
expect(envelopeItems[0]).toEqual([
1919
{
2020
type: 'log',
21-
item_count: 11,
21+
item_count: 15,
2222
content_type: 'application/vnd.sentry.items.log+json',
2323
},
2424
{
@@ -33,6 +33,9 @@ sentryTest('should capture console object calls', async ({ getLocalTestUrl, page
3333
'sentry.origin': { value: 'auto.console.logging', type: 'string' },
3434
'sentry.sdk.name': { value: 'sentry.javascript.browser', type: 'string' },
3535
'sentry.sdk.version': { value: expect.any(String), type: 'string' },
36+
'sentry.message.template': { value: 'console.trace {} {}', type: 'string' },
37+
'sentry.message.parameter.0': { value: 123, type: 'integer' },
38+
'sentry.message.parameter.1': { value: false, type: 'boolean' },
3639
},
3740
},
3841
{
@@ -45,6 +48,9 @@ sentryTest('should capture console object calls', async ({ getLocalTestUrl, page
4548
'sentry.origin': { value: 'auto.console.logging', type: 'string' },
4649
'sentry.sdk.name': { value: 'sentry.javascript.browser', type: 'string' },
4750
'sentry.sdk.version': { value: expect.any(String), type: 'string' },
51+
'sentry.message.template': { value: 'console.debug {} {}', type: 'string' },
52+
'sentry.message.parameter.0': { value: 123, type: 'integer' },
53+
'sentry.message.parameter.1': { value: false, type: 'boolean' },
4854
},
4955
},
5056
{
@@ -57,6 +63,9 @@ sentryTest('should capture console object calls', async ({ getLocalTestUrl, page
5763
'sentry.origin': { value: 'auto.console.logging', type: 'string' },
5864
'sentry.sdk.name': { value: 'sentry.javascript.browser', type: 'string' },
5965
'sentry.sdk.version': { value: expect.any(String), type: 'string' },
66+
'sentry.message.template': { value: 'console.log {} {}', type: 'string' },
67+
'sentry.message.parameter.0': { value: 123, type: 'integer' },
68+
'sentry.message.parameter.1': { value: false, type: 'boolean' },
6069
},
6170
},
6271
{
@@ -69,6 +78,9 @@ sentryTest('should capture console object calls', async ({ getLocalTestUrl, page
6978
'sentry.origin': { value: 'auto.console.logging', type: 'string' },
7079
'sentry.sdk.name': { value: 'sentry.javascript.browser', type: 'string' },
7180
'sentry.sdk.version': { value: expect.any(String), type: 'string' },
81+
'sentry.message.template': { value: 'console.info {} {}', type: 'string' },
82+
'sentry.message.parameter.0': { value: 123, type: 'integer' },
83+
'sentry.message.parameter.1': { value: false, type: 'boolean' },
7284
},
7385
},
7486
{
@@ -81,6 +93,9 @@ sentryTest('should capture console object calls', async ({ getLocalTestUrl, page
8193
'sentry.origin': { value: 'auto.console.logging', type: 'string' },
8294
'sentry.sdk.name': { value: 'sentry.javascript.browser', type: 'string' },
8395
'sentry.sdk.version': { value: expect.any(String), type: 'string' },
96+
'sentry.message.template': { value: 'console.warn {} {}', type: 'string' },
97+
'sentry.message.parameter.0': { value: 123, type: 'integer' },
98+
'sentry.message.parameter.1': { value: false, type: 'boolean' },
8499
},
85100
},
86101
{
@@ -93,6 +108,9 @@ sentryTest('should capture console object calls', async ({ getLocalTestUrl, page
93108
'sentry.origin': { value: 'auto.console.logging', type: 'string' },
94109
'sentry.sdk.name': { value: 'sentry.javascript.browser', type: 'string' },
95110
'sentry.sdk.version': { value: expect.any(String), type: 'string' },
111+
'sentry.message.template': { value: 'console.error {} {}', type: 'string' },
112+
'sentry.message.parameter.0': { value: 123, type: 'integer' },
113+
'sentry.message.parameter.1': { value: false, type: 'boolean' },
96114
},
97115
},
98116
{
@@ -117,6 +135,8 @@ sentryTest('should capture console object calls', async ({ getLocalTestUrl, page
117135
'sentry.origin': { value: 'auto.console.logging', type: 'string' },
118136
'sentry.sdk.name': { value: 'sentry.javascript.browser', type: 'string' },
119137
'sentry.sdk.version': { value: expect.any(String), type: 'string' },
138+
'sentry.message.template': { value: 'Object: {}', type: 'string' },
139+
'sentry.message.parameter.0': { value: '{"key":"value","nested":{"prop":123}}', type: 'string' },
120140
},
121141
},
122142
{
@@ -129,6 +149,8 @@ sentryTest('should capture console object calls', async ({ getLocalTestUrl, page
129149
'sentry.origin': { value: 'auto.console.logging', type: 'string' },
130150
'sentry.sdk.name': { value: 'sentry.javascript.browser', type: 'string' },
131151
'sentry.sdk.version': { value: expect.any(String), type: 'string' },
152+
'sentry.message.template': { value: 'Array: {}', type: 'string' },
153+
'sentry.message.parameter.0': { value: '[1,2,3,"string"]', type: 'string' },
132154
},
133155
},
134156
{
@@ -141,6 +163,11 @@ sentryTest('should capture console object calls', async ({ getLocalTestUrl, page
141163
'sentry.origin': { value: 'auto.console.logging', type: 'string' },
142164
'sentry.sdk.name': { value: 'sentry.javascript.browser', type: 'string' },
143165
'sentry.sdk.version': { value: expect.any(String), type: 'string' },
166+
'sentry.message.template': { value: 'Mixed: {} {} {} {}', type: 'string' },
167+
'sentry.message.parameter.0': { value: 'prefix', type: 'string' },
168+
'sentry.message.parameter.1': { value: '{"obj":true}', type: 'string' },
169+
'sentry.message.parameter.2': { value: '[4,5,6]', type: 'string' },
170+
'sentry.message.parameter.3': { value: 'suffix', type: 'string' },
144171
},
145172
},
146173
{
@@ -155,6 +182,62 @@ sentryTest('should capture console object calls', async ({ getLocalTestUrl, page
155182
'sentry.sdk.version': { value: expect.any(String), type: 'string' },
156183
},
157184
},
185+
{
186+
timestamp: expect.any(Number),
187+
level: 'info',
188+
severity_number: 10,
189+
trace_id: expect.any(String),
190+
body: 'String substitution %s %d test 42',
191+
attributes: {
192+
'sentry.origin': { value: 'auto.console.logging', type: 'string' },
193+
'sentry.sdk.name': { value: 'sentry.javascript.browser', type: 'string' },
194+
'sentry.sdk.version': { value: expect.any(String), type: 'string' },
195+
},
196+
},
197+
{
198+
timestamp: expect.any(Number),
199+
level: 'info',
200+
severity_number: 10,
201+
trace_id: expect.any(String),
202+
body: 'Object substitution %o {"key":"value"}',
203+
attributes: {
204+
'sentry.origin': { value: 'auto.console.logging', type: 'string' },
205+
'sentry.sdk.name': { value: 'sentry.javascript.browser', type: 'string' },
206+
'sentry.sdk.version': { value: expect.any(String), type: 'string' },
207+
},
208+
},
209+
{
210+
timestamp: expect.any(Number),
211+
level: 'info',
212+
severity_number: 10,
213+
trace_id: expect.any(String),
214+
body: 'first 0 1 2',
215+
attributes: {
216+
'sentry.origin': { value: 'auto.console.logging', type: 'string' },
217+
'sentry.sdk.name': { value: 'sentry.javascript.browser', type: 'string' },
218+
'sentry.sdk.version': { value: expect.any(String), type: 'string' },
219+
'sentry.message.template': { value: 'first {} {} {}', type: 'string' },
220+
'sentry.message.parameter.0': { value: 0, type: 'integer' },
221+
'sentry.message.parameter.1': { value: 1, type: 'integer' },
222+
'sentry.message.parameter.2': { value: 2, type: 'integer' },
223+
},
224+
},
225+
{
226+
timestamp: expect.any(Number),
227+
level: 'info',
228+
severity_number: 10,
229+
trace_id: expect.any(String),
230+
body: 'hello true null undefined',
231+
attributes: {
232+
'sentry.origin': { value: 'auto.console.logging', type: 'string' },
233+
'sentry.sdk.name': { value: 'sentry.javascript.browser', type: 'string' },
234+
'sentry.sdk.version': { value: expect.any(String), type: 'string' },
235+
'sentry.message.template': { value: 'hello {} {} {}', type: 'string' },
236+
'sentry.message.parameter.0': { value: true, type: 'boolean' },
237+
'sentry.message.parameter.1': { value: 'null', type: 'string' },
238+
'sentry.message.parameter.2': { value: '', type: 'string' },
239+
},
240+
},
158241
],
159242
},
160243
]);
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
window.Sentry = Sentry;
4+
window._testBaseTimestamp = performance.timeOrigin / 1000;
5+
6+
Sentry.init({
7+
dsn: 'https://[email protected]/1337',
8+
integrations: [Sentry.browserTracingIntegration({ enableReportPageLoaded: true })],
9+
tracesSampleRate: 1,
10+
debug: true,
11+
});
12+
13+
setTimeout(() => {
14+
Sentry.reportPageLoaded();
15+
}, 2500);
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { expect } from '@playwright/test';
2+
import {
3+
SEMANTIC_ATTRIBUTE_SENTRY_OP,
4+
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
5+
SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE,
6+
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
7+
} from '@sentry/browser';
8+
import { sentryTest } from '../../../../../utils/fixtures';
9+
import { envelopeRequestParser, shouldSkipTracingTest, waitForTransactionRequest } from '../../../../../utils/helpers';
10+
11+
sentryTest(
12+
'waits for Sentry.reportPageLoaded() to be called when `enableReportPageLoaded` is true',
13+
async ({ getLocalTestUrl, page }) => {
14+
if (shouldSkipTracingTest()) {
15+
sentryTest.skip();
16+
}
17+
18+
const pageloadEventPromise = waitForTransactionRequest(page, event => event.contexts?.trace?.op === 'pageload');
19+
20+
const url = await getLocalTestUrl({ testDir: __dirname });
21+
22+
await page.goto(url);
23+
24+
const eventData = envelopeRequestParser(await pageloadEventPromise);
25+
26+
const traceContextData = eventData.contexts?.trace?.data;
27+
const spanDurationSeconds = eventData.timestamp! - eventData.start_timestamp!;
28+
29+
expect(traceContextData).toMatchObject({
30+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.pageload.browser',
31+
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: 1,
32+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
33+
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'pageload',
34+
['sentry.idle_span_finish_reason']: 'reportPageLoaded',
35+
});
36+
37+
// We wait for 2.5 seconds before calling Sentry.reportPageLoaded()
38+
// the margins are to account for timing weirdness in CI to avoid flakes
39+
expect(spanDurationSeconds).toBeGreaterThan(2);
40+
expect(spanDurationSeconds).toBeLessThan(3);
41+
},
42+
);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
window.Sentry = Sentry;
4+
window._testBaseTimestamp = performance.timeOrigin / 1000;
5+
6+
Sentry.init({
7+
dsn: 'https://[email protected]/1337',
8+
integrations: [Sentry.browserTracingIntegration({ enableReportPageLoaded: true, finalTimeout: 3000 })],
9+
tracesSampleRate: 1,
10+
debug: true,
11+
});
12+
13+
// not calling Sentry.reportPageLoaded() on purpose!
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { expect } from '@playwright/test';
2+
import {
3+
SEMANTIC_ATTRIBUTE_SENTRY_OP,
4+
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
5+
SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE,
6+
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
7+
} from '@sentry/browser';
8+
import { sentryTest } from '../../../../../utils/fixtures';
9+
import { envelopeRequestParser, shouldSkipTracingTest, waitForTransactionRequest } from '../../../../../utils/helpers';
10+
11+
sentryTest(
12+
'final timeout cancels the pageload span even if `enableReportPageLoaded` is true',
13+
async ({ getLocalTestUrl, page }) => {
14+
if (shouldSkipTracingTest()) {
15+
sentryTest.skip();
16+
}
17+
18+
const pageloadEventPromise = waitForTransactionRequest(page, event => event.contexts?.trace?.op === 'pageload');
19+
20+
const url = await getLocalTestUrl({ testDir: __dirname });
21+
22+
await page.goto(url);
23+
24+
const eventData = envelopeRequestParser(await pageloadEventPromise);
25+
26+
const traceContextData = eventData.contexts?.trace?.data;
27+
const spanDurationSeconds = eventData.timestamp! - eventData.start_timestamp!;
28+
29+
expect(traceContextData).toMatchObject({
30+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.pageload.browser',
31+
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: 1,
32+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
33+
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'pageload',
34+
['sentry.idle_span_finish_reason']: 'finalTimeout',
35+
});
36+
37+
// We wait for 3 seconds before calling Sentry.reportPageLoaded()
38+
// the margins are to account for timing weirdness in CI to avoid flakes
39+
expect(spanDurationSeconds).toBeGreaterThan(2.5);
40+
expect(spanDurationSeconds).toBeLessThan(3.5);
41+
},
42+
);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
window.Sentry = Sentry;
4+
window._testBaseTimestamp = performance.timeOrigin / 1000;
5+
6+
Sentry.init({
7+
dsn: 'https://[email protected]/1337',
8+
integrations: [Sentry.browserTracingIntegration({ enableReportPageLoaded: true, instrumentNavigation: false })],
9+
tracesSampleRate: 1,
10+
debug: true,
11+
});
12+
13+
setTimeout(() => {
14+
Sentry.startBrowserTracingNavigationSpan(Sentry.getClient(), { name: 'custom_navigation' });
15+
}, 1000);
16+
17+
setTimeout(() => {
18+
Sentry.reportPageLoaded();
19+
}, 2500);
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { expect } from '@playwright/test';
2+
import {
3+
SEMANTIC_ATTRIBUTE_SENTRY_OP,
4+
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
5+
SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE,
6+
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
7+
} from '@sentry/browser';
8+
import { sentryTest } from '../../../../../utils/fixtures';
9+
import { envelopeRequestParser, shouldSkipTracingTest, waitForTransactionRequest } from '../../../../../utils/helpers';
10+
11+
sentryTest(
12+
'starting a navigation span cancels the pageload span even if `enableReportPageLoaded` is true',
13+
async ({ getLocalTestUrl, page }) => {
14+
if (shouldSkipTracingTest()) {
15+
sentryTest.skip();
16+
}
17+
18+
const pageloadEventPromise = waitForTransactionRequest(page, event => event.contexts?.trace?.op === 'pageload');
19+
20+
const url = await getLocalTestUrl({ testDir: __dirname });
21+
22+
await page.goto(url);
23+
24+
const eventData = envelopeRequestParser(await pageloadEventPromise);
25+
26+
const traceContextData = eventData.contexts?.trace?.data;
27+
const spanDurationSeconds = eventData.timestamp! - eventData.start_timestamp!;
28+
29+
expect(traceContextData).toMatchObject({
30+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.pageload.browser',
31+
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: 1,
32+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
33+
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'pageload',
34+
['sentry.idle_span_finish_reason']: 'cancelled',
35+
});
36+
37+
// ending span after 1s but adding a margin of 0.5s to account for timing weirdness in CI to avoid flakes
38+
expect(spanDurationSeconds).toBeLessThan(1.5);
39+
},
40+
);

packages/browser/src/index.bundle.tracing.replay.feedback.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ export {
2323
startBrowserTracingPageLoadSpan,
2424
} from './tracing/browserTracingIntegration';
2525

26+
export { reportPageLoaded } from './tracing/reportPageLoaded';
27+
2628
export { getFeedback, sendFeedback } from '@sentry-internal/feedback';
2729

2830
export { feedbackAsyncIntegration as feedbackAsyncIntegration, feedbackAsyncIntegration as feedbackIntegration };

packages/browser/src/index.bundle.tracing.replay.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ export {
2222
startBrowserTracingNavigationSpan,
2323
startBrowserTracingPageLoadSpan,
2424
} from './tracing/browserTracingIntegration';
25+
26+
export { reportPageLoaded } from './tracing/reportPageLoaded';
27+
2528
export { feedbackIntegrationShim as feedbackAsyncIntegration, feedbackIntegrationShim as feedbackIntegration };
2629

2730
export { replayIntegration, getReplay } from '@sentry-internal/replay';

0 commit comments

Comments
 (0)