diff options
Diffstat (limited to 'lib/logger/index.ts')
-rw-r--r-- | lib/logger/index.ts | 192 |
1 files changed, 75 insertions, 117 deletions
diff --git a/lib/logger/index.ts b/lib/logger/index.ts index f066e05f97b..a120c4a4584 100644 --- a/lib/logger/index.ts +++ b/lib/logger/index.ts @@ -6,9 +6,8 @@ import upath from 'upath'; import cmdSerializer from './cmd-serializer'; import configSerializer from './config-serializer'; import errSerializer from './err-serializer'; -import { once, reset as onceReset } from './once'; import { RenovateStream } from './pretty-stdout'; -import { getRemappedLevel } from './remap'; +import { RenovateLogger } from './renovate-logger'; import type { BunyanRecord, Logger } from './types'; import { ProblemStream, @@ -17,161 +16,120 @@ import { withSanitizer, } from './utils'; -let logContext: string = getEnv('LOG_CONTEXT') ?? nanoid(); -let curMeta: Record<string, unknown> = {}; - const problems = new ProblemStream(); - let stdoutLevel = validateLogLevel(getEnv('LOG_LEVEL'), 'info'); -const stdout: bunyan.Stream = { - name: 'stdout', - level: stdoutLevel, - stream: process.stdout, -}; export function logLevel(): bunyan.LogLevelString { return stdoutLevel; } -// istanbul ignore if: not testable -if (getEnv('LOG_FORMAT') !== 'json') { - // TODO: typings (#9615) - const prettyStdOut = new RenovateStream() as any; - prettyStdOut.pipe(process.stdout); - stdout.stream = prettyStdOut; - stdout.type = 'raw'; -} - -const bunyanLogger = bunyan.createLogger({ - name: 'renovate', - serializers: { - body: configSerializer, - cmd: cmdSerializer, - config: configSerializer, - migratedConfig: configSerializer, - originalConfig: configSerializer, - presetConfig: configSerializer, - oldConfig: configSerializer, - newConfig: configSerializer, - err: errSerializer, - }, - streams: [ - stdout, - { - name: 'problems', - level: 'warn' as bunyan.LogLevel, - stream: problems as any, - type: 'raw', - }, - ].map(withSanitizer), -}); - -const logFactory = ( - _level: bunyan.LogLevelString, -): ((p1: unknown, p2: unknown) => void) => { - return (p1: any, p2: any): void => { - let level = _level; - if (p2) { - // meta and msg provided - const msg = p2; - const meta: Record<string, unknown> = { logContext, ...curMeta, ...p1 }; - const remappedLevel = getRemappedLevel(msg); - // istanbul ignore if: not testable - if (remappedLevel) { - meta.oldLevel = level; - level = remappedLevel; - } - bunyanLogger[level](meta, msg); - } else if (is.string(p1)) { - // only message provided - const msg = p1; - const meta: Record<string, unknown> = { logContext, ...curMeta }; - const remappedLevel = getRemappedLevel(msg); - // istanbul ignore if: not testable - if (remappedLevel) { - meta.oldLevel = level; - level = remappedLevel; - } - bunyanLogger[level](meta, msg); - } else { - // only meta provided - bunyanLogger[level]({ logContext, ...curMeta, ...p1 }); - } +export function createDefaultStreams( + stdoutLevel: bunyan.LogLevelString, + problems: ProblemStream, + logFile: string | undefined, +): bunyan.Stream[] { + const stdout: bunyan.Stream = { + name: 'stdout', + level: stdoutLevel, + stream: process.stdout, }; -}; - -const loggerLevels: bunyan.LogLevelString[] = [ - 'trace', - 'debug', - 'info', - 'warn', - 'error', - 'fatal', -]; - -export const logger: Logger = { once: { reset: onceReset } } as any; - -loggerLevels.forEach((loggerLevel) => { - logger[loggerLevel] = logFactory(loggerLevel) as never; - - const logOnceFn = (p1: any, p2: any): void => { - once(() => { - const logFn = logger[loggerLevel]; - if (is.undefined(p2)) { - logFn(p1); - } else { - logFn(p1, p2); - } - }, logOnceFn); + + // istanbul ignore if: not testable + if (getEnv('LOG_FORMAT') !== 'json') { + // TODO: typings (#9615) + const prettyStdOut = new RenovateStream() as any; + prettyStdOut.pipe(process.stdout); + stdout.stream = prettyStdOut; + stdout.type = 'raw'; + } + + const problemsStream: bunyan.Stream = { + name: 'problems', + level: 'warn' as bunyan.LogLevel, + stream: problems as any, + type: 'raw', }; - logger.once[loggerLevel] = logOnceFn as never; -}); -const logFile = getEnv('LOG_FILE'); -// istanbul ignore if: not easily testable -if (is.string(logFile)) { - // ensure log file directory exists + // istanbul ignore next: not easily testable + const logFileStream: bunyan.Stream | undefined = is.string(logFile) + ? createLogFileStream(logFile) + : undefined; + + return [stdout, problemsStream, logFileStream].filter( + Boolean, + ) as bunyan.Stream[]; +} + +// istanbul ignore next: not easily testable +function createLogFileStream(logFile: string): bunyan.Stream { + // Ensure log file directory exists const directoryName = upath.dirname(logFile); fs.ensureDirSync(directoryName); - addStream({ + return { name: 'logfile', path: logFile, level: validateLogLevel(getEnv('LOG_FILE_LEVEL'), 'debug'), + }; +} + +function serializedSanitizedLogger(streams: bunyan.Stream[]): bunyan { + return bunyan.createLogger({ + name: 'renovate', + serializers: { + body: configSerializer, + cmd: cmdSerializer, + config: configSerializer, + migratedConfig: configSerializer, + originalConfig: configSerializer, + presetConfig: configSerializer, + oldConfig: configSerializer, + newConfig: configSerializer, + err: errSerializer, + }, + streams: streams.map(withSanitizer), }); } +const defaultStreams = createDefaultStreams( + stdoutLevel, + problems, + getEnv('LOG_FILE'), +); + +const bunyanLogger = serializedSanitizedLogger(defaultStreams); +const logContext = getEnv('LOG_CONTEXT') ?? nanoid(); +const loggerInternal = new RenovateLogger(bunyanLogger, logContext, {}); + +export const logger: Logger = loggerInternal; + export function setContext(value: string): void { - logContext = value; + loggerInternal.logContext = value; } export function getContext(): any { - return logContext; + return loggerInternal.logContext; } // setMeta overrides existing meta, may remove fields if no longer existing export function setMeta(obj: Record<string, unknown>): void { - curMeta = { ...obj }; + loggerInternal.setMeta(obj); } // addMeta overrides or adds fields but does not remove any export function addMeta(obj: Record<string, unknown>): void { - curMeta = { ...curMeta, ...obj }; + loggerInternal.addMeta(obj); } // removeMeta removes the provided fields from meta export function removeMeta(fields: string[]): void { - Object.keys(curMeta).forEach((key) => { - if (fields.includes(key)) { - delete curMeta[key]; - } - }); + loggerInternal.removeMeta(fields); } export /* istanbul ignore next */ function addStream( stream: bunyan.Stream, ): void { - bunyanLogger.addStream(withSanitizer(stream)); + loggerInternal.addStream(stream); } /** |