Skip to content

Commit 7d754a3

Browse files
authored
chore(node)!: Remove legacy profiling options (profilesSampleRate and profilesSampler) (#23216)
Node profiling now uses only `profileSessionSampleRate` and `profileLifecycle`. This PR removes all code that belonged to the previous options. Updated tests (removed tests for legacy options) and added E2E assertions (was only checking the build previously). Browser profiling will be updated in a follow-up PR. Closes of #23021
1 parent 32dd9d8 commit 7d754a3

14 files changed

Lines changed: 141 additions & 1654 deletions

File tree

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,44 @@
1+
import * as assert from 'node:assert/strict';
2+
import type { Envelope, ProfileChunkEnvelope } from '@sentry/core';
13
import * as Sentry from '@sentry/node';
24
import { nodeProfilingIntegration } from '@sentry/profiling-node';
35

4-
const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
6+
const sentEnvelopes: Envelope[] = [];
57

68
Sentry.init({
7-
traceLifecycle: 'static',
8-
dsn: 'https://7fa19397baaf433f919fbe02228d5470@o1137848.ingest.sentry.io/6625302',
9+
dsn: 'https://public@example.com/1',
910
integrations: [nodeProfilingIntegration()],
10-
tracesSampleRate: 1.0,
11-
profilesSampleRate: 1.0,
11+
tracesSampleRate: 1,
12+
profileSessionSampleRate: 1,
13+
profileLifecycle: 'trace',
14+
transport: () => ({
15+
send: envelope => {
16+
sentEnvelopes.push(envelope);
17+
return Promise.resolve({});
18+
},
19+
flush: () => Promise.resolve(true),
20+
}),
1221
});
1322

14-
Sentry.startSpan({ name: 'Precompile test' }, async () => {
15-
await wait(500);
16-
});
23+
async function main(): Promise<void> {
24+
await Sentry.startSpan({ name: 'Precompile test' }, async () => {
25+
await new Promise(resolve => setTimeout(resolve, 1_000));
26+
});
27+
await Sentry.flush(2_000);
28+
29+
const profileChunkEnvelopes = sentEnvelopes.filter(
30+
(envelope): envelope is ProfileChunkEnvelope => envelope[1][0]?.[0].type === 'profile_chunk',
31+
);
32+
assert.equal(profileChunkEnvelopes.length, 1);
33+
34+
const [header, payload] = profileChunkEnvelopes[0][1][0];
35+
assert.deepEqual(header, { type: 'profile_chunk', platform: 'node' });
36+
assert.equal(payload.platform, 'node');
37+
assert.equal(payload.version, '2');
38+
assert.match(payload.profiler_id, /^[a-f0-9]{32}$/);
39+
assert.match(payload.chunk_id, /^[a-f0-9]{32}$/);
40+
assert.ok(payload.profile.samples.length > 1);
41+
assert.ok(payload.profile.stacks.length > 0);
42+
}
43+
44+
void main();

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
},
1212
"dependencies": {
1313
"@playwright/test": "~1.56.0",
14+
"@sentry/core": "file:../../packed/sentry-core-packed.tgz",
1415
"@sentry/node": "file:../../packed/sentry-node-packed.tgz",
1516
"@sentry/profiling-node": "file:../../packed/sentry-profiling-node-packed.tgz",
1617
"@types/node": "^18.19.1",
Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,44 @@
1+
import * as assert from 'node:assert/strict';
2+
import type { Envelope, ProfileChunkEnvelope } from '@sentry/core';
13
import * as Sentry from '@sentry/node';
24
import { nodeProfilingIntegration } from '@sentry/profiling-node';
35

4-
const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
6+
const sentEnvelopes: Envelope[] = [];
57

68
Sentry.init({
7-
traceLifecycle: 'static',
8-
dsn: 'https://7fa19397baaf433f919fbe02228d5470@o1137848.ingest.sentry.io/6625302',
9+
dsn: 'https://public@example.com/1',
910
integrations: [nodeProfilingIntegration()],
10-
tracesSampleRate: 1.0,
11-
profilesSampleRate: 1.0,
11+
tracesSampleRate: 1,
12+
profileSessionSampleRate: 1,
13+
profileLifecycle: 'trace',
14+
transport: () => ({
15+
send: envelope => {
16+
sentEnvelopes.push(envelope);
17+
return Promise.resolve({});
18+
},
19+
flush: () => Promise.resolve(true),
20+
}),
1221
});
1322

14-
Sentry.startSpan({ name: 'Precompile test' }, async () => {
15-
await wait(500);
16-
});
23+
async function main(): Promise<void> {
24+
await Sentry.startSpan({ name: 'Precompile test' }, async () => {
25+
await new Promise(resolve => setTimeout(resolve, 1_000));
26+
});
27+
await Sentry.flush(2_000);
28+
29+
const profileChunkEnvelopes = sentEnvelopes.filter(
30+
(envelope): envelope is ProfileChunkEnvelope => envelope[1][0]?.[0].type === 'profile_chunk',
31+
);
32+
assert.equal(profileChunkEnvelopes.length, 1);
33+
34+
const [header, payload] = profileChunkEnvelopes[0][1][0];
35+
assert.deepEqual(header, { type: 'profile_chunk', platform: 'node' });
36+
assert.equal(payload.platform, 'node');
37+
assert.equal(payload.version, '2');
38+
assert.match(payload.profiler_id, /^[a-f0-9]{32}$/);
39+
assert.match(payload.chunk_id, /^[a-f0-9]{32}$/);
40+
assert.ok(payload.profile.samples.length > 1);
41+
assert.ok(payload.profile.stacks.length > 0);
42+
}
43+
44+
void main();

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
},
1212
"dependencies": {
1313
"@playwright/test": "~1.56.0",
14+
"@sentry/core": "file:../../packed/sentry-core-packed.tgz",
1415
"@sentry/node": "file:../../packed/sentry-node-packed.tgz",
1516
"@sentry/profiling-node": "file:../../packed/sentry-profiling-node-packed.tgz",
1617
"@types/node": "^18.19.1",

docs/migration/continuous-profiling.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ We've introduced `profileSessionSampleRate` to control what percentage of SDK in
2222
- Controlling profiling costs across distributed services
2323
- Managing profiling in serverless environments where you may only want to profile a subset of instances
2424

25-
### Deprecations
25+
### Removed Legacy Options
2626

27-
The `profilesSampleRate` option has been deprecated in favor of the new sampling controls.
28-
The `profilesSampler` option hsa been deprecated in favor of manual profiler control.
27+
The `profilesSampleRate` option has been removed in favor of the new sampling controls.
28+
The `profilesSampler` option hsa been removed in favor of manual profiler control.

packages/core/src/profiling.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ function isProfilingIntegrationWithProfiler(
1414
);
1515
}
1616
/**
17-
* Starts the Sentry continuous profiler.
18-
* This mode is exclusive with the transaction profiler and will only work if the profilesSampleRate is set to a falsy value.
19-
* In continuous profiling mode, the profiler will keep reporting profile chunks to Sentry until it is stopped, which allows for continuous profiling of the application.
17+
* Starts a manually controlled Sentry profiling session.
18+
*
19+
* Profiling starts only when the profiling integration sampled the current session and `profileLifecycle` is set to `manual`.
20+
* While running, the profiler periodically sends profile chunks to Sentry until `stopProfiler()` is called.
2021
*/
2122
function startProfiler(): void {
2223
const client = getClient();
@@ -41,8 +42,10 @@ function startProfiler(): void {
4142
}
4243

4344
/**
44-
* Stops the Sentry continuous profiler.
45-
* Calls to stop will stop the profiler and flush the currently collected profile data to Sentry.
45+
* Stops a manually controlled Sentry profiling session.
46+
*
47+
* If a manual profiling session is running, stops the profiler and sends the currently collected profile chunk to Sentry.
48+
* Calls are ignored when using the trace lifecycle or when no profiling session is running.
4649
*/
4750
function stopProfiler(): void {
4851
const client = getClient();

packages/node/src/types.ts

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { ClientOptions, Options, SamplingContext, Scope, ServerRuntimeOptions } from '@sentry/core';
1+
import type { ClientOptions, Options, Scope, ServerRuntimeOptions } from '@sentry/core';
22
import type { NodeTransportOptions } from './transports';
33

44
/**
@@ -37,28 +37,6 @@ export interface BaseNodeOptions extends OpenTelemetryServerRuntimeOptions {
3737
* @hidden This is primarily used internally to support platforms like Next on OpenNext/Cloudflare.
3838
*/
3939
runtime?: { name: string; version?: string };
40-
/**
41-
* Sets profiling sample rate when @sentry/profiling-node is installed
42-
*
43-
* @deprecated
44-
*/
45-
profilesSampleRate?: number;
46-
47-
/**
48-
* Function to compute profiling sample rate dynamically and filter unwanted profiles.
49-
*
50-
* Profiling is enabled if either this or `profilesSampleRate` is defined. If both are defined, `profilesSampleRate` is
51-
* ignored.
52-
*
53-
* Will automatically be passed a context object of default and optional custom data.
54-
*
55-
* @returns A sample rate between 0 and 1 (0 drops the profile, 1 guarantees it will be sent). Returning `true` is
56-
* equivalent to returning 1 and returning `false` is equivalent to returning 0.
57-
*
58-
* @deprecated
59-
*/
60-
profilesSampler?: (samplingContext: SamplingContext) => number | boolean;
61-
6240
/**
6341
* Sets profiling session sample rate for the entire profiling session (evaluated once per SDK initialization).
6442
*

packages/profiling-node/README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,22 @@ Sentry.init({
3232
dsn: 'https://7fa19397baaf433f919fbe02228d5470@o1137848.ingest.sentry.io/6625302',
3333
debug: true,
3434
tracesSampleRate: 1,
35-
profilesSampleRate: 1, // Set profiling sampling rate.
35+
profileSessionSampleRate: 1,
36+
profileLifecycle: 'trace',
3637
integrations: [nodeProfilingIntegration()],
3738
});
3839
```
3940

40-
Sentry SDK will now automatically profile all root spans, even the ones which may be started as a result of using an
41-
automatic instrumentation integration.
41+
The Sentry SDK will now collect profile chunks while spans are active, including spans started by automatic instrumentation.
4242

4343
```javascript
4444
Sentry.startSpan({ name: 'some workflow' }, () => {
4545
// The code in here will be profiled
4646
});
4747
```
4848

49+
With `profileLifecycle: 'manual'` (the default), you can start and stop the profiler by calling `Sentry.profiler.startProfiler()` and `Sentry.profiler.stopProfiler()`.
50+
4951
### Building the package from source
5052

5153
Profiling uses native modules to interop with the v8 javascript engine which means that you may be required to build it

0 commit comments

Comments
 (0)