Skip to content

Commit 0ef0c7f

Browse files
authored
Merge pull request #12073 from getsentry/prepare-release/8.2.0
meta(changelog): Update changelog for v8.2.0
2 parents e94e551 + 46511e5 commit 0ef0c7f

File tree

39 files changed

+1029
-59
lines changed

39 files changed

+1029
-59
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,6 +1004,7 @@ jobs:
10041004
'create-remix-app-express-vite-dev',
10051005
'debug-id-sourcemaps',
10061006
'node-express-esm-loader',
1007+
'node-express-esm-without-loader',
10071008
'nextjs-app-dir',
10081009
'nextjs-14',
10091010
'react-create-hash-router',

CHANGELOG.md

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

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

7+
## 8.2.0
8+
9+
- feat(redis-cache): Create cache-span with prefixed keys (get/set commands) (#12070)
10+
- feat(core): Add `beforeSendSpan` hook (#11886)
11+
- feat(browser): Improve idle span handling (#12065)
12+
- fix(node): Set transactionName for unsampled spans in httpIntegration (#12071)
13+
- fix(core): Export Scope interface as `Scope` (#12067)
14+
- fix(core): Avoid looking up client for `hasTracingEnabled()` if possible (#12066)
15+
- fix(browser): Use consistent timestamps (#12063)
16+
- fix(node): Fix check for performance integrations (#12043)
17+
- ref(sveltekit): Warn to delete source maps if Sentry plugin enabled source maps generation (#12072)
18+
719
## 8.1.0
820

921
This release mainly fixes a couple of bugs from the initial [8.0.0 release](#800). In addition to the changes below, we

MIGRATION.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,38 @@ The `BrowserTracing` integration, together with the custom routing instrumentati
647647
Instead, you should use `Sentry.browserTracingIntegration()`. See examples
648648
[below](./MIGRATION.md#deprecated-browsertracing-integration)
649649

650+
#### Removal of `interactionsSampleRate` in `browserTracingIntegration` options
651+
652+
The `interactionsSampleRate` option that could be passed to `browserTracingIntegration` or `new BrowserTracing()` was
653+
removed in v8, due to the option being redundant and in favour of bundle size minimization.
654+
655+
It's important to note that this sample rate only ever was applied when collecting INP (Interaction To Next Paint)
656+
values. You most likely don't need to replace this option. Furthermore, INP values are already sampled by the
657+
[`tracesSampleRate` SDK option](https://docs.sentry.io/platforms/javascript/configuration/options/#traces-sampler), like
658+
any regular span. At the time of writing, INP value collection does not deplete your span or transaction quota.
659+
660+
If you used `interactionsSampleRate` before, and still want to reduce INP value collection, we recommend using the
661+
`tracesSampler` SDK option instead:
662+
663+
```javascript
664+
// v7
665+
Sentry.init({
666+
integrations: [new BrowserTracing({ interactionsSampleRate: 0.1 })],
667+
});
668+
```
669+
670+
```javascript
671+
// v8 - please read the text above, you most likely don't need this :)
672+
Sentry.init({
673+
tracesSampler: (ctx) => {
674+
if (ctx.attributes?['sentry.op']?.startsWith('ui.interaction')) {
675+
return 0.1;
676+
}
677+
return 0.5;
678+
}
679+
})
680+
```
681+
650682
#### Removal of the `Offline` integration
651683
652684
The `Offline` integration has been removed in favor of the
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@sentry:registry=http://127.0.0.1:4873
2+
@sentry-internal:registry=http://127.0.0.1:4873
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "node-express-esm-without-loader",
3+
"version": "1.0.0",
4+
"private": true,
5+
"scripts": {
6+
"start": "node src/app.mjs",
7+
"clean": "npx rimraf node_modules pnpm-lock.yaml",
8+
"test:build": "pnpm install",
9+
"test:assert": "playwright test"
10+
},
11+
"dependencies": {
12+
"@sentry/node": "latest || *",
13+
"@sentry/opentelemetry": "latest || *",
14+
"express": "4.19.2"
15+
},
16+
"devDependencies": {
17+
"@sentry-internal/event-proxy-server": "link:../../../event-proxy-server",
18+
"@playwright/test": "^1.27.1"
19+
},
20+
"volta": {
21+
"extends": "../../package.json",
22+
"node": "18.19.1"
23+
}
24+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import type { PlaywrightTestConfig } from '@playwright/test';
2+
import { devices } from '@playwright/test';
3+
4+
// Fix urls not resolving to localhost on Node v17+
5+
// See: https://github.com/axios/axios/issues/3821#issuecomment-1413727575
6+
import { setDefaultResultOrder } from 'dns';
7+
setDefaultResultOrder('ipv4first');
8+
9+
const eventProxyPort = 3031;
10+
const expressPort = 3030;
11+
12+
/**
13+
* See https://playwright.dev/docs/test-configuration.
14+
*/
15+
const config: PlaywrightTestConfig = {
16+
testDir: './tests',
17+
/* Maximum time one test can run for. */
18+
timeout: 150_000,
19+
expect: {
20+
/**
21+
* Maximum time expect() should wait for the condition to be met.
22+
* For example in `await expect(locator).toHaveText();`
23+
*/
24+
timeout: 5000,
25+
},
26+
/* Run tests in files in parallel */
27+
fullyParallel: true,
28+
/* Fail the build on CI if you accidentally left test.only in the source code. */
29+
forbidOnly: !!process.env.CI,
30+
/* Retry on CI only */
31+
retries: 0,
32+
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
33+
reporter: 'list',
34+
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
35+
use: {
36+
/* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */
37+
actionTimeout: 0,
38+
39+
/* Base URL to use in actions like `await page.goto('/')`. */
40+
baseURL: `http://localhost:${expressPort}`,
41+
},
42+
43+
/* Configure projects for major browsers */
44+
projects: [
45+
{
46+
name: 'chromium',
47+
use: {
48+
...devices['Desktop Chrome'],
49+
},
50+
},
51+
],
52+
53+
/* Run your local dev server before starting the tests */
54+
webServer: [
55+
{
56+
command: 'node start-event-proxy.mjs',
57+
port: eventProxyPort,
58+
stdout: 'pipe',
59+
stderr: 'pipe',
60+
},
61+
{
62+
command: 'pnpm start',
63+
port: expressPort,
64+
stdout: 'pipe',
65+
stderr: 'pipe',
66+
},
67+
],
68+
};
69+
70+
export default config;
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import './instrument.mjs';
2+
3+
// Below other imports
4+
import * as Sentry from '@sentry/node';
5+
import express from 'express';
6+
7+
const app = express();
8+
const port = 3030;
9+
10+
app.get('/test-success', function (req, res) {
11+
setTimeout(() => {
12+
res.status(200).end();
13+
}, 100);
14+
});
15+
16+
app.get('/test-params/:param', function (req, res) {
17+
const { param } = req.params;
18+
Sentry.setTag(`param-${param}`, 'yes');
19+
Sentry.captureException(new Error(`Error for param ${param}`));
20+
21+
setTimeout(() => {
22+
res.status(200).end();
23+
}, 100);
24+
});
25+
26+
app.get('/test-error', function (req, res) {
27+
Sentry.captureException(new Error('This is an error'));
28+
setTimeout(() => {
29+
Sentry.flush(2000).then(() => {
30+
res.status(200).end();
31+
});
32+
}, 100);
33+
});
34+
35+
Sentry.setupExpressErrorHandler(app);
36+
37+
app.use(function onError(err, req, res, next) {
38+
// The error id is attached to `res.sentry` to be returned
39+
// and optionally displayed to the user for support.
40+
res.statusCode = 500;
41+
res.end(res.sentry + '\n');
42+
});
43+
44+
app.listen(port, () => {
45+
console.log(`Example app listening on port ${port}`);
46+
});
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import * as Sentry from '@sentry/node';
2+
3+
Sentry.init({
4+
environment: 'qa', // dynamic sampling bias to keep transactions
5+
dsn: process.env.E2E_TEST_DSN,
6+
tunnel: `http://localhost:3031/`, // proxy server
7+
});
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { startEventProxyServer } from '@sentry-internal/event-proxy-server';
2+
3+
startEventProxyServer({
4+
port: 3031,
5+
proxyServerName: 'node-express-esm-without-loader',
6+
});
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { expect, test } from '@playwright/test';
2+
import { waitForError } from '@sentry-internal/event-proxy-server';
3+
4+
test('Should record exceptions captured inside handlers', async ({ request }) => {
5+
const errorEventPromise = waitForError('node-express-esm-without-loader', errorEvent => {
6+
return !!errorEvent?.exception?.values?.[0]?.value?.includes('This is an error');
7+
});
8+
9+
await request.get('/test-error');
10+
11+
await expect(errorEventPromise).resolves.toBeDefined();
12+
});
13+
14+
test('Isolates requests', async ({ request }) => {
15+
const errorEventPromise = waitForError('node-express-esm-without-loader', errorEvent => {
16+
return !!errorEvent?.exception?.values?.[0]?.value?.includes('Error for param 1');
17+
});
18+
19+
const errorEventPromise2 = waitForError('node-express-esm-without-loader', errorEvent => {
20+
return !!errorEvent?.exception?.values?.[0]?.value?.includes('Error for param 2');
21+
});
22+
23+
await request.get('/test-params/1');
24+
await request.get('/test-params/2');
25+
26+
const errorEvent1 = await errorEventPromise;
27+
const errorEvent2 = await errorEventPromise2;
28+
29+
expect(errorEvent1.tags).toEqual({ 'param-1': 'yes' });
30+
expect(errorEvent2.tags).toEqual({ 'param-2': 'yes' });
31+
32+
expect(errorEvent1.transaction).toBe('GET /test-params/1');
33+
expect(errorEvent2.transaction).toBe('GET /test-params/2');
34+
});

dev-packages/node-integration-tests/suites/express/without-tracing/server.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ app.get('/test/isolationScope/:id', (req, res) => {
1818
const id = req.params.id;
1919
Sentry.setTag('isolation-scope', 'tag');
2020
Sentry.setTag(`isolation-scope-${id}`, id);
21-
Sentry.setTag('isolation-scope-transactionName', `${Sentry.getIsolationScope().getScopeData().transactionName}`);
2221

2322
Sentry.captureException(new Error('This is an exception'));
2423

dev-packages/node-integration-tests/suites/express/without-tracing/test.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,11 @@ test('correctly applies isolation scope even without tracing', done => {
99
.ignore('session', 'sessions')
1010
.expect({
1111
event: {
12+
transaction: 'GET /test/isolationScope/1',
1213
tags: {
1314
global: 'tag',
1415
'isolation-scope': 'tag',
1516
'isolation-scope-1': '1',
16-
// We can't properly test non-existance of fields here, so we cast this to a string to test it here
17-
'isolation-scope-transactionName': 'undefined',
1817
},
1918
// Request is correctly set
2019
request: {
@@ -27,12 +26,11 @@ test('correctly applies isolation scope even without tracing', done => {
2726
})
2827
.expect({
2928
event: {
29+
transaction: 'GET /test/isolationScope/2',
3030
tags: {
3131
global: 'tag',
3232
'isolation-scope': 'tag',
3333
'isolation-scope-2': '2',
34-
// We can't properly test non-existance of fields here, so we cast this to a string to test it here
35-
'isolation-scope-transactionName': 'undefined',
3634
},
3735
// Request is correctly set
3836
request: {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
version: '3.9'
2+
3+
services:
4+
db:
5+
image: redis:latest
6+
restart: always
7+
container_name: integration-tests-redis
8+
ports:
9+
- '6379:6379'
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
const { loggingTransport } = require('@sentry-internal/node-integration-tests');
2+
const Sentry = require('@sentry/node');
3+
4+
Sentry.init({
5+
dsn: 'https://public@dsn.ingest.sentry.io/1337',
6+
release: '1.0',
7+
tracesSampleRate: 1.0,
8+
transport: loggingTransport,
9+
integrations: [Sentry.redisIntegration({ cachePrefixes: ['ioredis-cache:'] })],
10+
});
11+
12+
// Stop the process from exiting before the transaction is sent
13+
setInterval(() => {}, 1000);
14+
15+
const Redis = require('ioredis');
16+
17+
const redis = new Redis({ port: 6379 });
18+
19+
async function run() {
20+
await Sentry.startSpan(
21+
{
22+
name: 'Test Span',
23+
op: 'test-span',
24+
},
25+
async () => {
26+
try {
27+
await redis.set('test-key', 'test-value');
28+
await redis.set('ioredis-cache:test-key', 'test-value');
29+
30+
await redis.get('test-key');
31+
await redis.get('ioredis-cache:test-key');
32+
await redis.get('ioredis-cache:unavailable-data');
33+
} finally {
34+
await redis.disconnect();
35+
}
36+
},
37+
);
38+
}
39+
40+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
41+
run();

0 commit comments

Comments
 (0)