Skip to content

Commit 27a47f2

Browse files
authored
Merge pull request #12236 from getsentry/prepare-release/8.5.0
meta: Add CHANGELOG entry for `8.5.0`
2 parents 672cdd7 + f32f88d commit 27a47f2

File tree

147 files changed

+3027
-714
lines changed

Some content is hidden

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

147 files changed

+3027
-714
lines changed

Diff for: .github/workflows/build.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -436,8 +436,6 @@ jobs:
436436
env:
437437
DEPENDENCY_CACHE_KEY: ${{ needs.job_build.outputs.dependency_cache_key }}
438438
- name: Run tests
439-
env:
440-
NODE_VERSION: 16
441439
run: yarn test-ci-browser
442440
- name: Compute test coverage
443441
uses: codecov/codecov-action@v4
@@ -1005,7 +1003,9 @@ jobs:
10051003
'create-remix-app-express-vite-dev',
10061004
'debug-id-sourcemaps',
10071005
'node-express-esm-loader',
1006+
'node-express-esm-preload',
10081007
'node-express-esm-without-loader',
1008+
'node-express-cjs-preload',
10091009
'nextjs-app-dir',
10101010
'nextjs-14',
10111011
'nextjs-15',

Diff for: .github/workflows/canary.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,8 @@ jobs:
159159
strategy:
160160
fail-fast: false
161161
matrix:
162-
scenario: [ember-release, embroider-optimized, ember-4.0]
162+
# scenario: [ember-release, embroider-optimized, ember-4.0]
163+
scenario: [ember-4.0]
163164
steps:
164165
- name: 'Check out current commit'
165166
uses: actions/checkout@v4

Diff for: .size-limit.js

+16
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,20 @@ module.exports = [
5757
gzip: true,
5858
limit: '87 KB',
5959
},
60+
{
61+
name: '@sentry/browser (incl. Tracing, Replay, Feedback, metrics)',
62+
path: 'packages/browser/build/npm/esm/index.js',
63+
import: createImport('init', 'browserTracingIntegration', 'replayIntegration', 'feedbackIntegration', 'metrics'),
64+
gzip: true,
65+
limit: '100 KB',
66+
},
67+
{
68+
name: '@sentry/browser (incl. metrics)',
69+
path: 'packages/browser/build/npm/esm/index.js',
70+
import: createImport('init', 'metrics'),
71+
gzip: true,
72+
limit: '40 KB',
73+
},
6074
{
6175
name: '@sentry/browser (incl. Feedback)',
6276
path: 'packages/browser/build/npm/esm/index.js',
@@ -83,13 +97,15 @@ module.exports = [
8397
name: '@sentry/react',
8498
path: 'packages/react/build/esm/index.js',
8599
import: createImport('init', 'ErrorBoundary'),
100+
ignore: ['react/jsx-runtime'],
86101
gzip: true,
87102
limit: '27 KB',
88103
},
89104
{
90105
name: '@sentry/react (incl. Tracing)',
91106
path: 'packages/react/build/esm/index.js',
92107
import: createImport('init', 'ErrorBoundary', 'reactRouterV6BrowserTracingIntegration'),
108+
ignore: ['react/jsx-runtime'],
93109
gzip: true,
94110
limit: '37 KB',
95111
},

Diff for: CHANGELOG.md

+53
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,59 @@
44

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

7+
## 8.5.0
8+
9+
### Important Changes
10+
11+
- **feat(react): Add React 19 to peer deps (#12207)**
12+
13+
This release adds support for React 19 in the `@sentry/react` SDK package.
14+
15+
- **feat(node): Add `@sentry/node/preload` hook (#12213)**
16+
17+
This release adds a new way to initialize `@sentry/node`, which allows you to use the SDK with performance
18+
instrumentation even if you cannot call `Sentry.init()` at the very start of your app.
19+
20+
First, run the SDK like this:
21+
22+
```bash
23+
node --require @sentry/node/preload ./app.js
24+
```
25+
26+
Now, you can initialize and import the rest of the SDK later or asynchronously:
27+
28+
```js
29+
const express = require('express');
30+
const Sentry = require('@sentry/node');
31+
32+
const dsn = await getSentryDsn();
33+
Sentry.init({ dsn });
34+
```
35+
36+
For more details, head over to the
37+
[PR Description of the new feature](https://github.com/getsentry/sentry-javascript/pull/12213). Our docs will be updated
38+
soon with a new guide.
39+
40+
### Other Changes
41+
42+
- feat(browser): Do not include metrics in base CDN bundle (#12230)
43+
- feat(core): Add `startNewTrace` API (#12138)
44+
- feat(core): Allow to pass custom scope to `captureFeedback()` (#12216)
45+
- feat(core): Only allow `SerializedSession` in session envelope items (#11979)
46+
- feat(nextjs): Use Vercel's `waitUntil` to defer freezing of Vercel Lambdas (#12133)
47+
- feat(node): Ensure manual OTEL setup works (#12214)
48+
- fix(aws-serverless): Avoid minifying `Module._resolveFilename` in Lambda layer bundle (#12232)
49+
- fix(aws-serverless): Ensure lambda layer uses default export from `ImportInTheMiddle` (#12233)
50+
- fix(browser): Improve browser extension error message check (#12146)
51+
- fix(browser): Remove optional chaining in INP code (#12196)
52+
- fix(nextjs): Don't report React postpone errors (#12194)
53+
- fix(nextjs): Use global scope for generic event filters (#12205)
54+
- fix(node): Add origin to redis span (#12201)
55+
- fix(node): Change import of `@prisma/instrumentation` to use default import (#12185)
56+
- fix(node): Only import `inspector` asynchronously (#12231)
57+
- fix(replay): Update matcher for hydration error detection to new React docs (#12209)
58+
- ref(profiling-node): Add warning when using non-LTS node (#12211)
59+
760
## 8.4.0
861

962
### Important Changes

Diff for: dev-packages/browser-integration-tests/suites/metrics/test.ts renamed to dev-packages/browser-integration-tests/suites/metrics/metricsEvent/test.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
import { expect } from '@playwright/test';
22

3-
import { sentryTest } from '../../utils/fixtures';
4-
import { getFirstSentryEnvelopeRequest, properEnvelopeRequestParser } from '../../utils/helpers';
3+
import { sentryTest } from '../../../utils/fixtures';
4+
import {
5+
getFirstSentryEnvelopeRequest,
6+
properEnvelopeRequestParser,
7+
shouldSkipMetricsTest,
8+
} from '../../../utils/helpers';
59

610
sentryTest('collects metrics', async ({ getLocalTestUrl, page }) => {
11+
if (shouldSkipMetricsTest()) {
12+
sentryTest.skip();
13+
}
14+
715
const url = await getLocalTestUrl({ testDir: __dirname });
816

917
const statsdBuffer = await getFirstSentryEnvelopeRequest<Uint8Array>(page, url, properEnvelopeRequestParser);
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+
5+
Sentry.init({
6+
dsn: 'https://[email protected]/1337',
7+
});
8+
9+
// This should not fail
10+
Sentry.metrics.increment('increment');
11+
Sentry.metrics.distribution('distribution', 42);
12+
Sentry.metrics.gauge('gauge', 5);
13+
Sentry.metrics.set('set', 'nope');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { expect } from '@playwright/test';
2+
3+
import { sentryTest } from '../../../utils/fixtures';
4+
import { shouldSkipMetricsTest } from '../../../utils/helpers';
5+
6+
sentryTest('exports shim metrics integration for non-tracing bundles', async ({ getLocalTestPath, page }) => {
7+
// Skip in tracing tests
8+
if (!shouldSkipMetricsTest()) {
9+
sentryTest.skip();
10+
}
11+
12+
const consoleMessages: string[] = [];
13+
page.on('console', msg => consoleMessages.push(msg.text()));
14+
15+
let requestCount = 0;
16+
await page.route('https://dsn.ingest.sentry.io/**/*', route => {
17+
requestCount++;
18+
return route.fulfill({
19+
status: 200,
20+
contentType: 'application/json',
21+
body: JSON.stringify({ id: 'test-id' }),
22+
});
23+
});
24+
25+
const url = await getLocalTestPath({ testDir: __dirname });
26+
27+
await page.goto(url);
28+
29+
expect(requestCount).toBe(0);
30+
expect(consoleMessages).toEqual([
31+
'You are using metrics even though this bundle does not include tracing.',
32+
'You are using metrics even though this bundle does not include tracing.',
33+
'You are using metrics even though this bundle does not include tracing.',
34+
'You are using metrics even though this bundle does not include tracing.',
35+
]);
36+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const newTraceBtn = document.getElementById('newTrace');
2+
newTraceBtn.addEventListener('click', async () => {
3+
Sentry.startNewTrace(() => {
4+
Sentry.startSpan({ op: 'ui.interaction.click', name: 'new-trace' }, async () => {
5+
await fetch('http://example.com');
6+
});
7+
});
8+
});
9+
10+
const oldTraceBtn = document.getElementById('oldTrace');
11+
oldTraceBtn.addEventListener('click', async () => {
12+
Sentry.startSpan({ op: 'ui.interaction.click', name: 'old-trace' }, async () => {
13+
await fetch('http://example.com');
14+
});
15+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
</head>
6+
<body>
7+
<button id="oldTrace">Old Trace</button>
8+
<button id="newTrace">new Trace</button>
9+
</body>
10+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import { expect } from '@playwright/test';
2+
import { sentryTest } from '../../../../utils/fixtures';
3+
import type { EventAndTraceHeader } from '../../../../utils/helpers';
4+
import {
5+
eventAndTraceHeaderRequestParser,
6+
getFirstSentryEnvelopeRequest,
7+
getMultipleSentryEnvelopeRequests,
8+
shouldSkipTracingTest,
9+
} from '../../../../utils/helpers';
10+
11+
sentryTest(
12+
'creates a new trace if `startNewTrace` is called and leaves old trace valid outside the callback',
13+
async ({ getLocalTestUrl, page }) => {
14+
if (shouldSkipTracingTest()) {
15+
sentryTest.skip();
16+
}
17+
18+
const url = await getLocalTestUrl({ testDir: __dirname });
19+
20+
await page.route('http://example.com/**', route => {
21+
return route.fulfill({
22+
status: 200,
23+
contentType: 'application/json',
24+
body: JSON.stringify({}),
25+
});
26+
});
27+
28+
const [pageloadEvent, pageloadTraceHeaders] = await getFirstSentryEnvelopeRequest<EventAndTraceHeader>(
29+
page,
30+
url,
31+
eventAndTraceHeaderRequestParser,
32+
);
33+
34+
const pageloadTraceContext = pageloadEvent.contexts?.trace;
35+
36+
expect(pageloadEvent.type).toEqual('transaction');
37+
38+
expect(pageloadTraceContext).toMatchObject({
39+
op: 'pageload',
40+
trace_id: expect.stringMatching(/^[0-9a-f]{32}$/),
41+
span_id: expect.stringMatching(/^[0-9a-f]{16}$/),
42+
});
43+
expect(pageloadTraceContext).not.toHaveProperty('parent_span_id');
44+
45+
expect(pageloadTraceHeaders).toEqual({
46+
environment: 'production',
47+
public_key: 'public',
48+
sample_rate: '1',
49+
sampled: 'true',
50+
trace_id: pageloadTraceContext?.trace_id,
51+
});
52+
53+
const transactionPromises = getMultipleSentryEnvelopeRequests<EventAndTraceHeader>(
54+
page,
55+
2,
56+
{ envelopeType: 'transaction' },
57+
eventAndTraceHeaderRequestParser,
58+
);
59+
60+
await page.locator('#newTrace').click();
61+
await page.locator('#oldTrace').click();
62+
63+
const [txnEvent1, txnEvent2] = await transactionPromises;
64+
65+
const [newTraceTransactionEvent, newTraceTransactionTraceHeaders] =
66+
txnEvent1[0].transaction === 'new-trace' ? txnEvent1 : txnEvent2;
67+
const [oldTraceTransactionEvent, oldTraceTransactionTraceHeaders] =
68+
txnEvent1[0].transaction === 'old-trace' ? txnEvent1 : txnEvent2;
69+
70+
const newTraceTransactionTraceContext = newTraceTransactionEvent.contexts?.trace;
71+
expect(newTraceTransactionTraceContext).toMatchObject({
72+
op: 'ui.interaction.click',
73+
trace_id: expect.stringMatching(/^[0-9a-f]{32}$/),
74+
span_id: expect.stringMatching(/^[0-9a-f]{16}$/),
75+
});
76+
77+
expect(newTraceTransactionTraceHeaders).toEqual({
78+
environment: 'production',
79+
public_key: 'public',
80+
sample_rate: '1',
81+
sampled: 'true',
82+
trace_id: newTraceTransactionTraceContext?.trace_id,
83+
transaction: 'new-trace',
84+
});
85+
86+
const oldTraceTransactionEventTraceContext = oldTraceTransactionEvent.contexts?.trace;
87+
expect(oldTraceTransactionEventTraceContext).toMatchObject({
88+
op: 'ui.interaction.click',
89+
trace_id: expect.stringMatching(/^[0-9a-f]{32}$/),
90+
span_id: expect.stringMatching(/^[0-9a-f]{16}$/),
91+
});
92+
93+
expect(oldTraceTransactionTraceHeaders).toEqual({
94+
environment: 'production',
95+
public_key: 'public',
96+
sample_rate: '1',
97+
sampled: 'true',
98+
trace_id: oldTraceTransactionTraceHeaders?.trace_id,
99+
// transaction: 'old-trace', <-- this is not in the DSC because the DSC is continued from the pageload transaction
100+
// which does not have a `transaction` field because its source is URL.
101+
});
102+
103+
expect(oldTraceTransactionEventTraceContext?.trace_id).toEqual(pageloadTraceContext?.trace_id);
104+
expect(newTraceTransactionTraceContext?.trace_id).not.toEqual(pageloadTraceContext?.trace_id);
105+
},
106+
);

Diff for: dev-packages/browser-integration-tests/utils/helpers.ts

+13-1
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ export function shouldSkipTracingTest(): boolean {
241241
}
242242

243243
/**
244-
* We can only test replay tests in certain bundles/packages:
244+
* We can only test feedback tests in certain bundles/packages:
245245
* - NPM (ESM, CJS)
246246
* - CDN bundles that contain the Replay integration
247247
*
@@ -252,6 +252,18 @@ export function shouldSkipFeedbackTest(): boolean {
252252
return bundle != null && !bundle.includes('feedback') && !bundle.includes('esm') && !bundle.includes('cjs');
253253
}
254254

255+
/**
256+
* We can only test metrics tests in certain bundles/packages:
257+
* - NPM (ESM, CJS)
258+
* - CDN bundles that include tracing
259+
*
260+
* @returns `true` if we should skip the metrics test
261+
*/
262+
export function shouldSkipMetricsTest(): boolean {
263+
const bundle = process.env.PW_BUNDLE as string | undefined;
264+
return bundle != null && !bundle.includes('tracing') && !bundle.includes('esm') && !bundle.includes('cjs');
265+
}
266+
255267
/**
256268
* Waits until a number of requests matching urlRgx at the given URL arrive.
257269
* If the timout option is configured, this function will abort waiting, even if it hasn't reveived the configured
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import * as Sentry from '@sentry/nextjs';
2+
3+
export default async function Page({
4+
searchParams,
5+
}: {
6+
searchParams: { id?: string };
7+
}) {
8+
try {
9+
console.log(searchParams.id); // Accessing a field on searchParams will throw the PPR error
10+
} catch (e) {
11+
Sentry.captureException(e); // This error should not be reported
12+
await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for any async event processors to run
13+
await Sentry.flush();
14+
throw e;
15+
}
16+
17+
return <div>This server component will throw a PPR error that we do not want to catch.</div>;
18+
}

Diff for: dev-packages/e2e-tests/test-applications/nextjs-15/next.config.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
const { withSentryConfig } = require('@sentry/nextjs');
22

33
/** @type {import('next').NextConfig} */
4-
const nextConfig = {};
4+
const nextConfig = {
5+
experimental: {
6+
ppr: true,
7+
},
8+
};
59

610
module.exports = withSentryConfig(nextConfig, {
711
silent: true,

0 commit comments

Comments
 (0)