Skip to content

Commit b1f4fbc

Browse files
authored
feat(utils): Convert Logger class to functions (#4863)
Removes the logger class in favour of a function + object. They are functionality identical. Also refactors the `consoleSandbox` function, mainly adjusting the types.
1 parent 329e033 commit b1f4fbc

File tree

2 files changed

+58
-77
lines changed

2 files changed

+58
-77
lines changed

packages/integrations/src/captureconsole.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ export class CaptureConsole implements Integration {
1818
/**
1919
* @inheritDoc
2020
*/
21-
private readonly _levels: string[] = CONSOLE_LEVELS;
21+
private readonly _levels: typeof CONSOLE_LEVELS = CONSOLE_LEVELS;
2222

2323
/**
2424
* @inheritDoc
2525
*/
26-
public constructor(options: { levels?: string[] } = {}) {
26+
public constructor(options: { levels?: typeof CONSOLE_LEVELS } = {}) {
2727
if (options.levels) {
2828
this._levels = options.levels;
2929
}

packages/utils/src/logger.ts

Lines changed: 56 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,118 +1,99 @@
1-
/* eslint-disable @typescript-eslint/no-explicit-any */
21
import { WrappedFunction } from '@sentry/types';
32

43
import { IS_DEBUG_BUILD } from './flags';
5-
import { getGlobalObject } from './global';
4+
import { getGlobalObject, getGlobalSingleton } from './global';
65

76
// TODO: Implement different loggers for different environments
87
const global = getGlobalObject<Window | NodeJS.Global>();
98

109
/** Prefix for logging strings */
1110
const PREFIX = 'Sentry Logger ';
1211

13-
export const CONSOLE_LEVELS = ['debug', 'info', 'warn', 'error', 'log', 'assert'];
12+
export const CONSOLE_LEVELS = ['debug', 'info', 'warn', 'error', 'log', 'assert'] as const;
13+
14+
type LoggerMethod = (...args: unknown[]) => void;
15+
type LoggerConsoleMethods = Record<typeof CONSOLE_LEVELS[number], LoggerMethod>;
1416

1517
/** JSDoc */
16-
interface ExtensibleConsole extends Console {
17-
[key: string]: any;
18+
interface Logger extends LoggerConsoleMethods {
19+
disable(): void;
20+
enable(): void;
1821
}
1922

2023
/**
21-
* Temporarily unwrap `console.log` and friends in order to perform the given callback using the original methods.
22-
* Restores wrapping after the callback completes.
24+
* Temporarily disable sentry console instrumentations.
2325
*
2426
* @param callback The function to run against the original `console` messages
2527
* @returns The results of the callback
2628
*/
27-
export function consoleSandbox(callback: () => any): any {
29+
export function consoleSandbox<T>(callback: () => T): T {
2830
const global = getGlobalObject<Window>();
2931

3032
if (!('console' in global)) {
3133
return callback();
3234
}
3335

34-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
35-
const originalConsole = (global as any).console as ExtensibleConsole;
36-
const wrappedLevels: { [key: string]: any } = {};
36+
const originalConsole = global.console as Console & Record<string, unknown>;
37+
const wrappedLevels: Partial<LoggerConsoleMethods> = {};
3738

3839
// Restore all wrapped console methods
3940
CONSOLE_LEVELS.forEach(level => {
40-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
41-
if (level in (global as any).console && (originalConsole[level] as WrappedFunction).__sentry_original__) {
42-
wrappedLevels[level] = originalConsole[level] as WrappedFunction;
43-
originalConsole[level] = (originalConsole[level] as WrappedFunction).__sentry_original__;
41+
// TODO(v7): Remove this check as it's only needed for Node 6
42+
const originalWrappedFunc =
43+
originalConsole[level] && (originalConsole[level] as WrappedFunction).__sentry_original__;
44+
if (level in global.console && originalWrappedFunc) {
45+
wrappedLevels[level] = originalConsole[level] as LoggerConsoleMethods[typeof level];
46+
originalConsole[level] = originalWrappedFunc as Console[typeof level];
4447
}
4548
});
4649

47-
// Perform callback manipulations
48-
const result = callback();
49-
50-
// Revert restoration to wrapped state
51-
Object.keys(wrappedLevels).forEach(level => {
52-
originalConsole[level] = wrappedLevels[level];
53-
});
54-
55-
return result;
56-
}
57-
58-
/** JSDoc */
59-
class Logger {
60-
/** JSDoc */
61-
private _enabled: boolean;
62-
63-
/** JSDoc */
64-
public constructor() {
65-
this._enabled = false;
66-
}
67-
68-
/** JSDoc */
69-
public disable(): void {
70-
this._enabled = false;
71-
}
72-
73-
/** JSDoc */
74-
public enable(): void {
75-
this._enabled = true;
76-
}
77-
78-
/** JSDoc */
79-
public log(...args: any[]): void {
80-
if (!this._enabled) {
81-
return;
82-
}
83-
consoleSandbox(() => {
84-
global.console.log(`${PREFIX}[Log]:`, ...args);
50+
try {
51+
return callback();
52+
} finally {
53+
// Revert restoration to wrapped state
54+
Object.keys(wrappedLevels).forEach(level => {
55+
originalConsole[level] = wrappedLevels[level as typeof CONSOLE_LEVELS[number]];
8556
});
8657
}
58+
}
8759

88-
/** JSDoc */
89-
public warn(...args: any[]): void {
90-
if (!this._enabled) {
91-
return;
92-
}
93-
consoleSandbox(() => {
94-
global.console.warn(`${PREFIX}[Warn]:`, ...args);
60+
function makeLogger(): Logger {
61+
let enabled = false;
62+
const logger: Partial<Logger> = {
63+
enable: () => {
64+
enabled = true;
65+
},
66+
disable: () => {
67+
enabled = false;
68+
},
69+
};
70+
71+
if (IS_DEBUG_BUILD) {
72+
CONSOLE_LEVELS.forEach(name => {
73+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
74+
logger[name] = (...args: any[]) => {
75+
if (enabled) {
76+
consoleSandbox(() => {
77+
global.console[name](`${PREFIX}[${name}]:`, ...args);
78+
});
79+
}
80+
};
9581
});
96-
}
97-
98-
/** JSDoc */
99-
public error(...args: any[]): void {
100-
if (!this._enabled) {
101-
return;
102-
}
103-
consoleSandbox(() => {
104-
global.console.error(`${PREFIX}[Error]:`, ...args);
82+
} else {
83+
CONSOLE_LEVELS.forEach(name => {
84+
logger[name] = () => undefined;
10585
});
10686
}
107-
}
10887

109-
const sentryGlobal = global.__SENTRY__ || {};
110-
const logger = (sentryGlobal.logger as Logger) || new Logger();
88+
return logger as Logger;
89+
}
11190

91+
// Ensure we only have a single logger instance, even if multiple versions of @sentry/utils are being used
92+
let logger: Logger;
11293
if (IS_DEBUG_BUILD) {
113-
// Ensure we only have a single logger instance, even if multiple versions of @sentry/utils are being used
114-
sentryGlobal.logger = logger;
115-
global.__SENTRY__ = sentryGlobal;
94+
logger = getGlobalSingleton('logger', makeLogger);
95+
} else {
96+
logger = makeLogger();
11697
}
11798

11899
export { logger };

0 commit comments

Comments
 (0)