Skip to content

Commit 1a097a1

Browse files
committed
ref(browser): Refactor browser integrations to avoid setupOnce
Also a small core refactor...
1 parent 84299d0 commit 1a097a1

File tree

3 files changed

+93
-108
lines changed

3 files changed

+93
-108
lines changed

packages/browser/src/integrations/globalhandlers.ts

Lines changed: 27 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
2-
import { getCurrentHub } from '@sentry/core';
3-
import type { Event, Hub, Integration, Primitive, StackParser } from '@sentry/types';
2+
import { captureEvent, getClient } from '@sentry/core';
3+
import type { Client, Event, Integration, Primitive, StackParser } from '@sentry/types';
44
import {
55
addGlobalErrorInstrumentationHandler,
66
addGlobalUnhandledRejectionInstrumentationHandler,
@@ -36,12 +36,6 @@ export class GlobalHandlers implements Integration {
3636
/** JSDoc */
3737
private readonly _options: GlobalHandlersIntegrations;
3838

39-
/**
40-
* Stores references functions to installing handlers. Will set to undefined
41-
* after they have been run so that they are not used twice.
42-
*/
43-
private _installFunc: Record<GlobalHandlersIntegrationsOptionKeys, (() => void) | undefined>;
44-
4539
/** JSDoc */
4640
public constructor(options?: GlobalHandlersIntegrations) {
4741
this.name = GlobalHandlers.id;
@@ -50,43 +44,36 @@ export class GlobalHandlers implements Integration {
5044
onunhandledrejection: true,
5145
...options,
5246
};
53-
54-
this._installFunc = {
55-
onerror: _installGlobalOnErrorHandler,
56-
onunhandledrejection: _installGlobalOnUnhandledRejectionHandler,
57-
};
5847
}
5948
/**
6049
* @inheritDoc
6150
*/
6251
public setupOnce(): void {
6352
Error.stackTraceLimit = 50;
64-
const options = this._options;
65-
66-
// We can disable guard-for-in as we construct the options object above + do checks against
67-
// `this._installFunc` for the property.
68-
// eslint-disable-next-line guard-for-in
69-
for (const key in options) {
70-
const installFunc = this._installFunc[key as GlobalHandlersIntegrationsOptionKeys];
71-
if (installFunc && options[key as GlobalHandlersIntegrationsOptionKeys]) {
72-
globalHandlerLog(key);
73-
installFunc();
74-
this._installFunc[key as GlobalHandlersIntegrationsOptionKeys] = undefined;
75-
}
53+
}
54+
55+
/** @inheritdoc */
56+
public setup(client: Client): void {
57+
if (this._options.onerror) {
58+
_installGlobalOnErrorHandler(client);
59+
globalHandlerLog('onerror');
60+
}
61+
if (this._options.onunhandledrejection) {
62+
_installGlobalOnUnhandledRejectionHandler(client);
63+
globalHandlerLog('onunhandledrejection');
7664
}
7765
}
7866
}
7967

80-
function _installGlobalOnErrorHandler(): void {
68+
function _installGlobalOnErrorHandler(client: Client): void {
8169
addGlobalErrorInstrumentationHandler(data => {
82-
const [hub, stackParser, attachStacktrace] = getHubAndOptions();
83-
if (!hub.getIntegration(GlobalHandlers)) {
70+
const { stackParser, attachStacktrace } = getOptions();
71+
72+
if (getClient() !== client || shouldIgnoreOnError()) {
8473
return;
8574
}
75+
8676
const { msg, url, line, column, error } = data;
87-
if (shouldIgnoreOnError()) {
88-
return;
89-
}
9077

9178
const event =
9279
error === undefined && isString(msg)
@@ -100,7 +87,7 @@ function _installGlobalOnErrorHandler(): void {
10087

10188
event.level = 'error';
10289

103-
hub.captureEvent(event, {
90+
captureEvent(event, {
10491
originalException: error,
10592
mechanism: {
10693
handled: false,
@@ -110,15 +97,12 @@ function _installGlobalOnErrorHandler(): void {
11097
});
11198
}
11299

113-
function _installGlobalOnUnhandledRejectionHandler(): void {
100+
function _installGlobalOnUnhandledRejectionHandler(client: Client): void {
114101
addGlobalUnhandledRejectionInstrumentationHandler(e => {
115-
const [hub, stackParser, attachStacktrace] = getHubAndOptions();
116-
if (!hub.getIntegration(GlobalHandlers)) {
117-
return;
118-
}
102+
const { stackParser, attachStacktrace } = getOptions();
119103

120-
if (shouldIgnoreOnError()) {
121-
return true;
104+
if (getClient() !== client || shouldIgnoreOnError()) {
105+
return;
122106
}
123107

124108
const error = _getUnhandledRejectionError(e as unknown);
@@ -129,15 +113,13 @@ function _installGlobalOnUnhandledRejectionHandler(): void {
129113

130114
event.level = 'error';
131115

132-
hub.captureEvent(event, {
116+
captureEvent(event, {
133117
originalException: error,
134118
mechanism: {
135119
handled: false,
136120
type: 'onunhandledrejection',
137121
},
138122
});
139-
140-
return;
141123
});
142124
}
143125

@@ -258,12 +240,11 @@ function globalHandlerLog(type: string): void {
258240
DEBUG_BUILD && logger.log(`Global Handler attached: ${type}`);
259241
}
260242

261-
function getHubAndOptions(): [Hub, StackParser, boolean | undefined] {
262-
const hub = getCurrentHub();
263-
const client = hub.getClient<BrowserClient>();
243+
function getOptions(): { stackParser: StackParser; attachStacktrace?: boolean } {
244+
const client = getClient<BrowserClient>();
264245
const options = (client && client.getOptions()) || {
265246
stackParser: () => [],
266247
attachStacktrace: false,
267248
};
268-
return [hub, options.stackParser, options.attachStacktrace];
249+
return options;
269250
}
Lines changed: 64 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import type { EventEnvelope, EventProcessor, Hub, Integration, Transaction } from '@sentry/types';
1+
import { getCurrentScope } from '@sentry/core';
2+
import type { Client, EventEnvelope, EventProcessor, Hub, Integration, Transaction } from '@sentry/types';
23
import type { Profile } from '@sentry/types/src/profiling';
34
import { logger } from '@sentry/utils';
45

@@ -29,6 +30,7 @@ export class BrowserProfilingIntegration implements Integration {
2930

3031
public readonly name: string;
3132

33+
/** @deprecated This is never set. */
3234
public getCurrentHub?: () => Hub;
3335

3436
public constructor() {
@@ -38,12 +40,13 @@ export class BrowserProfilingIntegration implements Integration {
3840
/**
3941
* @inheritDoc
4042
*/
41-
public setupOnce(_addGlobalEventProcessor: (callback: EventProcessor) => void, getCurrentHub: () => Hub): void {
42-
this.getCurrentHub = getCurrentHub;
43+
public setupOnce(_addGlobalEventProcessor: (callback: EventProcessor) => void, _getCurrentHub: () => Hub): void {
44+
// noop
45+
}
4346

44-
const hub = this.getCurrentHub();
45-
const client = hub.getClient();
46-
const scope = hub.getScope();
47+
/** @inheritdoc */
48+
public setup(client: Client): void {
49+
const scope = getCurrentScope();
4750

4851
const transaction = scope.getTransaction();
4952

@@ -53,67 +56,68 @@ export class BrowserProfilingIntegration implements Integration {
5356
}
5457
}
5558

56-
if (client && typeof client.on === 'function') {
57-
client.on('startTransaction', (transaction: Transaction) => {
58-
if (shouldProfileTransaction(transaction)) {
59-
startProfileForTransaction(transaction);
59+
if (typeof client.on !== 'function') {
60+
logger.warn('[Profiling] Client does not support hooks, profiling will be disabled');
61+
return;
62+
}
63+
64+
client.on('startTransaction', (transaction: Transaction) => {
65+
if (shouldProfileTransaction(transaction)) {
66+
startProfileForTransaction(transaction);
67+
}
68+
});
69+
70+
client.on('beforeEnvelope', (envelope): void => {
71+
// if not profiles are in queue, there is nothing to add to the envelope.
72+
if (!getActiveProfilesCount()) {
73+
return;
74+
}
75+
76+
const profiledTransactionEvents = findProfiledTransactionsFromEnvelope(envelope);
77+
if (!profiledTransactionEvents.length) {
78+
return;
79+
}
80+
81+
const profilesToAddToEnvelope: Profile[] = [];
82+
83+
for (const profiledTransaction of profiledTransactionEvents) {
84+
const context = profiledTransaction && profiledTransaction.contexts;
85+
const profile_id = context && context['profile'] && context['profile']['profile_id'];
86+
const start_timestamp = context && context['profile'] && context['profile']['start_timestamp'];
87+
88+
if (typeof profile_id !== 'string') {
89+
DEBUG_BUILD && logger.log('[Profiling] cannot find profile for a transaction without a profile context');
90+
continue;
6091
}
61-
});
6292

63-
client.on('beforeEnvelope', (envelope): void => {
64-
// if not profiles are in queue, there is nothing to add to the envelope.
65-
if (!getActiveProfilesCount()) {
66-
return;
93+
if (!profile_id) {
94+
DEBUG_BUILD && logger.log('[Profiling] cannot find profile for a transaction without a profile context');
95+
continue;
6796
}
6897

69-
const profiledTransactionEvents = findProfiledTransactionsFromEnvelope(envelope);
70-
if (!profiledTransactionEvents.length) {
71-
return;
98+
// Remove the profile from the transaction context before sending, relay will take care of the rest.
99+
if (context && context['profile']) {
100+
delete context.profile;
72101
}
73102

74-
const profilesToAddToEnvelope: Profile[] = [];
75-
76-
for (const profiledTransaction of profiledTransactionEvents) {
77-
const context = profiledTransaction && profiledTransaction.contexts;
78-
const profile_id = context && context['profile'] && context['profile']['profile_id'];
79-
const start_timestamp = context && context['profile'] && context['profile']['start_timestamp'];
80-
81-
if (typeof profile_id !== 'string') {
82-
DEBUG_BUILD && logger.log('[Profiling] cannot find profile for a transaction without a profile context');
83-
continue;
84-
}
85-
86-
if (!profile_id) {
87-
DEBUG_BUILD && logger.log('[Profiling] cannot find profile for a transaction without a profile context');
88-
continue;
89-
}
90-
91-
// Remove the profile from the transaction context before sending, relay will take care of the rest.
92-
if (context && context['profile']) {
93-
delete context.profile;
94-
}
95-
96-
const profile = takeProfileFromGlobalCache(profile_id);
97-
if (!profile) {
98-
DEBUG_BUILD && logger.log(`[Profiling] Could not retrieve profile for transaction: ${profile_id}`);
99-
continue;
100-
}
101-
102-
const profileEvent = createProfilingEvent(
103-
profile_id,
104-
start_timestamp as number | undefined,
105-
profile,
106-
profiledTransaction as ProfiledEvent,
107-
);
108-
if (profileEvent) {
109-
profilesToAddToEnvelope.push(profileEvent);
110-
}
103+
const profile = takeProfileFromGlobalCache(profile_id);
104+
if (!profile) {
105+
DEBUG_BUILD && logger.log(`[Profiling] Could not retrieve profile for transaction: ${profile_id}`);
106+
continue;
111107
}
112108

113-
addProfilesToEnvelope(envelope as EventEnvelope, profilesToAddToEnvelope);
114-
});
115-
} else {
116-
logger.warn('[Profiling] Client does not support hooks, profiling will be disabled');
117-
}
109+
const profileEvent = createProfilingEvent(
110+
profile_id,
111+
start_timestamp as number | undefined,
112+
profile,
113+
profiledTransaction as ProfiledEvent,
114+
);
115+
if (profileEvent) {
116+
profilesToAddToEnvelope.push(profileEvent);
117+
}
118+
}
119+
120+
addProfilesToEnvelope(envelope as EventEnvelope, profilesToAddToEnvelope);
121+
});
118122
}
119123
}

packages/nextjs/src/common/wrapGenerationFunctionWithSentry.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {
22
addTracingExtensions,
33
captureException,
44
continueTrace,
5-
getCurrentHub,
5+
getClient,
66
getCurrentScope,
77
runWithAsyncContext,
88
trace,
@@ -34,7 +34,7 @@ export function wrapGenerationFunctionWithSentry<F extends (...args: any[]) => a
3434
}
3535

3636
let data: Record<string, unknown> | undefined = undefined;
37-
if (getCurrentHub().getClient()?.getOptions().sendDefaultPii) {
37+
if (getClient()?.getOptions().sendDefaultPii) {
3838
const props: unknown = args[0];
3939
const params = props && typeof props === 'object' && 'params' in props ? props.params : undefined;
4040
const searchParams =

0 commit comments

Comments
 (0)