diff options
Diffstat (limited to 'lib/logger/renovate-logger.ts')
-rw-r--r-- | lib/logger/renovate-logger.ts | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/lib/logger/renovate-logger.ts b/lib/logger/renovate-logger.ts new file mode 100644 index 00000000000..096b763ec42 --- /dev/null +++ b/lib/logger/renovate-logger.ts @@ -0,0 +1,156 @@ +import is from '@sindresorhus/is'; +import type * as bunyan from 'bunyan'; +import { once, reset as onceReset } from './once'; +import { getRemappedLevel } from './remap'; +import type { Logger } from './types'; +import { getMessage, toMeta, withSanitizer } from './utils'; + +const loggerLevels: bunyan.LogLevelString[] = [ + 'trace', + 'debug', + 'info', + 'warn', + 'error', + 'fatal', +]; + +type LoggerFunction = (p1: string | Record<string, any>, p2?: string) => void; + +export class RenovateLogger implements Logger { + readonly logger: Logger = { once: { reset: onceReset } } as any; + readonly once = this.logger.once; + + constructor( + private readonly bunyanLogger: bunyan, + private context: string, + private meta: Record<string, unknown>, + ) { + for (const level of loggerLevels) { + this.logger[level] = this.logFactory(level) as never; + this.logger.once[level] = this.logOnceFn(level); + } + } + + trace(p1: string): void; + trace(p1: Record<string, any>, p2?: string): void; + trace(p1: string | Record<string, any>, p2?: string): void { + this.log('trace', p1, p2); + } + + debug(p1: string): void; + debug(p1: Record<string, any>, p2?: string): void; + debug(p1: string | Record<string, any>, p2?: string): void { + this.log('debug', p1, p2); + } + + info(p1: string): void; + info(p1: Record<string, any>, p2?: string): void; + info(p1: string | Record<string, any>, p2?: string): void { + this.log('info', p1, p2); + } + + warn(p1: string): void; + warn(p1: Record<string, any>, p2?: string): void; + warn(p1: string | Record<string, any>, p2?: string): void { + this.log('warn', p1, p2); + } + + error(p1: string): void; + error(p1: Record<string, any>, p2?: string): void; + error(p1: string | Record<string, any>, p2?: string): void { + this.log('error', p1, p2); + } + + fatal(p1: string): void; + fatal(p1: Record<string, any>, p2?: string): void; + fatal(p1: string | Record<string, any>, p2?: string): void { + this.log('fatal', p1, p2); + } + + addStream(stream: bunyan.Stream): void { + this.bunyanLogger.addStream(withSanitizer(stream)); + } + + childLogger(): RenovateLogger { + return new RenovateLogger( + this.bunyanLogger.child({}), + this.context, + this.meta, + ); + } + + get logContext(): string { + return this.context; + } + + set logContext(context: string) { + this.context = context; + } + + setMeta(obj: Record<string, unknown>): void { + this.meta = { ...obj }; + } + + addMeta(obj: Record<string, unknown>): void { + this.meta = { ...this.meta, ...obj }; + } + + removeMeta(fields: string[]): void { + for (const key of Object.keys(this.meta)) { + if (fields.includes(key)) { + delete this.meta[key]; + } + } + } + + private logFactory(_level: bunyan.LogLevelString): LoggerFunction { + return (p1: string | Record<string, any>, p2?: string): void => { + const meta: Record<string, unknown> = { + logContext: this.context, + ...this.meta, + ...toMeta(p1), + }; + const msg = getMessage(p1, p2); + let level = _level; + + if (is.string(msg)) { + const remappedLevel = getRemappedLevel(msg); + // istanbul ignore if: not easily testable + if (remappedLevel) { + meta.oldLevel = level; + level = remappedLevel; + } + this.bunyanLogger[level](meta, msg); + } else { + this.bunyanLogger[level](meta); + } + }; + } + + private logOnceFn(level: bunyan.LogLevelString): LoggerFunction { + const logOnceFn = (p1: string | Record<string, any>, p2?: string): void => { + once(() => { + const logFn = this[level].bind(this); // bind to the instance. + if (is.string(p1)) { + logFn(p1); + } else { + logFn(p1, p2); + } + }, logOnceFn); + }; + return logOnceFn; + } + + private log( + level: bunyan.LogLevelString, + p1: string | Record<string, any>, + p2?: string, + ): void { + const logFn = this.logger[level]; + if (is.string(p1)) { + logFn(p1); + } else { + logFn(p1, p2); + } + } +} |