UNPKG

@spot-meetings/backend-logger

Version:
144 lines (122 loc) â€Ē 3.49 kB
/* eslint-disable no-bitwise */ import { format as formatDate } from 'date-fns' import colorizer from 'json-colorizer' import winston from 'winston' import chalk from 'chalk' const { timestamp, splat, json, errors, combine } = winston.format /** * @see https://github.com/winstonjs/winston#logging */ export enum LogLevel { Error = 'error', Warn = 'warn', Info = 'info', Http = 'http', Verbose = 'verbose', Debug = 'debug', Silly = 'silly', } export enum LogOutput { Summary = 'summary', Details = 'details', Silent = 'silent', Raw = 'raw', } export const logIcons = new Map<LogLevel, string>([ [LogLevel.Error, 'ðŸ’Ĩ'], [LogLevel.Warn, '🛑'], [LogLevel.Info, '🔔'], [LogLevel.Http, '🚛'], [LogLevel.Verbose, '💎'], [LogLevel.Debug, '🐛'], [LogLevel.Silly, 'ðŸĪŠ'], ]) export interface LogReporter { readonly version: string readonly id: string readonly ip: string } export interface LogData { // Default info readonly reporter: LogReporter readonly timestamp: string // Optional error stack stack?: string // Optional additional info [prop: string]: any } const colors = { STRING_LITERAL: 'white', BOOLEAN_LITERAL: 'blue', NUMBER_LITERAL: 'cyan', NULL_LITERAL: 'magenta', STRING_KEY: 'white.dim', } const getLogOutputType = (value: LogOutput = LogOutput.Raw) => { if (!Object.values(LogOutput).includes(value)) { // eslint-disable-next-line no-console console.warn( `The provided LOG_OUTPUT "${value}" is not supported. Defaulting to "${LogOutput.Raw}".`, ) return LogOutput.Raw } return value } const getLogLevel = (value: LogLevel = LogLevel.Info) => { if (!Object.values(LogLevel).includes(value)) { // eslint-disable-next-line no-console console.warn( `The provided LOG_LEVEL "${value}" is not supported. Defaulting to "${LogLevel.Info}".`, ) return LogLevel.Info } return value } const getReadableFormatter = (details = false) => winston.format.printf((info) => { const { level, message, timestamp: ts } = info const label = logIcons.get(level as LogLevel) || '❔' const time = chalk.yellow(formatDate(new Date(ts), '[HH:mm:ss.SSS]')) const header = chalk.bold(`${time} ${label} ${message}`) const parts = [header] if (details) { parts.push( colorizer(JSON.stringify(info), { pretty: true, colors, }).replace(/\\n/g, '\n'), // To avoid having "\n" in the stack log ) } return parts.join('\n') }) /** * SpotLogger Class */ export const createLogger = (id: string, ip: string, version: string) => { const { LOG_OUTPUT, LOG_LEVEL, RUNTIME_ENV, NODE_ENV } = process.env const outputType = getLogOutputType(LOG_OUTPUT as LogOutput) const logLevel = getLogLevel(LOG_LEVEL as LogLevel) const formats = [errors({ stack: true }), timestamp(), splat(), json()] // If any of the formatted output flags are set we pretty print. if ([LogOutput.Details, LogOutput.Summary].includes(outputType)) { formats.push(getReadableFormatter(outputType === LogOutput.Details)) } return winston.createLogger({ format: combine(...formats), level: logLevel, transports: [ new winston.transports.Console({ silent: outputType === LogOutput.Silent, }), ], defaultMeta: { environment: RUNTIME_ENV || NODE_ENV, type: 'log', reporter: { version, id, ip, }, }, }) }