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
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162import {parseLogOptions} from "./funcs.js";import { PinoLoggerOptions, CUSTOM_LEVELS, Logger, LoggerAppExtras, LogLevel, LogLevelStreamEntry, LogOptions} from "./types.js";import {buildDestinationFile, buildDestinationRollingFile, buildDestinationStdout} from "./destinations.js";import {pino} 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 = {} } = extras;
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, ...extras }, pino.multistream(streams)) 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 object * */export const childLogger = (parent: Logger, labelsVal: any | any[] = [], context: object = {}, options = {}): Logger => { const newChild = parent.child(context, options) 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); } return newChild}/** * A noop (no output) logger for use when testing a component that requires a Logger * * @source * */export const loggerTest = buildLogger('silent', [buildDestinationStdout('debug')]);
/** * 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('debug')]);
/** * 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('debug' 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('debug' as LogLevel, streams, pino); if (error !== undefined) { logger.warn(error); } return logger;}