Skip to content

Commit 3b7ec8c

Browse files
authored
Merge pull request #15755 from getsentry/prepare-release/9.7.0
meta(changelog): Update changelog for 9.7.0
2 parents c754c8c + 0614d95 commit 3b7ec8c

29 files changed

+1112
-139
lines changed

.size-limit.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ module.exports = [
4747
path: 'packages/browser/build/npm/esm/index.js',
4848
import: createImport('init', 'browserTracingIntegration', 'replayIntegration'),
4949
gzip: true,
50-
limit: '75.2 KB',
50+
limit: '75.5 KB',
5151
},
5252
{
5353
name: '@sentry/browser (incl. Tracing, Replay) - with treeshaking flags',
@@ -79,7 +79,7 @@ module.exports = [
7979
path: 'packages/browser/build/npm/esm/index.js',
8080
import: createImport('init', 'browserTracingIntegration', 'replayIntegration', 'replayCanvasIntegration'),
8181
gzip: true,
82-
limit: '80 KB',
82+
limit: '80.5 KB',
8383
},
8484
{
8585
name: '@sentry/browser (incl. Tracing, Replay, Feedback)',

CHANGELOG.md

+9
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,15 @@
1010

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

13+
## 9.7.0
14+
15+
- feat(core): Add `captureLog` method ([#15717](https://github.com/getsentry/sentry-javascript/pull/15717))
16+
- feat(remix/cloudflare): Export `sentryHandleError` ([#15726](https://github.com/getsentry/sentry-javascript/pull/15726))
17+
- fix(node): Always flush on Vercel before Lambda freeze ([#15602](https://github.com/getsentry/sentry-javascript/pull/15602))
18+
- fix(node): Ensure incoming traces are propagated without HttpInstrumentation ([#15732](https://github.com/getsentry/sentry-javascript/pull/15732))
19+
- fix(node): Use `fatal` level for unhandled rejections in `strict` mode ([#15720](https://github.com/getsentry/sentry-javascript/pull/15720))
20+
- fix(nuxt): Delete Nuxt server template injection ([#15749](https://github.com/getsentry/sentry-javascript/pull/15749))
21+
1322
## 9.6.1
1423

1524
- feat(deps): bump @prisma/instrumentation from 6.4.1 to 6.5.0 ([#15714](https://github.com/getsentry/sentry-javascript/pull/15714))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
const Sentry = require('@sentry/node');
2+
3+
Sentry.init({
4+
dsn: 'https://[email protected]/1337',
5+
integrations: [Sentry.onUnhandledRejectionIntegration({ mode: 'none' })],
6+
});
7+
8+
setTimeout(() => {
9+
process.stdout.write("I'm alive!");
10+
process.exit(0);
11+
}, 500);
12+
13+
Promise.reject('test rejection');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const Sentry = require('@sentry/node');
2+
3+
Sentry.init({
4+
dsn: 'https://[email protected]/1337',
5+
integrations: [Sentry.onUnhandledRejectionIntegration({ mode: 'strict' })],
6+
});
7+
8+
setTimeout(() => {
9+
// should not be called
10+
process.stdout.write("I'm alive!");
11+
process.exit(0);
12+
}, 500);
13+
14+
Promise.reject('test rejection');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const Sentry = require('@sentry/node');
2+
3+
Sentry.init({
4+
dsn: 'https://[email protected]/1337',
5+
});
6+
7+
setTimeout(() => {
8+
process.stdout.write("I'm alive!");
9+
process.exit(0);
10+
}, 500);
11+
12+
Promise.reject(new Error('test rejection'));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const Sentry = require('@sentry/node');
2+
3+
Sentry.init({
4+
dsn: 'https://[email protected]/1337',
5+
});
6+
7+
setTimeout(() => {
8+
process.stdout.write("I'm alive!");
9+
process.exit(0);
10+
}, 500);
11+
12+
Promise.reject('test rejection');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { loggingTransport } from '@sentry-internal/node-integration-tests';
2+
import * as Sentry from '@sentry/node';
3+
4+
Sentry.init({
5+
dsn: 'https://[email protected]/1337',
6+
release: '1.0',
7+
transport: loggingTransport,
8+
integrations: [Sentry.onUnhandledRejectionIntegration({ mode: 'strict' })],
9+
});
10+
11+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
12+
Promise.reject('test rejection');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { loggingTransport } from '@sentry-internal/node-integration-tests';
2+
import * as Sentry from '@sentry/node';
3+
4+
Sentry.init({
5+
dsn: 'https://[email protected]/1337',
6+
release: '1.0',
7+
transport: loggingTransport,
8+
});
9+
10+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
11+
Promise.reject('test rejection');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import * as childProcess from 'child_process';
2+
import * as path from 'path';
3+
import { afterAll, describe, expect, test } from 'vitest';
4+
import { cleanupChildProcesses } from '../../../utils/runner';
5+
import { createRunner } from '../../../utils/runner';
6+
7+
describe('onUnhandledRejectionIntegration', () => {
8+
afterAll(() => {
9+
cleanupChildProcesses();
10+
});
11+
12+
test('should show string-type promise rejection warnings by default', () =>
13+
new Promise<void>(done => {
14+
expect.assertions(3);
15+
16+
const testScriptPath = path.resolve(__dirname, 'mode-warn-string.js');
17+
18+
childProcess.execFile('node', [testScriptPath], { encoding: 'utf8' }, (err, stdout, stderr) => {
19+
expect(err).toBeNull();
20+
expect(stdout).toBe("I'm alive!");
21+
expect(stderr.trim())
22+
.toBe(`This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason:
23+
test rejection`);
24+
done();
25+
});
26+
}));
27+
28+
test('should show error-type promise rejection warnings by default', () =>
29+
new Promise<void>(done => {
30+
expect.assertions(3);
31+
32+
const testScriptPath = path.resolve(__dirname, 'mode-warn-error.js');
33+
34+
childProcess.execFile('node', [testScriptPath], { encoding: 'utf8' }, (err, stdout, stderr) => {
35+
expect(err).toBeNull();
36+
expect(stdout).toBe("I'm alive!");
37+
expect(stderr)
38+
.toContain(`This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason:
39+
Error: test rejection
40+
at Object.<anonymous>`);
41+
done();
42+
});
43+
}));
44+
45+
test('should not close process on unhandled rejection in strict mode', () =>
46+
new Promise<void>(done => {
47+
expect.assertions(4);
48+
49+
const testScriptPath = path.resolve(__dirname, 'mode-strict.js');
50+
51+
childProcess.execFile('node', [testScriptPath], { encoding: 'utf8' }, (err, stdout, stderr) => {
52+
expect(err).not.toBeNull();
53+
expect(err?.code).toBe(1);
54+
expect(stdout).not.toBe("I'm alive!");
55+
expect(stderr)
56+
.toContain(`This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason:
57+
test rejection`);
58+
done();
59+
});
60+
}));
61+
62+
test('should not close process or warn on unhandled rejection in none mode', () =>
63+
new Promise<void>(done => {
64+
expect.assertions(3);
65+
66+
const testScriptPath = path.resolve(__dirname, 'mode-none.js');
67+
68+
childProcess.execFile('node', [testScriptPath], { encoding: 'utf8' }, (err, stdout, stderr) => {
69+
expect(err).toBeNull();
70+
expect(stdout).toBe("I'm alive!");
71+
expect(stderr).toBe('');
72+
done();
73+
});
74+
}));
75+
76+
test('captures exceptions for unhandled rejections', async () => {
77+
await createRunner(__dirname, 'scenario-warn.ts')
78+
.expect({
79+
event: {
80+
level: 'error',
81+
exception: {
82+
values: [
83+
{
84+
type: 'Error',
85+
value: 'test rejection',
86+
mechanism: {
87+
type: 'onunhandledrejection',
88+
handled: false,
89+
},
90+
stacktrace: {
91+
frames: expect.any(Array),
92+
},
93+
},
94+
],
95+
},
96+
},
97+
})
98+
.start()
99+
.completed();
100+
});
101+
102+
test('captures exceptions for unhandled rejections in strict mode', async () => {
103+
await createRunner(__dirname, 'scenario-strict.ts')
104+
.expect({
105+
event: {
106+
level: 'fatal',
107+
exception: {
108+
values: [
109+
{
110+
type: 'Error',
111+
value: 'test rejection',
112+
mechanism: {
113+
type: 'onunhandledrejection',
114+
handled: false,
115+
},
116+
stacktrace: {
117+
frames: expect.any(Array),
118+
},
119+
},
120+
],
121+
},
122+
},
123+
})
124+
.start()
125+
.completed();
126+
});
127+
});

docs/publishing-a-release.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ _These steps are only relevant to Sentry employees when preparing and publishing
2020
[@getsentry/releases-approvers](https://github.com/orgs/getsentry/teams/release-approvers) to approve the release. a.
2121
Once the release is completed, a sync from `master` ->` develop` will be automatically triggered
2222

23-
## Publishing a release for previous majors
23+
## Publishing a release for previous majors or prerelease (alpha, beta) versions
2424

25-
1. Run `yarn changelog` on a previous major branch (e.g. `v8`) and determine what version will be released (we use
25+
1. Run `yarn changelog` on a previous major branch (e.g. `v8` or `9.7.0-alpha`) and determine what version will be released (we use
2626
[semver](https://semver.org))
2727
2. Create a branch, e.g. `changelog-8.45.1`, off a previous major branch (e.g. `v8`)
2828
3. Update `CHANGELOG.md` to add an entry for the next release number and a list of changes since the
@@ -32,9 +32,9 @@ _These steps are only relevant to Sentry employees when preparing and publishing
3232
(as the commits already exist on this branch).
3333
6. Once the PR is merged, open the [Prepare Release workflow](https://github.com/getsentry/sentry-javascript/actions/workflows/release.yml) and
3434
fill in ![run-release-workflow.png](./assets/run-release-workflow.png)
35-
1. The major branch you want to release for, e.g. `v8`
36-
2. The version you want to release, e.g. `8.45.1`
37-
3. The major branch to merge into, e.g. `v8`
35+
1. The major branch you want to release for, e.g. `v8` or `9.7.0-alpha`
36+
2. The version you want to release, e.g. `8.45.1` `9.7.0-alpha.1`
37+
3. The major branch to merge into, e.g. `v8` `9.7.0-alpha`
3838
7. Run the release workflow
3939

4040
## Updating the Changelog

packages/browser/src/client.ts

+4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
addAutoIpAddressToUser,
1616
applySdkMetadata,
1717
getSDKSource,
18+
_INTERNAL_flushLogsBuffer,
1819
} from '@sentry/core';
1920
import { eventFromException, eventFromMessage } from './eventbuilder';
2021
import { WINDOW } from './helpers';
@@ -85,6 +86,9 @@ export class BrowserClient extends Client<BrowserClientOptions> {
8586
WINDOW.document.addEventListener('visibilitychange', () => {
8687
if (WINDOW.document.visibilityState === 'hidden') {
8788
this._flushOutcomes();
89+
if (this._options._experiments?.enableLogs) {
90+
_INTERNAL_flushLogsBuffer(this);
91+
}
8892
}
8993
});
9094
}

packages/core/src/client.ts

+25-3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import type {
2828
SpanContextData,
2929
SpanJSON,
3030
StartSpanOptions,
31+
TraceContext,
3132
TransactionEvent,
3233
Transport,
3334
TransportMakeRequestResponse,
@@ -44,7 +45,10 @@ import { afterSetupIntegrations } from './integration';
4445
import { setupIntegration, setupIntegrations } from './integration';
4546
import type { Scope } from './scope';
4647
import { updateSession } from './session';
47-
import { getDynamicSamplingContextFromScope } from './tracing/dynamicSamplingContext';
48+
import {
49+
getDynamicSamplingContextFromScope,
50+
getDynamicSamplingContextFromSpan,
51+
} from './tracing/dynamicSamplingContext';
4852
import { createClientReportEnvelope } from './utils-hoist/clientreport';
4953
import { dsnToString, makeDsn } from './utils-hoist/dsn';
5054
import { addItemToEnvelope, createAttachmentEnvelopeItem } from './utils-hoist/envelope';
@@ -57,8 +61,9 @@ import { getPossibleEventMessages } from './utils/eventUtils';
5761
import { merge } from './utils/merge';
5862
import { parseSampleRate } from './utils/parseSampleRate';
5963
import { prepareEvent } from './utils/prepareEvent';
60-
import { showSpanDropWarning } from './utils/spanUtils';
64+
import { showSpanDropWarning, spanToTraceContext } from './utils/spanUtils';
6165
import { convertSpanJsonToTransactionEvent, convertTransactionEventToSpanJson } from './utils/transactionEvent';
66+
import { _getSpanForScope } from './utils/spanOnScope';
6267

6368
const ALREADY_SEEN_ERROR = "Not capturing exception because it's already been captured.";
6469
const MISSING_RELEASE_FOR_SESSION_ERROR = 'Discarded session because of missing or non-string release';
@@ -617,7 +622,7 @@ export abstract class Client<O extends ClientOptions = ClientOptions> {
617622
public on(hook: 'close', callback: () => void): () => void;
618623

619624
/**
620-
* Register a hook oin this client.
625+
* Register a hook on this client.
621626
*/
622627
public on(hook: string, callback: unknown): () => void {
623628
const hooks = (this._hooks[hook] = this._hooks[hook] || []);
@@ -1256,3 +1261,20 @@ function isErrorEvent(event: Event): event is ErrorEvent {
12561261
function isTransactionEvent(event: Event): event is TransactionEvent {
12571262
return event.type === 'transaction';
12581263
}
1264+
1265+
/** Extract trace information from scope */
1266+
export function _getTraceInfoFromScope(
1267+
client: Client,
1268+
scope: Scope | undefined,
1269+
): [dynamicSamplingContext: Partial<DynamicSamplingContext> | undefined, traceContext: TraceContext | undefined] {
1270+
if (!scope) {
1271+
return [undefined, undefined];
1272+
}
1273+
1274+
const span = _getSpanForScope(scope);
1275+
const traceContext = span ? spanToTraceContext(span) : getTraceContextFromScope(scope);
1276+
const dynamicSamplingContext = span
1277+
? getDynamicSamplingContextFromSpan(span)
1278+
: getDynamicSamplingContextFromScope(client, scope);
1279+
return [dynamicSamplingContext, traceContext];
1280+
}

packages/core/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ export { instrumentFetchRequest } from './fetch';
113113
export { trpcMiddleware } from './trpc';
114114
export { captureFeedback } from './feedback';
115115
export type { ReportDialogOptions } from './report-dialog';
116+
export { _INTERNAL_flushLogsBuffer } from './logs';
116117

117118
// TODO: Make this structure pretty again and don't do "export *"
118119
export * from './utils-hoist/index';

packages/core/src/logs/constants.ts

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import type { LogSeverityLevel } from '../types-hoist';
2+
3+
/**
4+
* Maps a log severity level to a log severity number.
5+
*
6+
* @see LogSeverityLevel
7+
*/
8+
export const SEVERITY_TEXT_TO_SEVERITY_NUMBER: Partial<Record<LogSeverityLevel, number>> = {
9+
trace: 1,
10+
debug: 5,
11+
info: 9,
12+
warn: 13,
13+
error: 17,
14+
fatal: 21,
15+
};

0 commit comments

Comments
 (0)