From c5327f74d42a811e4a924b0f72b8cd8aaa0d0b71 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Thu, 18 May 2023 21:41:32 +0200 Subject: [PATCH] refactor to check log levels This will eventually allow the log level to be configured. For now, the explicit debug flag does not work. --- packages/backend/src/services/logger.ts | 112 ++++++++++++++++-------- 1 file changed, 77 insertions(+), 35 deletions(-) diff --git a/packages/backend/src/services/logger.ts b/packages/backend/src/services/logger.ts index a3bfc8a0a..ea5d321fa 100644 --- a/packages/backend/src/services/logger.ts +++ b/packages/backend/src/services/logger.ts @@ -12,7 +12,14 @@ type Domain = { color?: KEYWORD; }; -type Level = 'error' | 'success' | 'warning' | 'debug' | 'info'; +export const LEVELS = { + error: 0, + warning: 1, + success: 2, + info: 3, + debug: 4, +}; +export type Level = LEVELS[keyof LEVELS]; /** * Class that facilitates recording log messages to the console and optionally a syslog server. @@ -22,6 +29,10 @@ export default class Logger { private parentLogger: Logger | null = null; private store: boolean; private syslogClient: SyslogPro.RFC5424 | null = null; + /** + * Messages below this level will be discarded. + */ + private minLevel: Level; /** * Create a logger instance. @@ -29,12 +40,13 @@ export default class Logger { * @param color Log message color * @param store Whether to store messages */ - constructor(domain: string, color?: KEYWORD, store = true) { + constructor(domain: string, color?: KEYWORD, store = true, minLevel: Level = LEVELS.info) { this.domain = { name: domain, color, }; this.store = store; + this.minLevel = minLevel; if (config.syslog) { this.syslogClient = new SyslogPro.RFC5424({ @@ -58,16 +70,29 @@ export default class Logger { * @param store Whether to store messages * @returns A Logger instance whose parent logger is this instance. */ - public createSubLogger(domain: string, color?: KEYWORD, store = true): Logger { - const logger = new Logger(domain, color, store); + public createSubLogger(domain: string, color?: KEYWORD, store = true, minLevel: Level = LEVELS.info): Logger { + const logger = new Logger(domain, color, store, minLevel); logger.parentLogger = this; return logger; } + /** + * Log a message. + * @param level Indicates the level of this particular message. If it is + * less than the minimum level configured, the message will be discarded. + * @param message The message to be logged. + * @param important Whether to highlight this message as especially important. + * @param subDomains Names of sub-loggers to be added. + */ private log(level: Level, message: string, data?: Record | null, important = false, subDomains: Domain[] = [], _store = true): void { if (envOption.quiet) return; - const store = _store && this.store && (level !== 'debug'); + const store = _store && this.store; + // Check against the configured log level. + if (level < this.minLevel) return; + + // If this logger has a parent logger, delegate the actual logging to it, + // so the parent domain(s) will be logged properly. if (this.parentLogger) { this.parentLogger.log(level, message, data, important, [this.domain].concat(subDomains), store); return; @@ -75,34 +100,53 @@ export default class Logger { const time = dateFormat(new Date(), 'HH:mm:ss'); const worker = cluster.isPrimary ? '*' : cluster.worker?.id; - const l = - level === 'error' ? important ? chalk.bgRed.white('ERR ') : chalk.red('ERR ') : - level === 'warning' ? chalk.yellow('WARN') : - level === 'success' ? important ? chalk.bgGreen.white('DONE') : chalk.green('DONE') : - level === 'debug' ? chalk.gray('VERB') : - chalk.blue('INFO'); const domains = [this.domain].concat(subDomains).map(d => d.color ? chalk.rgb(...convertColor.keyword.rgb(d.color))(d.name) : chalk.white(d.name)); - const m = - level === 'error' ? chalk.red(message) : - level === 'warning' ? chalk.yellow(message) : - level === 'success' ? chalk.green(message) : - level === 'debug' ? chalk.gray(message) : - message; - let log = `${l} ${worker}\t[${domains.join(' ')}]\t${m}`; + let levelDisplay; + let messageDisplay; + switch (level) { + case LEVELS.error: + if (important) { + levelDisplay = chalk.bgRed.white('ERR '); + } else { + levelDisplay = chalk.red('ERR '); + } + messageDisplay = chalk.red(message); + break; + case LEVELS.warning: + levelDisplay = chalk.yellow('WARN'); + messageDisplay = chalk.yellow(message); + break; + case LEVELS.success: + if (important) { + levelDisplay = chalk.bgGreen.white('DONE'); + } else { + levelDisplay = chalk.green('DONE'); + } + messageDisplay = chalk.green(message); + break; + case LEVELS.info: + levelDisplay = chalk.blue('INFO'); + messageDisplay = message; + break; + case LEVELS.debug: default: + levelDisplay = chalk.gray('VERB'); + messageDisplay = chalk.gray(message); + break; + } + + let log = `${levelDisplay} ${worker}\t[${domains.join(' ')}]\t${messageDisplay}`; if (envOption.withLogTime) log = chalk.gray(time) + ' ' + log; console.log(important ? chalk.bold(log) : log); - if (store) { - if (this.syslogClient) { - const send = - level === 'error' ? this.syslogClient.error : - level === 'warning' ? this.syslogClient.warning : - this.syslogClient.info; + if (store && this.syslogClient) { + const send = + level === LEVELS.error ? this.syslogClient.error : + level === LEVELS.warning ? this.syslogClient.warning : + this.syslogClient.info; - send.bind(this.syslogClient)(message).catch(() => {}); - } + send.bind(this.syslogClient)(message).catch(() => {}); } } @@ -116,11 +160,11 @@ export default class Logger { public error(err: string | Error, data: Record = {}, important = false): void { if (err instanceof Error) { data.e = err; - this.log('error', err.toString(), data, important); + this.log(LEVELS.error, err.toString(), data, important); } else if (typeof err === 'object') { - this.log('error', `${(err as any).message || (err as any).name || err}`, data, important); + this.log(LEVELS.error, `${(err as any).message || (err as any).name || err}`, data, important); } else { - this.log('error', `${err}`, data, important); + this.log(LEVELS.error, `${err}`, data, important); } } @@ -132,7 +176,7 @@ export default class Logger { * @param important Whether this warning is important */ public warn(message: string, data?: Record | null, important = false): void { - this.log('warning', message, data, important); + this.log(LEVELS.warning, message, data, important); } /** @@ -143,7 +187,7 @@ export default class Logger { * @param important Whether this success message is important */ public succ(message: string, data?: Record | null, important = false): void { - this.log('success', message, data, important); + this.log(LEVELS.success, message, important); } /** @@ -154,9 +198,7 @@ export default class Logger { * @param important Whether this debug message is important */ public debug(message: string, data?: Record | null, important = false): void { - if (process.env.NODE_ENV !== 'production' || envOption.verbose) { - this.log('debug', message, data, important); - } + this.log(LEVELS.debug, message, data, important); } /** @@ -167,6 +209,6 @@ export default class Logger { * @param important Whether this info message is important */ public info(message: string, data?: Record | null, important = false): void { - this.log('info', message, data, important); + this.log(LEVELS.info, message, data, important); } }