Skip to content

Commit 7ab0fe8

Browse files
authored
feat(core): Add client.init() to replace client.setupIntegrations() (#10118)
This adds a new `client.init()` method to be called instead of `client.setupIntegrations()`. Note that this method simply initializes the integrations always, and depends on the check that we don't add integrations multiple times. This also has a bit of a different semantic, dropping the `force` argument in favor of just calling `addIntegration()` again - this depends on #10116 to really work.
1 parent 324e5bf commit 7ab0fe8

File tree

10 files changed

+134
-27
lines changed

10 files changed

+134
-27
lines changed

MIGRATION.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ If you are using the `Hub` right now, see the following table on how to migrate
6464
| endSession() | `Sentry.endSession()` |
6565
| shouldSendDefaultPii() | REMOVED - The closest equivalent is `Sentry.getClient().getOptions().sendDefaultPii` |
6666

67+
## Deprecate `client.setupIntegrations()`
68+
69+
Instead, use the new `client.init()` method. You should probably not use this directly and instead use `Sentry.init()`, which calls this under the hood. But if you have a special use case that requires that, you can call `client.init()` instead now.
70+
6771
## Deprecate `scope.getSpan()` and `scope.setSpan()`
6872

6973
Instead, you can get the currently active span via `Sentry.getActiveSpan()`. Setting a span on the scope happens

packages/browser/test/unit/sdk.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ jest.mock('@sentry/core', () => {
4242
return new Scope();
4343
},
4444
bindClient(client: Client): boolean {
45-
client.setupIntegrations();
45+
client.init!();
4646
return true;
4747
},
4848
};

packages/core/src/baseclient.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -314,12 +314,19 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
314314
}
315315

316316
/**
317-
* Sets up the integrations
317+
* This is an internal function to setup all integrations that should run on the client.
318+
* @deprecated Use `client.init()` instead.
318319
*/
319320
public setupIntegrations(forceInitialize?: boolean): void {
320321
if ((forceInitialize && !this._integrationsInitialized) || (this._isEnabled() && !this._integrationsInitialized)) {
321-
this._integrations = setupIntegrations(this, this._options.integrations);
322-
this._integrationsInitialized = true;
322+
this._setupIntegrations();
323+
}
324+
}
325+
326+
/** @inheritdoc */
327+
public init(): void {
328+
if (this._isEnabled()) {
329+
this._setupIntegrations();
323330
}
324331
}
325332

@@ -512,6 +519,13 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
512519

513520
/* eslint-enable @typescript-eslint/unified-signatures */
514521

522+
/** Setup integrations for this client. */
523+
protected _setupIntegrations(): void {
524+
this._integrations = setupIntegrations(this, this._options.integrations);
525+
// TODO v8: We don't need this flag anymore
526+
this._integrationsInitialized = true;
527+
}
528+
515529
/** Updates existing session based on the provided event */
516530
protected _updateSessionFromEvent(session: Session, event: Event): void {
517531
let crashed = false;

packages/core/src/hub.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,9 @@ export class Hub implements HubInterface {
173173
const top = this.getStackTop();
174174
top.client = client;
175175
top.scope.setClient(client);
176+
// eslint-disable-next-line deprecation/deprecation
176177
if (client && client.setupIntegrations) {
178+
// eslint-disable-next-line deprecation/deprecation
177179
client.setupIntegrations();
178180
}
179181
}

packages/core/test/lib/base.test.ts

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -681,7 +681,7 @@ describe('BaseClient', () => {
681681
test('adds installed integrations to sdk info', () => {
682682
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
683683
const client = new TestClient(options);
684-
client.setupIntegrations();
684+
client.init();
685685

686686
client.captureEvent({ message: 'message' });
687687

@@ -695,7 +695,7 @@ describe('BaseClient', () => {
695695

696696
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
697697
const client = new TestClient(options);
698-
client.setupIntegrations();
698+
client.init();
699699
client.addIntegration(new AdHocIntegration());
700700

701701
client.captureException(new Error('test exception'));
@@ -716,7 +716,7 @@ describe('BaseClient', () => {
716716
integrations: [new TestIntegration(), null, undefined],
717717
});
718718
const client = new TestClient(options);
719-
client.setupIntegrations();
719+
client.init();
720720

721721
client.captureEvent({ message: 'message' });
722722

@@ -1492,24 +1492,48 @@ describe('BaseClient', () => {
14921492

14931493
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
14941494
const client = new TestClient(options);
1495+
// eslint-disable-next-line deprecation/deprecation
14951496
client.setupIntegrations();
14961497

14971498
expect(Object.keys((client as any)._integrations).length).toEqual(1);
14981499
expect(client.getIntegration(TestIntegration)).toBeTruthy();
14991500
});
15001501

1501-
test('skips installation if DSN is not provided', () => {
1502+
test('sets up each integration on `init` call', () => {
1503+
expect.assertions(2);
1504+
1505+
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
1506+
const client = new TestClient(options);
1507+
client.init();
1508+
1509+
expect(Object.keys((client as any)._integrations).length).toEqual(1);
1510+
expect(client.getIntegration(TestIntegration)).toBeTruthy();
1511+
});
1512+
1513+
test('skips installation for `setupIntegrations()` if DSN is not provided', () => {
15021514
expect.assertions(2);
15031515

15041516
const options = getDefaultTestClientOptions({ integrations: [new TestIntegration()] });
15051517
const client = new TestClient(options);
1518+
// eslint-disable-next-line deprecation/deprecation
15061519
client.setupIntegrations();
15071520

15081521
expect(Object.keys((client as any)._integrations).length).toEqual(0);
15091522
expect(client.getIntegration(TestIntegration)).toBeFalsy();
15101523
});
15111524

1512-
test('skips installation if `enabled` is set to `false`', () => {
1525+
test('skips installation for `init()` if DSN is not provided', () => {
1526+
expect.assertions(2);
1527+
1528+
const options = getDefaultTestClientOptions({ integrations: [new TestIntegration()] });
1529+
const client = new TestClient(options);
1530+
client.init();
1531+
1532+
expect(Object.keys((client as any)._integrations).length).toEqual(0);
1533+
expect(client.getIntegration(TestIntegration)).toBeFalsy();
1534+
});
1535+
1536+
test('skips installation for `setupIntegrations()` if `enabled` is set to `false`', () => {
15131537
expect.assertions(2);
15141538

15151539
const options = getDefaultTestClientOptions({
@@ -1518,12 +1542,28 @@ describe('BaseClient', () => {
15181542
integrations: [new TestIntegration()],
15191543
});
15201544
const client = new TestClient(options);
1545+
// eslint-disable-next-line deprecation/deprecation
15211546
client.setupIntegrations();
15221547

15231548
expect(Object.keys((client as any)._integrations).length).toEqual(0);
15241549
expect(client.getIntegration(TestIntegration)).toBeFalsy();
15251550
});
15261551

1552+
test('skips installation for `init()` if `enabled` is set to `false`', () => {
1553+
expect.assertions(2);
1554+
1555+
const options = getDefaultTestClientOptions({
1556+
dsn: PUBLIC_DSN,
1557+
enabled: false,
1558+
integrations: [new TestIntegration()],
1559+
});
1560+
const client = new TestClient(options);
1561+
client.init();
1562+
1563+
expect(Object.keys((client as any)._integrations).length).toEqual(0);
1564+
expect(client.getIntegration(TestIntegration)).toBeFalsy();
1565+
});
1566+
15271567
test('skips installation if integrations are already installed', () => {
15281568
expect.assertions(4);
15291569

@@ -1533,17 +1573,41 @@ describe('BaseClient', () => {
15331573
const setupIntegrationsHelper = jest.spyOn(integrationModule, 'setupIntegrations');
15341574

15351575
// it should install the first time, because integrations aren't yet installed...
1576+
// eslint-disable-next-line deprecation/deprecation
15361577
client.setupIntegrations();
15371578

15381579
expect(Object.keys((client as any)._integrations).length).toEqual(1);
15391580
expect(client.getIntegration(TestIntegration)).toBeTruthy();
15401581
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);
15411582

15421583
// ...but it shouldn't try to install a second time
1584+
// eslint-disable-next-line deprecation/deprecation
15431585
client.setupIntegrations();
15441586

15451587
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);
15461588
});
1589+
1590+
test('does not add integrations twice when calling `init` multiple times', () => {
1591+
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
1592+
const client = new TestClient(options);
1593+
// note: not the `Client` method `setupIntegrations`, but the free-standing function which that method calls
1594+
const setupIntegrationsHelper = jest.spyOn(integrationModule, 'setupIntegrations');
1595+
1596+
// it should install the first time, because integrations aren't yet installed...
1597+
client.init();
1598+
1599+
expect(Object.keys((client as any)._integrations).length).toEqual(1);
1600+
expect(client.getIntegration(TestIntegration)).toBeTruthy();
1601+
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);
1602+
1603+
client.init();
1604+
1605+
// is called again...
1606+
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(2);
1607+
1608+
// but integrations are only added once anyhow!
1609+
expect(client['_integrations']).toEqual({ TestIntegration: expect.any(TestIntegration) });
1610+
});
15471611
});
15481612

15491613
describe('flush/close', () => {

packages/core/test/lib/integrations/inboundfilters.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ function createInboundFiltersEventProcessor(
3737
}),
3838
);
3939

40-
client.setupIntegrations();
40+
client.init();
4141

4242
const eventProcessors = client['_eventProcessors'];
4343
const eventProcessor = eventProcessors.find(processor => processor.id === 'InboundFilters');

packages/node-experimental/src/sdk/init.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
getSentryRelease,
77
makeNodeTransport,
88
} from '@sentry/node';
9-
import type { Integration } from '@sentry/types';
9+
import type { Client, Integration } from '@sentry/types';
1010
import {
1111
consoleSandbox,
1212
dropUndefinedKeys,
@@ -67,7 +67,9 @@ export function init(options: NodeExperimentalOptions | undefined = {}): void {
6767
// unless somebody specifically sets a different one on a scope/isolations cope
6868
getGlobalScope().setClient(client);
6969

70-
client.setupIntegrations();
70+
if (isEnabled(client)) {
71+
client.init();
72+
}
7173

7274
if (options.autoSessionTracking) {
7375
startSessionTracking();
@@ -79,7 +81,11 @@ export function init(options: NodeExperimentalOptions | undefined = {}): void {
7981
const client = getClient();
8082
if (client.addIntegration) {
8183
// force integrations to be setup even if no DSN was set
82-
client.setupIntegrations(true);
84+
// If they have already been added before, they will be ignored anyhow
85+
const integrations = client.getOptions().integrations;
86+
for (const integration of integrations) {
87+
client.addIntegration(integration);
88+
}
8389
client.addIntegration(
8490
new Integrations.Spotlight({
8591
sidecarUrl: typeof options.spotlight === 'string' ? options.spotlight : undefined,
@@ -213,3 +219,7 @@ function startSessionTracking(): void {
213219
}
214220
});
215221
}
222+
223+
function isEnabled(client: Client): boolean {
224+
return client.getOptions().enabled !== false && client.getTransport() !== undefined;
225+
}

packages/node/src/sdk.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,11 @@ export function init(options: NodeOptions = {}): void {
183183
const client = getClient();
184184
if (client && client.addIntegration) {
185185
// force integrations to be setup even if no DSN was set
186-
client.setupIntegrations(true);
186+
// If they have already been added before, they will be ignored anyhow
187+
const integrations = client.getOptions().integrations;
188+
for (const integration of integrations) {
189+
client.addIntegration(integration);
190+
}
187191
client.addIntegration(
188192
new Spotlight({ sidecarUrl: typeof options.spotlight === 'string' ? options.spotlight : undefined }),
189193
);

packages/node/test/integrations/localvariables.test.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
162162
const options = getDefaultNodeClientOptions({
163163
stackParser: defaultStackParser,
164164
includeLocalVariables: true,
165-
integrations: [localVariables],
165+
integrations: [],
166166
});
167167

168168
const client = new NodeClient(options);
169-
client.setupIntegrations(true);
169+
client.addIntegration(localVariables);
170170

171171
const eventProcessors = client['_eventProcessors'];
172172
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
@@ -253,11 +253,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
253253
const options = getDefaultNodeClientOptions({
254254
stackParser: defaultStackParser,
255255
includeLocalVariables: true,
256-
integrations: [localVariables],
256+
integrations: [],
257257
});
258258

259259
const client = new NodeClient(options);
260-
client.setupIntegrations(true);
260+
client.addIntegration(localVariables);
261261

262262
await session.runPause(exceptionEvent100Frames);
263263

@@ -278,11 +278,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
278278
const options = getDefaultNodeClientOptions({
279279
stackParser: defaultStackParser,
280280
includeLocalVariables: true,
281-
integrations: [localVariables],
281+
integrations: [],
282282
});
283283

284284
const client = new NodeClient(options);
285-
client.setupIntegrations(true);
285+
client.addIntegration(localVariables);
286286

287287
const nonExceptionEvent = {
288288
method: exceptionEvent.method,
@@ -299,11 +299,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
299299
const localVariables = new LocalVariablesSync({}, session);
300300
const options = getDefaultNodeClientOptions({
301301
stackParser: defaultStackParser,
302-
integrations: [localVariables],
302+
integrations: [],
303303
});
304304

305305
const client = new NodeClient(options);
306-
client.setupIntegrations(true);
306+
client.addIntegration(localVariables);
307307

308308
const eventProcessors = client['_eventProcessors'];
309309
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
@@ -315,11 +315,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
315315
const localVariables = new LocalVariablesSync({}, undefined);
316316
const options = getDefaultNodeClientOptions({
317317
stackParser: defaultStackParser,
318-
integrations: [localVariables],
318+
integrations: [],
319319
});
320320

321321
const client = new NodeClient(options);
322-
client.setupIntegrations(true);
322+
client.addIntegration(localVariables);
323323

324324
const eventProcessors = client['_eventProcessors'];
325325
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
@@ -336,11 +336,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
336336
const options = getDefaultNodeClientOptions({
337337
stackParser: defaultStackParser,
338338
includeLocalVariables: true,
339-
integrations: [localVariables],
339+
integrations: [],
340340
});
341341

342342
const client = new NodeClient(options);
343-
client.setupIntegrations(true);
343+
client.addIntegration(localVariables);
344344

345345
await session.runPause(exceptionEvent);
346346
await session.runPause(exceptionEvent);

packages/types/src/client.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,18 @@ export interface Client<O extends ClientOptions = ClientOptions> {
151151
* */
152152
addIntegration?(integration: Integration): void;
153153

154-
/** This is an internal function to setup all integrations that should run on the client */
154+
/**
155+
* This is an internal function to setup all integrations that should run on the client.
156+
* @deprecated Use `client.init()` instead.
157+
*/
155158
setupIntegrations(forceInitialize?: boolean): void;
156159

160+
/**
161+
* Initialize this client.
162+
* Call this after the client was set on a scope.
163+
*/
164+
init?(): void;
165+
157166
/** Creates an {@link Event} from all inputs to `captureException` and non-primitive inputs to `captureMessage`. */
158167
// eslint-disable-next-line @typescript-eslint/no-explicit-any
159168
eventFromException(exception: any, hint?: EventHint): PromiseLike<Event>;

0 commit comments

Comments
 (0)