Skip to content

Commit 4c741ea

Browse files
authored
Merge pull request #13988 from getsentry/prerelease/8.35.0-beta.0
meta: Prepare prelease of 8.35.0-beta.0
2 parents 5a5523e + 97aff96 commit 4c741ea

File tree

78 files changed

+1985
-476
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+1985
-476
lines changed

.github/workflows/external-contributors.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
&& github.event.pull_request.author_association != 'COLLABORATOR'
1919
&& github.event.pull_request.author_association != 'MEMBER'
2020
&& github.event.pull_request.author_association != 'OWNER'
21-
&& endsWith(github.actor, '[bot]') == false
21+
&& endsWith(github.event.pull_request.user.login, '[bot]') == false
2222
steps:
2323
- uses: actions/checkout@v4
2424
- name: Set up Node

.size-limit.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ module.exports = [
8686
path: 'packages/browser/build/npm/esm/index.js',
8787
import: createImport('init', 'browserTracingIntegration', 'replayIntegration', 'feedbackIntegration'),
8888
gzip: true,
89-
limit: '91 KB',
89+
limit: '95 KB',
9090
},
9191
{
9292
name: '@sentry/browser (incl. Tracing, Replay, Feedback, metrics)',

CHANGELOG.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,46 @@
1010

1111
- "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott
1212

13+
## 8.35.0-beta.0
14+
15+
### Important Changes
16+
17+
- **feat(core): Make stream instrumentation opt-in
18+
([#13951](https://github.com/getsentry/sentry-javascript/pull/13951))**
19+
20+
This change adds a new option `trackFetchStreamPerformance` to the browser tracing integration. Only when set to `true`,
21+
Sentry will instrument streams via fetch.
22+
23+
Work in this release was contributed by @ZakrepaShe and @zhiyan114. Thank you for your contributions!
24+
25+
### Other Changes
26+
27+
- chore(node): Bump `@opentelemetry/instrumentation-express` to `0.43.0`
28+
([#13948](https://github.com/getsentry/sentry-javascript/pull/13948))
29+
- ci: Ensure we check correctly for bot users ([#13955](https://github.com/getsentry/sentry-javascript/pull/13955))
30+
- dev(e2e): Fix nestjs version constraint ([#13964](https://github.com/getsentry/sentry-javascript/pull/13964))
31+
- feat(node): Expose `suppressTracing` API ([#13875](https://github.com/getsentry/sentry-javascript/pull/13875))
32+
- feat(node): Implement Sentry-specific http instrumentation
33+
([#13763](https://github.com/getsentry/sentry-javascript/pull/13763))
34+
- feat(nuxt): Add Rollup plugin to wrap server entry with `import()`
35+
([#13945](https://github.com/getsentry/sentry-javascript/pull/13945))
36+
- feat(replay): Do not log "timeout while trying to read resp body" as exception
37+
([#13965](https://github.com/getsentry/sentry-javascript/pull/13965))
38+
- feat(vue): Add Pinia plugin ([#13841](https://github.com/getsentry/sentry-javascript/pull/13841))
39+
- fix: Ensure type for `init` is correct in meta frameworks
40+
([#13938](https://github.com/getsentry/sentry-javascript/pull/13938))
41+
- fix(module): keep version for node ESM package ([#13922](https://github.com/getsentry/sentry-javascript/pull/13922))
42+
- fix(replay): Fix onError sampling when loading an expired buffered session
43+
([#13962](https://github.com/getsentry/sentry-javascript/pull/13962))
44+
- ref: Add external contributor to CHANGELOG.md ([#13956](https://github.com/getsentry/sentry-javascript/pull/13956))
45+
- ref: Add external contributor to CHANGELOG.md ([#13959](https://github.com/getsentry/sentry-javascript/pull/13959))
46+
- test(browser): Add test for current DSC transaction name updating behavior
47+
([#13953](https://github.com/getsentry/sentry-javascript/pull/13953))
48+
- test(loader): Update Loader Script & test error in `sentryOnLoad`
49+
([#13952](https://github.com/getsentry/sentry-javascript/pull/13952))
50+
- test(node): Add tests for current DSC transaction name updating behavior
51+
([#13961](https://github.com/getsentry/sentry-javascript/pull/13961))
52+
1353
## 8.34.0
1454

1555
### Important Changes

dev-packages/browser-integration-tests/fixtures/loader.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// we define sentryOnLoad in template
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Sentry.captureException('Test exception');
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
<script>
6+
window.sentryOnLoad = function () {
7+
Sentry.init({
8+
tracesSampleRate: 0.123,
9+
});
10+
11+
throw new Error('sentryOnLoad error');
12+
};
13+
</script>
14+
</head>
15+
<body></body>
16+
</html>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { expect } from '@playwright/test';
2+
3+
import { sentryTest } from '../../../../utils/fixtures';
4+
import { envelopeRequestParser, waitForErrorRequestOnUrl } from '../../../../utils/helpers';
5+
6+
sentryTest(
7+
'sentryOnLoad callback is called before Sentry.onLoad() and handles errors in handler',
8+
async ({ getLocalTestUrl, page }) => {
9+
const errors: string[] = [];
10+
11+
page.on('console', msg => {
12+
if (msg.type() === 'error') {
13+
errors.push(msg.text());
14+
}
15+
});
16+
17+
const url = await getLocalTestUrl({ testDir: __dirname });
18+
const req = await waitForErrorRequestOnUrl(page, url);
19+
20+
const eventData = envelopeRequestParser(req);
21+
22+
expect(eventData.message).toBe('Test exception');
23+
24+
expect(await page.evaluate('Sentry.getClient().getOptions().tracesSampleRate')).toEqual(0.123);
25+
26+
expect(errors).toEqual([
27+
'Error while calling `sentryOnLoad` handler:',
28+
expect.stringContaining('Error: sentryOnLoad error'),
29+
]);
30+
},
31+
);
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
window.Sentry = Sentry;
4+
5+
Sentry.init({
6+
dsn: 'https://public@dsn.ingest.sentry.io/1337',
7+
integrations: [Sentry.browserTracingIntegration({ instrumentNavigation: false, instrumentPageLoad: false })],
8+
tracesSampleRate: 1,
9+
tracePropagationTargets: ['example.com'],
10+
release: '1.1.1',
11+
});
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
const btnStartSpan = document.getElementById('btnStartSpan');
2+
const btnUpdateName = document.getElementById('btnUpdateName');
3+
const btnMakeRequest = document.getElementById('btnMakeRequest');
4+
const btnCaptureError = document.getElementById('btnCaptureError');
5+
const btnEndSpan = document.getElementById('btnEndSpan');
6+
7+
btnStartSpan.addEventListener('click', () => {
8+
Sentry.startSpanManual(
9+
{ name: 'test-root-span', attributes: { [Sentry.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url' } },
10+
async span => {
11+
window.__traceId = span.spanContext().traceId;
12+
await new Promise(resolve => {
13+
btnEndSpan.addEventListener('click', resolve);
14+
});
15+
span.end();
16+
},
17+
);
18+
});
19+
20+
let updateCnt = 0;
21+
btnUpdateName.addEventListener('click', () => {
22+
const span = Sentry.getActiveSpan();
23+
const rootSpan = Sentry.getRootSpan(span);
24+
rootSpan.updateName(`updated-root-span-${++updateCnt}`);
25+
rootSpan.setAttribute(Sentry.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');
26+
});
27+
28+
btnMakeRequest.addEventListener('click', () => {
29+
fetch('https://example.com/api');
30+
});
31+
32+
btnCaptureError.addEventListener('click', () => {
33+
Sentry.captureException(new Error('test-error'));
34+
});
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<button id="btnStartSpan">Start Span</button>
2+
<button id="btnUpdateName">Update Name</button>
3+
<button id="btnMakeRequest">Make Request</button>
4+
<button id="btnCaptureError">Capture Error</button>
5+
<button id="btnEndSpan">End Span</button>
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
import { expect } from '@playwright/test';
2+
import type { Page } from '@playwright/test';
3+
import type { DynamicSamplingContext } from '@sentry/types';
4+
import { sentryTest } from '../../../utils/fixtures';
5+
import type { EventAndTraceHeader } from '../../../utils/helpers';
6+
import {
7+
eventAndTraceHeaderRequestParser,
8+
getMultipleSentryEnvelopeRequests,
9+
shouldSkipTracingTest,
10+
} from '../../../utils/helpers';
11+
12+
sentryTest('updates the DSC when the txn name is updated and high-quality', async ({ getLocalTestUrl, page }) => {
13+
if (shouldSkipTracingTest()) {
14+
sentryTest.skip();
15+
}
16+
17+
const url = await getLocalTestUrl({ testDir: __dirname });
18+
19+
await page.goto(url);
20+
21+
/*
22+
Test Steps:
23+
1. Start new span with LQ txn name (source: url)
24+
2. Make request and check that baggage has no transaction name
25+
3. Capture error and check that envelope trace header has no transaction name
26+
4. Update span name and source to HQ (source: route)
27+
5. Make request and check that baggage has HQ txn name
28+
6. Capture error and check that envelope trace header has HQ txn name
29+
7. Update span name again with HQ name (source: route)
30+
8. Make request and check that baggage has updated HQ txn name
31+
9. Capture error and check that envelope trace header has updated HQ txn name
32+
10. End span and check that envelope trace header has updated HQ txn name
33+
11. Make another request and check that there's no span information in baggage
34+
12. Capture an error and check that envelope trace header has no span information
35+
*/
36+
37+
// 1
38+
await page.locator('#btnStartSpan').click();
39+
const traceId = await page.evaluate(() => {
40+
return (window as any).__traceId;
41+
});
42+
43+
expect(traceId).toMatch(/^[0-9a-f]{32}$/);
44+
45+
// 2
46+
const baggageItems = await makeRequestAndGetBaggageItems(page);
47+
expect(baggageItems).toEqual([
48+
'sentry-environment=production',
49+
'sentry-public_key=public',
50+
'sentry-release=1.1.1',
51+
'sentry-sample_rate=1',
52+
'sentry-sampled=true',
53+
`sentry-trace_id=${traceId}`,
54+
]);
55+
56+
// 3
57+
const errorEnvelopeTraceHeader = await captureErrorAndGetEnvelopeTraceHeader(page);
58+
expect(errorEnvelopeTraceHeader).toEqual({
59+
environment: 'production',
60+
public_key: 'public',
61+
release: '1.1.1',
62+
sample_rate: '1',
63+
sampled: 'true',
64+
trace_id: traceId,
65+
});
66+
67+
// 4
68+
await page.locator('#btnUpdateName').click();
69+
70+
// 5
71+
const baggageItemsAfterUpdate = await makeRequestAndGetBaggageItems(page);
72+
expect(baggageItemsAfterUpdate).toEqual([
73+
'sentry-environment=production',
74+
'sentry-public_key=public',
75+
'sentry-release=1.1.1',
76+
'sentry-sample_rate=1',
77+
'sentry-sampled=true',
78+
`sentry-trace_id=${traceId}`,
79+
'sentry-transaction=updated-root-span-1',
80+
]);
81+
82+
// 6
83+
const errorEnvelopeTraceHeaderAfterUpdate = await captureErrorAndGetEnvelopeTraceHeader(page);
84+
expect(errorEnvelopeTraceHeaderAfterUpdate).toEqual({
85+
environment: 'production',
86+
public_key: 'public',
87+
release: '1.1.1',
88+
sample_rate: '1',
89+
sampled: 'true',
90+
trace_id: traceId,
91+
transaction: 'updated-root-span-1',
92+
});
93+
94+
// 7
95+
await page.locator('#btnUpdateName').click();
96+
97+
// 8
98+
const baggageItemsAfterSecondUpdate = await makeRequestAndGetBaggageItems(page);
99+
expect(baggageItemsAfterSecondUpdate).toEqual([
100+
'sentry-environment=production',
101+
'sentry-public_key=public',
102+
'sentry-release=1.1.1',
103+
'sentry-sample_rate=1',
104+
'sentry-sampled=true',
105+
`sentry-trace_id=${traceId}`,
106+
'sentry-transaction=updated-root-span-2',
107+
]);
108+
109+
// 9
110+
const errorEnvelopeTraceHeaderAfterSecondUpdate = await captureErrorAndGetEnvelopeTraceHeader(page);
111+
expect(errorEnvelopeTraceHeaderAfterSecondUpdate).toEqual({
112+
environment: 'production',
113+
public_key: 'public',
114+
release: '1.1.1',
115+
sample_rate: '1',
116+
sampled: 'true',
117+
trace_id: traceId,
118+
transaction: 'updated-root-span-2',
119+
});
120+
121+
// 10
122+
const txnEventPromise = getMultipleSentryEnvelopeRequests<EventAndTraceHeader>(
123+
page,
124+
1,
125+
{ envelopeType: 'transaction' },
126+
eventAndTraceHeaderRequestParser,
127+
);
128+
129+
await page.locator('#btnEndSpan').click();
130+
131+
const [txnEvent, txnEnvelopeTraceHeader] = (await txnEventPromise)[0];
132+
expect(txnEnvelopeTraceHeader).toEqual({
133+
environment: 'production',
134+
public_key: 'public',
135+
release: '1.1.1',
136+
sample_rate: '1',
137+
sampled: 'true',
138+
trace_id: traceId,
139+
transaction: 'updated-root-span-2',
140+
});
141+
142+
expect(txnEvent.transaction).toEqual('updated-root-span-2');
143+
144+
// 11
145+
const baggageItemsAfterEnd = await makeRequestAndGetBaggageItems(page);
146+
expect(baggageItemsAfterEnd).toEqual([
147+
'sentry-environment=production',
148+
'sentry-public_key=public',
149+
'sentry-release=1.1.1',
150+
`sentry-trace_id=${traceId}`,
151+
]);
152+
153+
// 12
154+
const errorEnvelopeTraceHeaderAfterEnd = await captureErrorAndGetEnvelopeTraceHeader(page);
155+
expect(errorEnvelopeTraceHeaderAfterEnd).toEqual({
156+
environment: 'production',
157+
public_key: 'public',
158+
release: '1.1.1',
159+
trace_id: traceId,
160+
});
161+
});
162+
163+
async function makeRequestAndGetBaggageItems(page: Page): Promise<string[]> {
164+
const requestPromise = page.waitForRequest('https://example.com/*');
165+
await page.locator('#btnMakeRequest').click();
166+
const request = await requestPromise;
167+
168+
const baggage = await request.headerValue('baggage');
169+
170+
return baggage?.split(',').sort() ?? [];
171+
}
172+
173+
async function captureErrorAndGetEnvelopeTraceHeader(page: Page): Promise<DynamicSamplingContext | undefined> {
174+
const errorEventPromise = getMultipleSentryEnvelopeRequests<EventAndTraceHeader>(
175+
page,
176+
1,
177+
{ envelopeType: 'event' },
178+
eventAndTraceHeaderRequestParser,
179+
);
180+
181+
await page.locator('#btnCaptureError').click();
182+
183+
const [, errorEnvelopeTraceHeader] = (await errorEventPromise)[0];
184+
return errorEnvelopeTraceHeader;
185+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
const errorBtn = document.getElementById('errorBtn');
2+
errorBtn.addEventListener('click', () => {
3+
throw new Error(`Sentry Test Error ${Math.random()}`);
4+
});
5+
6+
const fetchBtn = document.getElementById('fetchBtn');
7+
fetchBtn.addEventListener('click', async () => {
8+
await fetch('http://example.com');
9+
});
10+
11+
const xhrBtn = document.getElementById('xhrBtn');
12+
xhrBtn.addEventListener('click', () => {
13+
const xhr = new XMLHttpRequest();
14+
xhr.open('GET', 'http://example.com');
15+
xhr.send();
16+
});

0 commit comments

Comments
 (0)