Skip to content

Commit 39f404d

Browse files
committed
ref: Avoid using global singleton for logger
1 parent e3dda4c commit 39f404d

File tree

5 files changed

+42
-29
lines changed

5 files changed

+42
-29
lines changed

packages/hub/test/scope.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ describe('Scope', () => {
99
afterEach(() => {
1010
jest.resetAllMocks();
1111
jest.useRealTimers();
12+
GLOBAL_OBJ.__SENTRY__ = GLOBAL_OBJ.__SENTRY__ || {};
1213
GLOBAL_OBJ.__SENTRY__.globalEventProcessors = undefined;
1314
});
1415

packages/integrations/test/captureconsole.test.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
/* eslint-disable @typescript-eslint/unbound-method */
22
import type { Event, Hub, Integration } from '@sentry/types';
33
import type { ConsoleLevel } from '@sentry/utils';
4-
import { addInstrumentationHandler, CONSOLE_LEVELS, GLOBAL_OBJ, originalConsoleMethods } from '@sentry/utils';
4+
import {
5+
addInstrumentationHandler,
6+
CONSOLE_LEVELS,
7+
GLOBAL_OBJ,
8+
originalConsoleMethods,
9+
resetInstrumentationHandlers,
10+
} from '@sentry/utils';
511

612
import { CaptureConsole } from '../src/captureconsole';
713

@@ -54,6 +60,8 @@ describe('CaptureConsole setup', () => {
5460
CONSOLE_LEVELS.forEach(key => {
5561
originalConsoleMethods[key] = _originalConsoleMethods[key];
5662
});
63+
64+
resetInstrumentationHandlers();
5765
});
5866

5967
describe('monkeypatching', () => {

packages/replay/test/mocks/resetSdkMock.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import type { EventProcessor } from '@sentry/types';
2+
import { getGlobalSingleton, resetInstrumentationHandlers } from '@sentry/utils';
3+
14
import type { Replay as ReplayIntegration } from '../../src';
25
import type { ReplayContainer } from '../../src/replay';
36
import type { RecordMock } from './../index';
@@ -17,9 +20,11 @@ export async function resetSdkMock({ replayOptions, sentryOptions, autoStart }:
1720
jest.setSystemTime(new Date(BASE_TIMESTAMP));
1821
jest.clearAllMocks();
1922
jest.resetModules();
20-
// NOTE: The listeners added to `addInstrumentationHandler` are leaking
21-
// @ts-ignore Don't know if there's a cleaner way to clean up old event processors
22-
globalThis.__SENTRY__.globalEventProcessors = [];
23+
24+
// Clear all handlers that have been registered
25+
resetInstrumentationHandlers();
26+
getGlobalSingleton<EventProcessor[]>('globalEventProcessors', () => []).length = 0;
27+
2328
const SentryUtils = await import('@sentry/utils');
2429
jest.spyOn(SentryUtils, 'addInstrumentationHandler').mockImplementation((type, handler: (args: any) => any) => {
2530
if (type === 'dom') {

packages/utils/src/instrument.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,16 @@ export function addInstrumentationHandler(type: InstrumentHandlerType, callback:
9494
instrument(type);
9595
}
9696

97+
/**
98+
* Reset all instrumentation handlers.
99+
* This can be used by tests to ensure we have a clean slate of instrumentation handlers.
100+
*/
101+
export function resetInstrumentationHandlers(): void {
102+
Object.keys(handlers).forEach(key => {
103+
handlers[key as InstrumentHandlerType] = undefined;
104+
});
105+
}
106+
97107
/** JSDoc */
98108
function triggerHandlers(type: InstrumentHandlerType, data: any): void {
99109
if (!type || !handlers[type]) {

packages/utils/src/logger.ts

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import type { WrappedFunction } from '@sentry/types';
2-
3-
import { getGlobalSingleton, GLOBAL_OBJ } from './worldwide';
1+
import { originalConsoleMethods } from './instrument';
2+
import { GLOBAL_OBJ } from './worldwide';
43

54
/** Prefix for logging strings */
65
const PREFIX = 'Sentry Logger ';
@@ -9,7 +8,7 @@ export const CONSOLE_LEVELS = ['debug', 'info', 'warn', 'error', 'log', 'assert'
98
export type ConsoleLevel = (typeof CONSOLE_LEVELS)[number];
109

1110
type LoggerMethod = (...args: unknown[]) => void;
12-
type LoggerConsoleMethods = Record<(typeof CONSOLE_LEVELS)[number], LoggerMethod>;
11+
type LoggerConsoleMethods = Record<ConsoleLevel, LoggerMethod>;
1312

1413
/** JSDoc */
1514
interface Logger extends LoggerConsoleMethods {
@@ -28,26 +27,24 @@ export function consoleSandbox<T>(callback: () => T): T {
2827
return callback();
2928
}
3029

31-
const originalConsole = GLOBAL_OBJ.console as Console & Record<string, unknown>;
32-
const wrappedLevels: Partial<LoggerConsoleMethods> = {};
30+
const console = GLOBAL_OBJ.console as Console;
31+
const wrappedFuncs: Partial<LoggerConsoleMethods> = {};
32+
33+
const wrappedLevels = Object.keys(originalConsoleMethods) as ConsoleLevel[];
3334

3435
// Restore all wrapped console methods
35-
CONSOLE_LEVELS.forEach(level => {
36-
// TODO(v7): Remove this check as it's only needed for Node 6
37-
const originalWrappedFunc =
38-
originalConsole[level] && (originalConsole[level] as WrappedFunction).__sentry_original__;
39-
if (level in originalConsole && originalWrappedFunc) {
40-
wrappedLevels[level] = originalConsole[level] as LoggerConsoleMethods[typeof level];
41-
originalConsole[level] = originalWrappedFunc as Console[typeof level];
42-
}
36+
wrappedLevels.forEach(level => {
37+
const originalConsoleMethod = originalConsoleMethods[level] as LoggerMethod;
38+
wrappedFuncs[level] = console[level] as LoggerMethod | undefined;
39+
console[level] = originalConsoleMethod;
4340
});
4441

4542
try {
4643
return callback();
4744
} finally {
4845
// Revert restoration to wrapped state
49-
Object.keys(wrappedLevels).forEach(level => {
50-
originalConsole[level] = wrappedLevels[level as (typeof CONSOLE_LEVELS)[number]];
46+
wrappedLevels.forEach(level => {
47+
console[level] = wrappedFuncs[level] as LoggerMethod;
5148
});
5249
}
5350
}
@@ -83,12 +80,4 @@ function makeLogger(): Logger {
8380
return logger as Logger;
8481
}
8582

86-
// Ensure we only have a single logger instance, even if multiple versions of @sentry/utils are being used
87-
let logger: Logger;
88-
if (__DEBUG_BUILD__) {
89-
logger = getGlobalSingleton('logger', makeLogger);
90-
} else {
91-
logger = makeLogger();
92-
}
93-
94-
export { logger };
83+
export const logger = makeLogger();

0 commit comments

Comments
 (0)