Skip to content

Commit 98cc6e3

Browse files
authored
Merge pull request #17020 from getsentry/prepare-release/9.39.0
meta(changelog): Update changelog for 9.39.0
2 parents abcc0e0 + fb80b36 commit 98cc6e3

File tree

205 files changed

+4445
-1194
lines changed

Some content is hidden

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

205 files changed

+4445
-1194
lines changed

.craft.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,8 @@ targets:
207207
onlyIfPresent: /^sentry-nuxt-\d.*\.tgz$/
208208
'npm:@sentry/node':
209209
onlyIfPresent: /^sentry-node-\d.*\.tgz$/
210+
'npm:@sentry/node-core':
211+
onlyIfPresent: /^sentry-node-core-\d.*\.tgz$/
210212
'npm:@sentry/react':
211213
onlyIfPresent: /^sentry-react-\d.*\.tgz$/
212214
'npm:@sentry/react-router':

CHANGELOG.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,39 @@
44

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

7+
## 9.39.0
8+
9+
### Important Changes
10+
11+
- **feat(browser): Add `afterStartPageloadSpan` hook to improve spanId assignment on web vital spans ([#16893](https://github.com/getsentry/sentry-javascript/pull/16893))**
12+
13+
This PR adds a new afterStartPageloadSpan lifecycle hook to more robustly assign the correct pageload span ID to web vital spans, replacing the previous unreliable "wait for a tick" approach with a direct callback that fires when the pageload span becomes available.
14+
15+
- **feat(nextjs): Client-side parameterized routes ([#16934](https://github.com/getsentry/sentry-javascript/pull/16934))**
16+
17+
This PR implements client-side parameterized routes for Next.js by leveraging an injected manifest within the existing app-router instrumentation to automatically parameterize all client-side transactions (e.g. `users/123` and `users/456` now become become `users/:id`).
18+
19+
- **feat(node): Drop 401-404 and 3xx status code spans by default ([#16972](https://github.com/getsentry/sentry-javascript/pull/16972))**
20+
21+
This PR changes the default behavior in the Node SDK to drop HTTP spans with 401-404 and 3xx status codes by default to reduce noise in tracing data.
22+
23+
### Other Changes
24+
25+
- feat(core): Prepend vercel ai attributes with `vercel.ai.X` ([#16908](https://github.com/getsentry/sentry-javascript/pull/16908))
26+
- feat(nextjs): Add `disableSentryWebpackConfig` flag ([#17013](https://github.com/getsentry/sentry-javascript/pull/17013))
27+
- feat(nextjs): Build app manifest ([#16851](https://github.com/getsentry/sentry-javascript/pull/16851))
28+
- feat(nextjs): Inject manifest into client for turbopack builds ([#16902](https://github.com/getsentry/sentry-javascript/pull/16902))
29+
- feat(nextjs): Inject manifest into client for webpack builds ([#16857](https://github.com/getsentry/sentry-javascript/pull/16857))
30+
- feat(node-native): Add option to disable event loop blocked detection ([#16919](https://github.com/getsentry/sentry-javascript/pull/16919))
31+
- feat(react-router): Ensure http.server route handling is consistent ([#16986](https://github.com/getsentry/sentry-javascript/pull/16986))
32+
- fix(core): Avoid prolonging idle span when starting standalone span ([#16928](https://github.com/getsentry/sentry-javascript/pull/16928))
33+
- fix(core): Remove side-effect from `tracing/errors.ts` ([#16888](https://github.com/getsentry/sentry-javascript/pull/16888))
34+
- fix(core): Wrap `beforeSendLog` in `consoleSandbox` ([#16968](https://github.com/getsentry/sentry-javascript/pull/16968))
35+
- fix(node-core): Apply correct SDK metadata ([#17014](https://github.com/getsentry/sentry-javascript/pull/17014))
36+
- fix(react-router): Ensure that all browser spans have `source=route` ([#16984](https://github.com/getsentry/sentry-javascript/pull/16984))
37+
38+
Work in this release was contributed by @janpapenbrock. Thank you for your contribution!
39+
740
## 9.38.0
841

942
### Important Changes

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ sentryTest('should output logger messages', async ({ getLocalTestUrl, page }) =>
2121
await Promise.all([page.goto(url), reqPromise0]);
2222

2323
expect(messages).toContain('Sentry Logger [log]: Integration installed: Replay');
24-
expect(messages).toContain('Sentry Logger [info]: [Replay] Creating new session');
25-
expect(messages).toContain('Sentry Logger [info]: [Replay] Starting replay in session mode');
26-
expect(messages).toContain('Sentry Logger [info]: [Replay] Using compression worker');
24+
expect(messages).toContain('Sentry Logger [log]: [Replay] Creating new session');
25+
expect(messages).toContain('Sentry Logger [log]: [Replay] Starting replay in session mode');
26+
expect(messages).toContain('Sentry Logger [log]: [Replay] Using compression worker');
2727
});

dev-packages/e2e-tests/run.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,10 @@ async function run(): Promise<void> {
8484
const cwd = tmpDirPath;
8585

8686
console.log(`Building ${testAppPath} in ${tmpDirPath}...`);
87-
await asyncExec('pnpm test:build', { env, cwd });
87+
await asyncExec('volta run pnpm test:build', { env, cwd });
8888

8989
console.log(`Testing ${testAppPath}...`);
90-
await asyncExec('pnpm test:assert', { env, cwd });
90+
await asyncExec('volta run pnpm test:assert', { env, cwd });
9191

9292
// clean up (although this is tmp, still nice to do)
9393
await rm(tmpDirPath, { recursive: true });
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function ParameterizedPage() {
2+
return <div>Dynamic page two</div>;
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function BeepPage() {
2+
return <div>Beep</div>;
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function ParameterizedPage() {
2+
return <div>Dynamic page one</div>;
3+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default function StaticPage() {
2+
return (
3+
<div>
4+
Static page
5+
</div>
6+
);
7+
}
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
import { expect, test } from '@playwright/test';
2+
import { waitForTransaction } from '@sentry-internal/test-utils';
3+
4+
test('should create a parameterized transaction when the `app` directory is used', async ({ page }) => {
5+
const transactionPromise = waitForTransaction('nextjs-13', async transactionEvent => {
6+
return (
7+
transactionEvent.transaction === '/parameterized/:one' && transactionEvent.contexts?.trace?.op === 'pageload'
8+
);
9+
});
10+
11+
await page.goto(`/parameterized/cappuccino`);
12+
13+
const transaction = await transactionPromise;
14+
15+
expect(transaction).toMatchObject({
16+
breadcrumbs: expect.arrayContaining([
17+
{
18+
category: 'navigation',
19+
data: { from: '/parameterized/cappuccino', to: '/parameterized/cappuccino' },
20+
timestamp: expect.any(Number),
21+
},
22+
]),
23+
contexts: {
24+
react: { version: expect.any(String) },
25+
trace: {
26+
data: {
27+
'sentry.op': 'pageload',
28+
'sentry.origin': 'auto.pageload.nextjs.app_router_instrumentation',
29+
'sentry.source': 'route',
30+
},
31+
op: 'pageload',
32+
origin: 'auto.pageload.nextjs.app_router_instrumentation',
33+
span_id: expect.stringMatching(/[a-f0-9]{16}/),
34+
trace_id: expect.stringMatching(/[a-f0-9]{32}/),
35+
},
36+
},
37+
environment: 'qa',
38+
request: {
39+
headers: expect.any(Object),
40+
url: expect.stringMatching(/\/parameterized\/cappuccino$/),
41+
},
42+
start_timestamp: expect.any(Number),
43+
timestamp: expect.any(Number),
44+
transaction: '/parameterized/:one',
45+
transaction_info: { source: 'route' },
46+
type: 'transaction',
47+
});
48+
});
49+
50+
test('should create a static transaction when the `app` directory is used and the route is not parameterized', async ({
51+
page,
52+
}) => {
53+
const transactionPromise = waitForTransaction('nextjs-13', async transactionEvent => {
54+
return (
55+
transactionEvent.transaction === '/parameterized/static' && transactionEvent.contexts?.trace?.op === 'pageload'
56+
);
57+
});
58+
59+
await page.goto(`/parameterized/static`);
60+
61+
const transaction = await transactionPromise;
62+
63+
expect(transaction).toMatchObject({
64+
breadcrumbs: expect.arrayContaining([
65+
{
66+
category: 'navigation',
67+
data: { from: '/parameterized/static', to: '/parameterized/static' },
68+
timestamp: expect.any(Number),
69+
},
70+
]),
71+
contexts: {
72+
react: { version: expect.any(String) },
73+
trace: {
74+
data: {
75+
'sentry.op': 'pageload',
76+
'sentry.origin': 'auto.pageload.nextjs.app_router_instrumentation',
77+
'sentry.source': 'url',
78+
},
79+
op: 'pageload',
80+
origin: 'auto.pageload.nextjs.app_router_instrumentation',
81+
span_id: expect.stringMatching(/[a-f0-9]{16}/),
82+
trace_id: expect.stringMatching(/[a-f0-9]{32}/),
83+
},
84+
},
85+
environment: 'qa',
86+
request: {
87+
headers: expect.any(Object),
88+
url: expect.stringMatching(/\/parameterized\/static$/),
89+
},
90+
start_timestamp: expect.any(Number),
91+
timestamp: expect.any(Number),
92+
transaction: '/parameterized/static',
93+
transaction_info: { source: 'url' },
94+
type: 'transaction',
95+
});
96+
});
97+
98+
test('should create a partially parameterized transaction when the `app` directory is used', async ({ page }) => {
99+
const transactionPromise = waitForTransaction('nextjs-13', async transactionEvent => {
100+
return (
101+
transactionEvent.transaction === '/parameterized/:one/beep' && transactionEvent.contexts?.trace?.op === 'pageload'
102+
);
103+
});
104+
105+
await page.goto(`/parameterized/cappuccino/beep`);
106+
107+
const transaction = await transactionPromise;
108+
109+
expect(transaction).toMatchObject({
110+
breadcrumbs: expect.arrayContaining([
111+
{
112+
category: 'navigation',
113+
data: { from: '/parameterized/cappuccino/beep', to: '/parameterized/cappuccino/beep' },
114+
timestamp: expect.any(Number),
115+
},
116+
]),
117+
contexts: {
118+
react: { version: expect.any(String) },
119+
trace: {
120+
data: {
121+
'sentry.op': 'pageload',
122+
'sentry.origin': 'auto.pageload.nextjs.app_router_instrumentation',
123+
'sentry.source': 'route',
124+
},
125+
op: 'pageload',
126+
origin: 'auto.pageload.nextjs.app_router_instrumentation',
127+
span_id: expect.stringMatching(/[a-f0-9]{16}/),
128+
trace_id: expect.stringMatching(/[a-f0-9]{32}/),
129+
},
130+
},
131+
environment: 'qa',
132+
request: {
133+
headers: expect.any(Object),
134+
url: expect.stringMatching(/\/parameterized\/cappuccino\/beep$/),
135+
},
136+
start_timestamp: expect.any(Number),
137+
timestamp: expect.any(Number),
138+
transaction: '/parameterized/:one/beep',
139+
transaction_info: { source: 'route' },
140+
type: 'transaction',
141+
});
142+
});
143+
144+
test('should create a nested parameterized transaction when the `app` directory is used', async ({ page }) => {
145+
const transactionPromise = waitForTransaction('nextjs-13', async transactionEvent => {
146+
return (
147+
transactionEvent.transaction === '/parameterized/:one/beep/:two' &&
148+
transactionEvent.contexts?.trace?.op === 'pageload'
149+
);
150+
});
151+
152+
await page.goto(`/parameterized/cappuccino/beep/espresso`);
153+
154+
const transaction = await transactionPromise;
155+
156+
expect(transaction).toMatchObject({
157+
breadcrumbs: expect.arrayContaining([
158+
{
159+
category: 'navigation',
160+
data: { from: '/parameterized/cappuccino/beep/espresso', to: '/parameterized/cappuccino/beep/espresso' },
161+
timestamp: expect.any(Number),
162+
},
163+
]),
164+
contexts: {
165+
react: { version: expect.any(String) },
166+
trace: {
167+
data: {
168+
'sentry.op': 'pageload',
169+
'sentry.origin': 'auto.pageload.nextjs.app_router_instrumentation',
170+
'sentry.source': 'route',
171+
},
172+
op: 'pageload',
173+
origin: 'auto.pageload.nextjs.app_router_instrumentation',
174+
span_id: expect.stringMatching(/[a-f0-9]{16}/),
175+
trace_id: expect.stringMatching(/[a-f0-9]{32}/),
176+
},
177+
},
178+
environment: 'qa',
179+
request: {
180+
headers: expect.any(Object),
181+
url: expect.stringMatching(/\/parameterized\/cappuccino\/beep\/espresso$/),
182+
},
183+
start_timestamp: expect.any(Number),
184+
timestamp: expect.any(Number),
185+
transaction: '/parameterized/:one/beep/:two',
186+
transaction_info: { source: 'route' },
187+
type: 'transaction',
188+
});
189+
});

dev-packages/e2e-tests/test-applications/nextjs-14/app/generation-functions/with-redirect/page.tsx

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)