Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/FoxxMD/logging. A typed, opinionated, batteries-included, Pino-based logging solution for backend T foxxmd.github.io/logging
child-logger logging logging-library nodejs pinojs typescript-library
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215import {labelsDisableFromEnv, labelsDisableFromEnvSingleton, labelsEnableFromEnv, labelsEnableFromEnvSingleton, parseLogOptions} from "./funcs.js";import { PinoLoggerOptions, CUSTOM_LEVELS, Logger, LoggerAppExtras, LogLevel, LogLevelStreamEntry, LogOptions, ChildLoggerOptions} from "./types.js";import {buildDestinationFile, buildDestinationRollingFile, buildDestinationStdout} from "./destinations.js";import {pino, levels, stdSerializers} from "pino";
/** * Builds a Logger object for use in your application * * `defaultLevel` must the minimum level ANY stream can log from IE it should be the lowest level any of your streams will possibly log. Recommended to always use `debug`. * * @see Logger * */export const buildLogger = (defaultLevel: LogLevel, streams: LogLevelStreamEntry[], extras: PinoLoggerOptions = {}): Logger => { // TODO maybe implement custom levels //const { levels: extraLevels = {} } = extras; /* pino levels are found at pino/lib/constants.js trace: 10, debug: 20, info: 30, warn: 40, error: 50, fatal: 60
MS custom levels verbose: 25 log: 21 */ const ms = pino.multistream(streams, {levels: {...levels.values, ...CUSTOM_LEVELS}});
const plogger = pino<"verbose" | "log">({ // @ts-ignore mixin: (obj, num, loggerThis: Logger) => { return { labels: loggerThis.labels ?? [] } }, mixinMergeStrategy(mergeObject: Record<any, any>, mixinObject: Record<any, any>) { if(mergeObject.labels === undefined || mixinObject.labels === undefined || mixinObject.labels.length === 0) { return Object.assign(mergeObject, mixinObject); } const runtimeLabels = Array.isArray(mergeObject.labels) ? mergeObject.labels : [mergeObject.labels]; const finalObj = Object.assign(mergeObject, mixinObject); finalObj.labels = [...(mixinObject.labels ?? []), ...runtimeLabels]; return finalObj; }, level: defaultLevel, customLevels: CUSTOM_LEVELS, useOnlyCustomLevels: false, serializers: { err: stdSerializers.err, labels: (labels: any[]) => { // allow dynamic labels return labels.map(x => { if(typeof x === 'function') { try { return x() } catch (e) { return e.message; } } return x;
}).filter(x => x !== null && x !== undefined); }, }, ...extras }, ms) as Logger; plogger.labels = [];
plogger.addLabel = function (value) { if (this.labels === undefined) { this.labels = []; } this.labels.push(value) } return plogger;}
/** * Returns a new logger with the given properties appended to all log objects created by it * * @param parent Logger Parent logger to inherit from * @param labelsVal (any | any[]) Labels to always apply to logs from this logger * @param context object Additional properties to always apply to logs from this logger * @param options ChildLoggerOptions * */export const childLogger = (parent: Logger, labelsVal: any | any[] = [], context: object = {}, options: ChildLoggerOptions = {}): Logger => { const { labelEnable = labelsEnableFromEnvSingleton, labelEnableLevel = process.env.LOG_FILTER_ENABLE_LEVEL ?? 'trace', labelDisable = labelsDisableFromEnvSingleton, labelDisableLevel = process.env.LOG_FILTER_DISABLE_LEVEL ?? 'silent', ...rest } = options;
const newChild = parent.child(context, rest) as Logger; const labels = Array.isArray(labelsVal) ? labelsVal : [labelsVal]; newChild.labels = [...[...(parent.labels ?? [])], ...labels]; newChild.addLabel = function (value) { if (this.labels === undefined) { this.labels = []; } this.labels.push(value); }
if(newChild.level !== labelEnableLevel && labelEnable !== undefined && labelEnable(newChild.labels)) { newChild.level = labelEnableLevel; } else if (newChild.level !== labelDisableLevel && labelDisable !== undefined && labelDisable(newChild.labels)) { newChild.level = labelDisableLevel; } return newChild}/** * A noop (no output) logger for use when testing a component that requires a Logger * * @source * */export const loggerTest = buildLogger('silent', [buildDestinationStdout('trace')]);
/** * A logger that ONLY logs to console at minimum 'debug' level. Useful for logging during startup before a loggerApp has been initialized * * @source * */export const loggerDebug = buildLogger('debug', [buildDestinationStdout('trace')]);
/** * A logger that logs to console at the lowest minimum level, 'trace'. Useful for logging during startup before a loggerApp has been initialized * * @source * */export const loggerTrace = buildLogger('trace', [buildDestinationStdout('trace')]);
/** * A Logger that logs to console and a static file * */export const loggerApp = (config: LogOptions | object = {}, extras?: LoggerAppExtras) => {
const { pretty = {}, destinations = [], pino, } = extras || {};
const options = parseLogOptions(config, extras); const streams: LogLevelStreamEntry[] = [ buildDestinationStdout(options.console, pretty), ...destinations ];
let error: Error; if(options.file.level !== false) { try { const file = buildDestinationFile(options.file.level, {...options.file, ...pretty, append: true}); if (file !== undefined) { streams.push(file); } } catch (e) { error = e; } }
const logger = buildLogger('trace' as LogLevel, streams, pino); if (error !== undefined) { logger.warn(error); } return logger;}
/** * A Logger that logs to console and a rolling file * */export const loggerAppRolling = async (config: LogOptions | object = {}, extras?: LoggerAppExtras) => {
const { pretty = {}, destinations = [], pino, } = extras || {};
const options = parseLogOptions(config, extras); const streams: LogLevelStreamEntry[] = [ buildDestinationStdout(options.console, pretty), ...destinations ];
let error: Error; if(options.file.level !== false) { try { const file = await buildDestinationRollingFile(options.file.level, {...options.file, ...pretty}); if (file !== undefined) { streams.push(file); } } catch (e) { error = e; } } const logger = buildLogger('trace' as LogLevel, streams, pino); if (error !== undefined) { logger.warn(error); } return logger;}