Skip to content

Commit 4d489e5

Browse files
committed
feat(utils): Convert Logger class to functions
1 parent 393962b commit 4d489e5

File tree

2 files changed

+56
-77
lines changed

2 files changed

+56
-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: 54 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,118 +1,97 @@
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+
const originalWrappedFunc = (originalConsole[level] as WrappedFunction).__sentry_original__;
42+
if (level in global.console && originalWrappedFunc) {
43+
wrappedLevels[level] = originalConsole[level] as LoggerConsoleMethods[typeof level];
44+
originalConsole[level] = originalWrappedFunc as Console[typeof level];
4445
}
4546
});
4647

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);
48+
try {
49+
return callback();
50+
} finally {
51+
// Revert restoration to wrapped state
52+
Object.keys(wrappedLevels).forEach(level => {
53+
originalConsole[level] = wrappedLevels[level as typeof CONSOLE_LEVELS[number]];
8554
});
8655
}
56+
}
8757

88-
/** JSDoc */
89-
public warn(...args: any[]): void {
90-
if (!this._enabled) {
91-
return;
92-
}
93-
consoleSandbox(() => {
94-
global.console.warn(`${PREFIX}[Warn]:`, ...args);
58+
function makeLogger(): Logger {
59+
let enabled = false;
60+
const logger: Partial<Logger> = {
61+
enable: () => {
62+
enabled = true;
63+
},
64+
disable: () => {
65+
enabled = false;
66+
},
67+
};
68+
69+
if (IS_DEBUG_BUILD) {
70+
CONSOLE_LEVELS.forEach(name => {
71+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
72+
logger[name] = (...args: any[]) => {
73+
if (enabled) {
74+
consoleSandbox(() => {
75+
global.console[name](`${PREFIX}[${name}]:`, ...args);
76+
});
77+
}
78+
};
9579
});
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);
80+
} else {
81+
CONSOLE_LEVELS.forEach(name => {
82+
logger[name] = () => undefined;
10583
});
10684
}
107-
}
10885

109-
const sentryGlobal = global.__SENTRY__ || {};
110-
const logger = (sentryGlobal.logger as Logger) || new Logger();
86+
return logger as Logger;
87+
}
11188

89+
// Ensure we only have a single logger instance, even if multiple versions of @sentry/utils are being used
90+
let logger: Logger;
11291
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;
92+
logger = getGlobalSingleton('logger', makeLogger);
93+
} else {
94+
logger = makeLogger();
11695
}
11796

11897
export { logger };

0 commit comments

Comments
 (0)