Skip to content

Commit e0a75f5

Browse files
fix(integrations): Report BaseClient integrations added after init (#7011)
Report all integrations from BaseClient, even the ones that were added after the SDK intialization. This patch changes reading the list of integrations from `options.integrations` to `client._integrations`.
1 parent be6a8a1 commit e0a75f5

File tree

7 files changed

+51
-7
lines changed

7 files changed

+51
-7
lines changed

packages/core/src/baseclient.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,10 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
435435
*/
436436
protected _prepareEvent(event: Event, hint: EventHint, scope?: Scope): PromiseLike<Event | null> {
437437
const options = this.getOptions();
438+
const integrations = Object.keys(this._integrations);
439+
if (!hint.integrations && integrations.length > 0) {
440+
hint.integrations = integrations;
441+
}
438442
return prepareEvent(options, event, hint, scope);
439443
}
440444

packages/core/src/utils/prepareEvent.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,10 @@ export function prepareEvent(
3232
event_id: event.event_id || hint.event_id || uuid4(),
3333
timestamp: event.timestamp || dateTimestampInSeconds(),
3434
};
35+
const integrations = hint.integrations || options.integrations.map(i => i.name);
3536

3637
applyClientOptions(prepared, options);
37-
applyIntegrationsMetadata(
38-
prepared,
39-
options.integrations.map(i => i.name),
40-
);
38+
applyIntegrationsMetadata(prepared, integrations);
4139

4240
// If we have scope given to us, use it as the base for further modifications.
4341
// This allows us to prevent unnecessary copying of data if `captureContext` is not provided.

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

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { dsnToString, logger, SentryError, SyncPromise } from '@sentry/utils';
44
import { Hub, makeSession, Scope } from '../../src';
55
import * as integrationModule from '../../src/integration';
66
import { getDefaultTestClientOptions, TestClient } from '../mocks/client';
7-
import { TestIntegration } from '../mocks/integration';
7+
import { AdHocIntegration, TestIntegration } from '../mocks/integration';
88
import { makeFakeTransport } from '../mocks/transport';
99

1010
const PUBLIC_DSN = 'https://username@domain/123';
@@ -678,6 +678,25 @@ describe('BaseClient', () => {
678678
});
679679
});
680680

681+
test('send all installed integrations in event sdk metadata', () => {
682+
expect.assertions(1);
683+
684+
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
685+
const client = new TestClient(options);
686+
client.setupIntegrations();
687+
client.addIntegration(new AdHocIntegration());
688+
689+
client.captureException(new Error('test exception'));
690+
691+
expect(TestClient.instance!.event).toEqual(
692+
expect.objectContaining({
693+
sdk: expect.objectContaining({
694+
integrations: expect.arrayContaining(['TestIntegration', 'AdHockIntegration']),
695+
}),
696+
}),
697+
);
698+
});
699+
681700
test('normalizes event with default depth of 3', () => {
682701
expect.assertions(1);
683702

packages/core/test/mocks/integration.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,13 @@ export class AddAttachmentTestIntegration implements Integration {
3636
});
3737
}
3838
}
39+
40+
export class AdHocIntegration implements Integration {
41+
public static id: string = 'AdHockIntegration';
42+
43+
public name: string = 'AdHockIntegration';
44+
45+
public setupOnce(): void {
46+
// Noop
47+
}
48+
}

packages/replay/src/util/prepareReplayEvent.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { Scope } from '@sentry/core';
22
import { prepareEvent } from '@sentry/core';
3+
import type { IntegrationIndex } from '@sentry/core/build/types/integration';
34
import type { Client, ReplayEvent } from '@sentry/types';
45

56
/**
@@ -11,12 +12,21 @@ export async function prepareReplayEvent({
1112
replayId: event_id,
1213
event,
1314
}: {
14-
client: Client;
15+
client: Client & { _integrations?: IntegrationIndex };
1516
scope: Scope;
1617
replayId: string;
1718
event: ReplayEvent;
1819
}): Promise<ReplayEvent | null> {
19-
const preparedEvent = (await prepareEvent(client.getOptions(), event, { event_id }, scope)) as ReplayEvent | null;
20+
const integrations =
21+
typeof client._integrations === 'object' && client._integrations !== null && !Array.isArray(client._integrations)
22+
? Object.keys(client._integrations)
23+
: undefined;
24+
const preparedEvent = (await prepareEvent(
25+
client.getOptions(),
26+
event,
27+
{ event_id, integrations },
28+
scope,
29+
)) as ReplayEvent | null;
2030

2131
// If e.g. a global event processor returned null
2232
if (!preparedEvent) {

packages/types/src/event.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,5 @@ export interface EventHint {
8080
originalException?: Error | string | null;
8181
attachments?: Attachment[];
8282
data?: any;
83+
integrations?: string[];
8384
}

rollup/plugins/bundlePlugins.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ export function makeTerserPlugin() {
119119
// We want to keept he _replay and _isEnabled variable unmangled to enable integration tests to access it
120120
'_replay',
121121
'_isEnabled',
122+
// We want to keep the _integrations variable unmangled to send all installed integrations from replay
123+
'_integrations',
122124
],
123125
},
124126
},

0 commit comments

Comments
 (0)