Skip to content

Commit 77a07e2

Browse files
authored
Merge branch 'develop' into sig/vue-error-throw
2 parents 964dfc7 + 3e73850 commit 77a07e2

File tree

76 files changed

+883
-700
lines changed

Some content is hidden

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

76 files changed

+883
-700
lines changed

.github/workflows/build.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1202,7 +1202,8 @@ jobs:
12021202
- name: Run E2E test
12031203
working-directory: dev-packages/e2e-tests/test-applications/${{ matrix.test-application }}
12041204
timeout-minutes: 10
1205-
run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- yarn test:assert
1205+
run: |
1206+
xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- yarn test:assert
12061207
12071208
job_required_jobs_passed:
12081209
name: All required jobs passed or were skipped

dev-packages/browser-integration-tests/suites/public-api/startSpan/parallel-root-spans-with-parentSpanId/subject.js

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
Sentry.getCurrentScope().setPropagationContext({
22
parentSpanId: '1234567890123456',
3-
spanId: '123456789012345x',
43
traceId: '12345678901234567890123456789012',
54
});
65

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
window.Sentry = Sentry;
4+
5+
Sentry.init({
6+
dsn: 'https://[email protected]/1337',
7+
integrations: integrations => {
8+
integrations.push(Sentry.browserTracingIntegration());
9+
return integrations.filter(i => i.name !== 'BrowserSession');
10+
},
11+
tracesSampleRate: 0,
12+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Sentry.captureException(new Error('test error'));
2+
Sentry.captureException(new Error('test error 2'));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="sentry-trace" content="12312012123120121231201212312012-1121201211212012" />
6+
<meta
7+
name="baggage"
8+
content="sentry-release=2.1.12,sentry-public_key=public,sentry-trace_id=123"
9+
/>
10+
</head>
11+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { expect } from '@playwright/test';
2+
import type { Event } from '@sentry/browser';
3+
import { sentryTest } from '../../../../utils/fixtures';
4+
import { getMultipleSentryEnvelopeRequests, shouldSkipTracingTest } from '../../../../utils/helpers';
5+
6+
sentryTest('errors in TwP mode have same trace ID & span IDs', async ({ getLocalTestUrl, page }) => {
7+
if (shouldSkipTracingTest()) {
8+
sentryTest.skip();
9+
}
10+
11+
const traceId = '12312012123120121231201212312012';
12+
const spanId = '1121201211212012';
13+
14+
const url = await getLocalTestUrl({ testDir: __dirname });
15+
const [event1, event2] = await getMultipleSentryEnvelopeRequests<Event>(page, 2, { url });
16+
17+
// Ensure these are the actual errors we care about
18+
expect(event1.exception?.values?.[0].value).toContain('test error');
19+
expect(event2.exception?.values?.[0].value).toContain('test error');
20+
21+
const contexts1 = event1.contexts;
22+
const { trace_id: traceId1, span_id: spanId1 } = contexts1?.trace || {};
23+
expect(traceId1).toEqual(traceId);
24+
25+
// Span ID is a virtual span, not the propagated one
26+
expect(spanId1).not.toEqual(spanId);
27+
expect(spanId1).toMatch(/^[a-f0-9]{16}$/);
28+
29+
const contexts2 = event2.contexts;
30+
const { trace_id: traceId2, span_id: spanId2 } = contexts2?.trace || {};
31+
expect(traceId2).toEqual(traceId);
32+
expect(spanId2).toMatch(/^[a-f0-9]{16}$/);
33+
34+
expect(spanId2).toEqual(spanId1);
35+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
window.Sentry = Sentry;
4+
5+
Sentry.init({
6+
dsn: 'https://[email protected]/1337',
7+
integrations: integrations => {
8+
integrations.push(Sentry.browserTracingIntegration());
9+
return integrations.filter(i => i.name !== 'BrowserSession');
10+
},
11+
tracesSampleRate: 0,
12+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Sentry.captureException(new Error('test error'));
2+
Sentry.captureException(new Error('test error 2'));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { expect } from '@playwright/test';
2+
import type { Event } from '@sentry/browser';
3+
import { sentryTest } from '../../../../utils/fixtures';
4+
import { getMultipleSentryEnvelopeRequests, shouldSkipTracingTest } from '../../../../utils/helpers';
5+
6+
sentryTest('errors in TwP mode have same trace ID & span IDs', async ({ getLocalTestUrl, page }) => {
7+
if (shouldSkipTracingTest()) {
8+
sentryTest.skip();
9+
}
10+
11+
const url = await getLocalTestUrl({ testDir: __dirname });
12+
const [event1, event2] = await getMultipleSentryEnvelopeRequests<Event>(page, 2, { url });
13+
14+
// Ensure these are the actual errors we care about
15+
expect(event1.exception?.values?.[0].value).toContain('test error');
16+
expect(event2.exception?.values?.[0].value).toContain('test error');
17+
18+
const contexts1 = event1.contexts;
19+
const { trace_id: traceId1, span_id: spanId1 } = contexts1?.trace || {};
20+
expect(traceId1).toMatch(/^[a-f0-9]{32}$/);
21+
expect(spanId1).toMatch(/^[a-f0-9]{16}$/);
22+
23+
const contexts2 = event2.contexts;
24+
const { trace_id: traceId2, span_id: spanId2 } = contexts2?.trace || {};
25+
expect(traceId2).toMatch(/^[a-f0-9]{32}$/);
26+
expect(spanId2).toMatch(/^[a-f0-9]{16}$/);
27+
28+
expect(traceId2).toEqual(traceId1);
29+
expect(spanId2).toEqual(spanId1);
30+
});

dev-packages/e2e-tests/test-applications/node-profiling/build.mjs renamed to dev-packages/e2e-tests/test-applications/node-profiling/build-cjs.mjs

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ console.log('Running build using esbuild version', esbuild.version);
1111
esbuild.buildSync({
1212
platform: 'node',
1313
entryPoints: ['./index.ts'],
14-
outdir: './dist',
14+
outfile: './dist/cjs/index.js',
1515
target: 'esnext',
1616
format: 'cjs',
1717
bundle: true,
1818
loader: { '.node': 'copy' },
19+
external: ['@sentry/node', '@sentry/profiling-node'],
1920
});

dev-packages/e2e-tests/test-applications/node-profiling/build.shimmed.mjs renamed to dev-packages/e2e-tests/test-applications/node-profiling/build-esm.mjs

+2-11
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,10 @@ console.log('Running build using esbuild version', esbuild.version);
1111
esbuild.buildSync({
1212
platform: 'node',
1313
entryPoints: ['./index.ts'],
14-
outfile: './dist/index.shimmed.mjs',
14+
outfile: './dist/esm/index.mjs',
1515
target: 'esnext',
1616
format: 'esm',
1717
bundle: true,
1818
loader: { '.node': 'copy' },
19-
banner: {
20-
js: `
21-
import { dirname } from 'node:path';
22-
import { fileURLToPath } from 'node:url';
23-
import { createRequire } from 'node:module';
24-
const require = createRequire(import.meta.url);
25-
const __filename = fileURLToPath(import.meta.url);
26-
const __dirname = dirname(__filename);
27-
`,
28-
},
19+
external: ['@sentry/node', '@sentry/profiling-node'],
2920
});

dev-packages/e2e-tests/test-applications/node-profiling/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
const Sentry = require('@sentry/node');
2-
const { nodeProfilingIntegration } = require('@sentry/profiling-node');
1+
import * as Sentry from '@sentry/node';
2+
import { nodeProfilingIntegration } from '@sentry/profiling-node';
33

44
const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
55

dev-packages/e2e-tests/test-applications/node-profiling/package.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
"private": true,
55
"scripts": {
66
"typecheck": "tsc --noEmit",
7-
"build": "node build.mjs && node build.shimmed.mjs",
8-
"test": "node dist/index.js && node --experimental-require-module dist/index.js && node dist/index.shimmed.mjs",
7+
"build": "node build-cjs.mjs && node build-esm.mjs",
8+
"test": "node dist/cjs/index.js && node --experimental-require-module dist/cjs/index.js && node dist/esm/index.mjs",
99
"clean": "npx rimraf node_modules dist",
1010
"test:electron": "$(pnpm bin)/electron-rebuild && playwright test",
1111
"test:build": "pnpm run typecheck && pnpm run build",
@@ -17,9 +17,9 @@
1717
"@sentry/electron": "latest || *",
1818
"@sentry/node": "latest || *",
1919
"@sentry/profiling-node": "latest || *",
20-
"electron": "^33.2.0"
20+
"electron": "^33.2.0",
21+
"esbuild": "0.20.0"
2122
},
22-
"devDependencies": {},
2323
"volta": {
2424
"extends": "../../package.json"
2525
},

dev-packages/node-integration-tests/suites/public-api/startSpan/parallel-root-spans/scenario.ts

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ Sentry.init({
1010

1111
Sentry.getCurrentScope().setPropagationContext({
1212
parentSpanId: '1234567890123456',
13-
spanId: '123456789012345x',
1413
traceId: '12345678901234567890123456789012',
1514
});
1615

dev-packages/node-integration-tests/suites/public-api/startSpan/parallel-spans-in-scope-with-parentSpanId/scenario.ts

-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ Sentry.init({
1111
Sentry.withScope(scope => {
1212
scope.setPropagationContext({
1313
parentSpanId: '1234567890123456',
14-
spanId: '123456789012345x',
1514
traceId: '12345678901234567890123456789012',
1615
});
1716

dev-packages/node-integration-tests/suites/tracing/meta-tags-twp-errors/test.ts

+11-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ describe('errors in TwP mode have same trace in trace context and getTraceData()
55
cleanupChildProcesses();
66
});
77

8+
// In a request handler, the spanId is consistent inside of the request
89
test('in incoming request', done => {
910
createRunner(__dirname, 'server.js')
1011
.expect({
@@ -30,6 +31,7 @@ describe('errors in TwP mode have same trace in trace context and getTraceData()
3031
.makeRequest('get', '/test');
3132
});
3233

34+
// Outside of a request handler, the spanId is random
3335
test('outside of a request handler', done => {
3436
createRunner(__dirname, 'no-server.js')
3537
.expect({
@@ -41,11 +43,18 @@ describe('errors in TwP mode have same trace in trace context and getTraceData()
4143

4244
const traceData = contexts?.traceData || {};
4345

44-
expect(traceData['sentry-trace']).toEqual(`${trace_id}-${span_id}`);
46+
expect(traceData['sentry-trace']).toMatch(/^[a-f0-9]{32}-[a-f0-9]{16}$/);
47+
expect(traceData['sentry-trace']).toContain(`${trace_id}-`);
48+
// span_id is a random span ID
49+
expect(traceData['sentry-trace']).not.toContain(span_id);
50+
4551
expect(traceData.baggage).toContain(`sentry-trace_id=${trace_id}`);
4652
expect(traceData.baggage).not.toContain('sentry-sampled=');
4753

48-
expect(traceData.metaTags).toContain(`<meta name="sentry-trace" content="${trace_id}-${span_id}"/>`);
54+
expect(traceData.metaTags).toMatch(/<meta name="sentry-trace" content="[a-f0-9]{32}-[a-f0-9]{16}"\/>/);
55+
expect(traceData.metaTags).toContain(`<meta name="sentry-trace" content="${trace_id}-`);
56+
// span_id is a random span ID
57+
expect(traceData.metaTags).not.toContain(span_id);
4958
expect(traceData.metaTags).toContain(`sentry-trace_id=${trace_id}`);
5059
expect(traceData.metaTags).not.toContain('sentry-sampled=');
5160
},

docs/migration/v8-to-v9.md

+13
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ Sentry.init({
6868
});
6969
```
7070

71+
- Dropping spans in the `beforeSendSpan` hook is no longer possible.
72+
- The `beforeSendSpan` hook now receives the root span as well as the child spans.
7173
- In previous versions, we determined if tracing is enabled (for Tracing Without Performance) by checking if either `tracesSampleRate` or `traceSampler` are _defined_ at all, in `Sentry.init()`. This means that e.g. the following config would lead to tracing without performance (=tracing being enabled, even if no spans would be started):
7274

7375
```js
@@ -90,6 +92,12 @@ In v9, an `undefined` value will be treated the same as if the value is not defi
9092

9193
- The `captureUserFeedback` method has been removed. Use `captureFeedback` instead and update the `comments` field to `message`.
9294

95+
### `@sentry/nextjs`
96+
97+
- The Sentry Next.js SDK will no longer use the Next.js Build ID as fallback identifier for releases. The SDK will continue to attempt to read CI-provider-specific environment variables and the current git SHA to automatically determine a release name. If you examine that you no longer see releases created in Sentry, it is recommended to manually provide a release name to `withSentryConfig` via the `release.name` option.
98+
99+
This behavior was changed because the Next.js Build ID is non-deterministic and the release name is injected into client bundles, causing build artifacts to be non-deterministic. This caused issues for some users. Additionally, because it is uncertain whether it will be possible to rely on a Build ID when Turbopack becomes stable, we decided to pull the plug now instead of introducing confusing behavior in the future.
100+
93101
### Uncategorized (TODO)
94102

95103
TODO
@@ -226,6 +234,7 @@ Since v9, the types have been merged into `@sentry/core`, which removed some of
226234
- The `IntegrationClass` type is no longer exported - it was not used anymore. Instead, use `Integration` or `IntegrationFn`.
227235
- The `samplingContext.request` attribute in the `tracesSampler` has been removed. Use `samplingContext.normalizedRequest` instead. Note that the type of `normalizedRequest` differs from `request`.
228236
- `Client` now always expects the `BaseClient` class - there is no more abstract `Client` that can be implemented! Any `Client` class has to extend from `BaseClient`.
237+
- `ReportDialogOptions` now extends `Record<string, unknown>` instead of `Record<string, any>` - this should not affect most users.
229238

230239
# No Version Support Timeline
231240

@@ -243,6 +252,10 @@ The following outlines deprecations that were introduced in version 8 of the SDK
243252
## General
244253

245254
- **Returning `null` from `beforeSendSpan` span is deprecated.**
255+
256+
Returning `null` from `beforeSendSpan` will now result in a warning being logged.
257+
In v9, dropping spans is not possible anymore within this hook.
258+
246259
- **Passing `undefined` to `tracesSampleRate` / `tracesSampler` / `enableTracing` will be handled differently in v9**
247260

248261
In v8, a setup like the following:

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"circularDepCheck": "lerna run circularDepCheck",
1616
"clean": "run-s clean:build clean:caches",
1717
"clean:build": "lerna run clean",
18-
"clean:caches": "yarn rimraf eslintcache .nxcache && yarn jest --clearCache",
18+
"clean:caches": "yarn rimraf eslintcache .nxcache .nx && yarn jest --clearCache",
1919
"clean:deps": "lerna clean --yes && rm -rf node_modules && yarn",
2020
"clean:tarballs": "rimraf {packages,dev-packages}/*/*.tgz",
2121
"clean:watchman": "watchman watch-del \".\"",

packages/browser-utils/src/metrics/inp.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,8 @@ function _trackINP(): () => void {
127127

128128
/**
129129
* Register a listener to cache route information for INP interactions.
130-
* TODO(v9): `latestRoute` no longer needs to be passed in and will be removed in v9.
131130
*/
132-
export function registerInpInteractionListener(_latestRoute?: unknown): void {
131+
export function registerInpInteractionListener(): void {
133132
const handleEntries = ({ entries }: { entries: PerformanceEntry[] }): void => {
134133
const activeSpan = getActiveSpan();
135134
const activeRootSpan = activeSpan && getRootSpan(activeSpan);

packages/browser/src/exports.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,11 @@ export type {
1313
Thread,
1414
User,
1515
Session,
16+
ReportDialogOptions,
1617
} from '@sentry/core';
1718

1819
export type { BrowserOptions } from './client';
1920

20-
export type { ReportDialogOptions } from './sdk';
21-
2221
export {
2322
addEventProcessor,
2423
addBreadcrumb,

packages/browser/src/sdk.ts

+1-32
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Client, DsnLike, Integration, Options } from '@sentry/core';
1+
import type { Client, Integration, Options, ReportDialogOptions } from '@sentry/core';
22
import {
33
consoleSandbox,
44
dedupeIntegration,
@@ -200,37 +200,6 @@ export function init(browserOptions: BrowserOptions = {}): Client | undefined {
200200
return initAndBind(BrowserClient, clientOptions);
201201
}
202202

203-
/**
204-
* All properties the report dialog supports
205-
*/
206-
export interface ReportDialogOptions {
207-
// TODO(v9): Change this to [key: string]: unknkown;
208-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
209-
[key: string]: any;
210-
eventId?: string;
211-
dsn?: DsnLike;
212-
user?: {
213-
email?: string;
214-
name?: string;
215-
};
216-
lang?: string;
217-
title?: string;
218-
subtitle?: string;
219-
subtitle2?: string;
220-
labelName?: string;
221-
labelEmail?: string;
222-
labelComments?: string;
223-
labelClose?: string;
224-
labelSubmit?: string;
225-
errorGeneric?: string;
226-
errorFormEntry?: string;
227-
successMessage?: string;
228-
/** Callback after reportDialog showed up */
229-
onLoad?(this: void): void;
230-
/** Callback after reportDialog closed */
231-
onClose?(this: void): void;
232-
}
233-
234203
/**
235204
* Present the user with a report dialog.
236205
*

0 commit comments

Comments
 (0)