github.com/ethereum-optimism/optimism@v1.7.2/packages/common-ts/src/common/logger.ts (about) 1 import pino, { LoggerOptions as PinoLoggerOptions } from 'pino' 2 import pinoms, { Streams } from 'pino-multi-stream' 3 import { createWriteStream } from 'pino-sentry' 4 import { NodeOptions } from '@sentry/node' 5 6 export const logLevels = [ 7 'trace', 8 'debug', 9 'info', 10 'warn', 11 'error', 12 'fatal', 13 ] as const 14 export type LogLevel = (typeof logLevels)[number] 15 16 export interface LoggerOptions { 17 name: string 18 level?: LogLevel 19 sentryOptions?: NodeOptions 20 streams?: Streams 21 } 22 23 /** 24 * Temporary wrapper class to maintain earlier module interface. 25 */ 26 export class Logger { 27 options: LoggerOptions 28 inner: pino.Logger 29 30 constructor(options: LoggerOptions) { 31 this.options = options 32 33 const loggerOptions: PinoLoggerOptions = { 34 name: options.name, 35 36 level: options.level || 'debug', 37 38 // Remove pid and hostname considering production runs inside docker 39 base: null, 40 } 41 42 let loggerStreams: Streams = [{ stream: process.stdout }] 43 if (options.sentryOptions) { 44 loggerStreams.push({ 45 level: 'error', 46 stream: createWriteStream({ 47 ...options.sentryOptions, 48 stackAttributeKey: 'err', 49 }), 50 }) 51 } 52 if (options.streams) { 53 loggerStreams = loggerStreams.concat(options.streams) 54 } 55 56 this.inner = pino(loggerOptions, pinoms.multistream(loggerStreams)) 57 } 58 59 child(bindings: pino.Bindings): Logger { 60 const inner = this.inner.child(bindings) 61 const logger = new Logger(this.options) 62 logger.inner = inner 63 return logger 64 } 65 66 trace(msg: string, o?: object, ...args: any[]): void { 67 if (o) { 68 this.inner.trace(o, msg, ...args) 69 } else { 70 this.inner.trace(msg, ...args) 71 } 72 } 73 74 debug(msg: string, o?: object, ...args: any[]): void { 75 if (o) { 76 this.inner.debug(o, msg, ...args) 77 } else { 78 this.inner.debug(msg, ...args) 79 } 80 } 81 82 info(msg: string, o?: object, ...args: any[]): void { 83 if (o) { 84 this.inner.info(o, msg, ...args) 85 } else { 86 this.inner.info(msg, ...args) 87 } 88 } 89 90 warn(msg: string, o?: object, ...args: any[]): void { 91 if (o) { 92 this.inner.warn(o, msg, ...args) 93 } else { 94 this.inner.warn(msg, ...args) 95 } 96 } 97 98 warning(msg: string, o?: object, ...args: any[]): void { 99 if (o) { 100 this.inner.warn(o, msg, ...args) 101 } else { 102 this.inner.warn(msg, ...args) 103 } 104 } 105 106 error(msg: string, o?: object, ...args: any[]): void { 107 if (o) { 108 // Formatting error log for Sentry 109 const context = { 110 extra: { ...o }, 111 } 112 this.inner.error(context, msg, ...args) 113 } else { 114 this.inner.error(msg, ...args) 115 } 116 } 117 118 fatal(msg: string, o?: object, ...args: any[]): void { 119 if (o) { 120 const context = { 121 extra: { ...o }, 122 } 123 this.inner.fatal(context, msg, ...args) 124 } else { 125 this.inner.fatal(msg, ...args) 126 } 127 } 128 }