You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					359 lines
				
				10 KiB
			
		
		
			
		
	
	
					359 lines
				
				10 KiB
			| 
											3 years ago
										 | 'use strict' | ||
|  | 
 | ||
|  | const format = require('quick-format-unescaped') | ||
|  | 
 | ||
|  | module.exports = pino | ||
|  | 
 | ||
|  | const _console = pfGlobalThisOrFallback().console || {} | ||
|  | const stdSerializers = { | ||
|  |   mapHttpRequest: mock, | ||
|  |   mapHttpResponse: mock, | ||
|  |   wrapRequestSerializer: passthrough, | ||
|  |   wrapResponseSerializer: passthrough, | ||
|  |   wrapErrorSerializer: passthrough, | ||
|  |   req: mock, | ||
|  |   res: mock, | ||
|  |   err: asErrValue | ||
|  | } | ||
|  | 
 | ||
|  | function shouldSerialize (serialize, serializers) { | ||
|  |   if (Array.isArray(serialize)) { | ||
|  |     const hasToFilter = serialize.filter(function (k) { | ||
|  |       return k !== '!stdSerializers.err' | ||
|  |     }) | ||
|  |     return hasToFilter | ||
|  |   } else if (serialize === true) { | ||
|  |     return Object.keys(serializers) | ||
|  |   } | ||
|  | 
 | ||
|  |   return false | ||
|  | } | ||
|  | 
 | ||
|  | function pino (opts) { | ||
|  |   opts = opts || {} | ||
|  |   opts.browser = opts.browser || {} | ||
|  | 
 | ||
|  |   const transmit = opts.browser.transmit | ||
|  |   if (transmit && typeof transmit.send !== 'function') { throw Error('pino: transmit option must have a send function') } | ||
|  | 
 | ||
|  |   const proto = opts.browser.write || _console | ||
|  |   if (opts.browser.write) opts.browser.asObject = true | ||
|  |   const serializers = opts.serializers || {} | ||
|  |   const serialize = shouldSerialize(opts.browser.serialize, serializers) | ||
|  |   let stdErrSerialize = opts.browser.serialize | ||
|  | 
 | ||
|  |   if ( | ||
|  |     Array.isArray(opts.browser.serialize) && | ||
|  |     opts.browser.serialize.indexOf('!stdSerializers.err') > -1 | ||
|  |   ) stdErrSerialize = false | ||
|  | 
 | ||
|  |   const levels = ['error', 'fatal', 'warn', 'info', 'debug', 'trace'] | ||
|  | 
 | ||
|  |   if (typeof proto === 'function') { | ||
|  |     proto.error = proto.fatal = proto.warn = | ||
|  |     proto.info = proto.debug = proto.trace = proto | ||
|  |   } | ||
|  |   if (opts.enabled === false) opts.level = 'silent' | ||
|  |   const level = opts.level || 'info' | ||
|  |   const logger = Object.create(proto) | ||
|  |   if (!logger.log) logger.log = noop | ||
|  | 
 | ||
|  |   Object.defineProperty(logger, 'levelVal', { | ||
|  |     get: getLevelVal | ||
|  |   }) | ||
|  |   Object.defineProperty(logger, 'level', { | ||
|  |     get: getLevel, | ||
|  |     set: setLevel | ||
|  |   }) | ||
|  | 
 | ||
|  |   const setOpts = { | ||
|  |     transmit, | ||
|  |     serialize, | ||
|  |     asObject: opts.browser.asObject, | ||
|  |     levels, | ||
|  |     timestamp: getTimeFunction(opts) | ||
|  |   } | ||
|  |   logger.levels = pino.levels | ||
|  |   logger.level = level | ||
|  | 
 | ||
|  |   logger.setMaxListeners = logger.getMaxListeners = | ||
|  |   logger.emit = logger.addListener = logger.on = | ||
|  |   logger.prependListener = logger.once = | ||
|  |   logger.prependOnceListener = logger.removeListener = | ||
|  |   logger.removeAllListeners = logger.listeners = | ||
|  |   logger.listenerCount = logger.eventNames = | ||
|  |   logger.write = logger.flush = noop | ||
|  |   logger.serializers = serializers | ||
|  |   logger._serialize = serialize | ||
|  |   logger._stdErrSerialize = stdErrSerialize | ||
|  |   logger.child = child | ||
|  | 
 | ||
|  |   if (transmit) logger._logEvent = createLogEventShape() | ||
|  | 
 | ||
|  |   function getLevelVal () { | ||
|  |     return this.level === 'silent' | ||
|  |       ? Infinity | ||
|  |       : this.levels.values[this.level] | ||
|  |   } | ||
|  | 
 | ||
|  |   function getLevel () { | ||
|  |     return this._level | ||
|  |   } | ||
|  |   function setLevel (level) { | ||
|  |     if (level !== 'silent' && !this.levels.values[level]) { | ||
|  |       throw Error('unknown level ' + level) | ||
|  |     } | ||
|  |     this._level = level | ||
|  | 
 | ||
|  |     set(setOpts, logger, 'error', 'log') // <-- must stay first
 | ||
|  |     set(setOpts, logger, 'fatal', 'error') | ||
|  |     set(setOpts, logger, 'warn', 'error') | ||
|  |     set(setOpts, logger, 'info', 'log') | ||
|  |     set(setOpts, logger, 'debug', 'log') | ||
|  |     set(setOpts, logger, 'trace', 'log') | ||
|  |   } | ||
|  | 
 | ||
|  |   function child (bindings, childOptions) { | ||
|  |     if (!bindings) { | ||
|  |       throw new Error('missing bindings for child Pino') | ||
|  |     } | ||
|  |     childOptions = childOptions || {} | ||
|  |     if (serialize && bindings.serializers) { | ||
|  |       childOptions.serializers = bindings.serializers | ||
|  |     } | ||
|  |     const childOptionsSerializers = childOptions.serializers | ||
|  |     if (serialize && childOptionsSerializers) { | ||
|  |       var childSerializers = Object.assign({}, serializers, childOptionsSerializers) | ||
|  |       var childSerialize = opts.browser.serialize === true | ||
|  |         ? Object.keys(childSerializers) | ||
|  |         : serialize | ||
|  |       delete bindings.serializers | ||
|  |       applySerializers([bindings], childSerialize, childSerializers, this._stdErrSerialize) | ||
|  |     } | ||
|  |     function Child (parent) { | ||
|  |       this._childLevel = (parent._childLevel | 0) + 1 | ||
|  |       this.error = bind(parent, bindings, 'error') | ||
|  |       this.fatal = bind(parent, bindings, 'fatal') | ||
|  |       this.warn = bind(parent, bindings, 'warn') | ||
|  |       this.info = bind(parent, bindings, 'info') | ||
|  |       this.debug = bind(parent, bindings, 'debug') | ||
|  |       this.trace = bind(parent, bindings, 'trace') | ||
|  |       if (childSerializers) { | ||
|  |         this.serializers = childSerializers | ||
|  |         this._serialize = childSerialize | ||
|  |       } | ||
|  |       if (transmit) { | ||
|  |         this._logEvent = createLogEventShape( | ||
|  |           [].concat(parent._logEvent.bindings, bindings) | ||
|  |         ) | ||
|  |       } | ||
|  |     } | ||
|  |     Child.prototype = this | ||
|  |     return new Child(this) | ||
|  |   } | ||
|  |   return logger | ||
|  | } | ||
|  | 
 | ||
|  | pino.levels = { | ||
|  |   values: { | ||
|  |     fatal: 60, | ||
|  |     error: 50, | ||
|  |     warn: 40, | ||
|  |     info: 30, | ||
|  |     debug: 20, | ||
|  |     trace: 10 | ||
|  |   }, | ||
|  |   labels: { | ||
|  |     10: 'trace', | ||
|  |     20: 'debug', | ||
|  |     30: 'info', | ||
|  |     40: 'warn', | ||
|  |     50: 'error', | ||
|  |     60: 'fatal' | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | pino.stdSerializers = stdSerializers | ||
|  | pino.stdTimeFunctions = Object.assign({}, { nullTime, epochTime, unixTime, isoTime }) | ||
|  | 
 | ||
|  | function set (opts, logger, level, fallback) { | ||
|  |   const proto = Object.getPrototypeOf(logger) | ||
|  |   logger[level] = logger.levelVal > logger.levels.values[level] | ||
|  |     ? noop | ||
|  |     : (proto[level] ? proto[level] : (_console[level] || _console[fallback] || noop)) | ||
|  | 
 | ||
|  |   wrap(opts, logger, level) | ||
|  | } | ||
|  | 
 | ||
|  | function wrap (opts, logger, level) { | ||
|  |   if (!opts.transmit && logger[level] === noop) return | ||
|  | 
 | ||
|  |   logger[level] = (function (write) { | ||
|  |     return function LOG () { | ||
|  |       const ts = opts.timestamp() | ||
|  |       const args = new Array(arguments.length) | ||
|  |       const proto = (Object.getPrototypeOf && Object.getPrototypeOf(this) === _console) ? _console : this | ||
|  |       for (var i = 0; i < args.length; i++) args[i] = arguments[i] | ||
|  | 
 | ||
|  |       if (opts.serialize && !opts.asObject) { | ||
|  |         applySerializers(args, this._serialize, this.serializers, this._stdErrSerialize) | ||
|  |       } | ||
|  |       if (opts.asObject) write.call(proto, asObject(this, level, args, ts)) | ||
|  |       else write.apply(proto, args) | ||
|  | 
 | ||
|  |       if (opts.transmit) { | ||
|  |         const transmitLevel = opts.transmit.level || logger.level | ||
|  |         const transmitValue = pino.levels.values[transmitLevel] | ||
|  |         const methodValue = pino.levels.values[level] | ||
|  |         if (methodValue < transmitValue) return | ||
|  |         transmit(this, { | ||
|  |           ts, | ||
|  |           methodLevel: level, | ||
|  |           methodValue, | ||
|  |           transmitLevel, | ||
|  |           transmitValue: pino.levels.values[opts.transmit.level || logger.level], | ||
|  |           send: opts.transmit.send, | ||
|  |           val: logger.levelVal | ||
|  |         }, args) | ||
|  |       } | ||
|  |     } | ||
|  |   })(logger[level]) | ||
|  | } | ||
|  | 
 | ||
|  | function asObject (logger, level, args, ts) { | ||
|  |   if (logger._serialize) applySerializers(args, logger._serialize, logger.serializers, logger._stdErrSerialize) | ||
|  |   const argsCloned = args.slice() | ||
|  |   let msg = argsCloned[0] | ||
|  |   const o = {} | ||
|  |   if (ts) { | ||
|  |     o.time = ts | ||
|  |   } | ||
|  |   o.level = pino.levels.values[level] | ||
|  |   let lvl = (logger._childLevel | 0) + 1 | ||
|  |   if (lvl < 1) lvl = 1 | ||
|  |   // deliberate, catching objects, arrays
 | ||
|  |   if (msg !== null && typeof msg === 'object') { | ||
|  |     while (lvl-- && typeof argsCloned[0] === 'object') { | ||
|  |       Object.assign(o, argsCloned.shift()) | ||
|  |     } | ||
|  |     msg = argsCloned.length ? format(argsCloned.shift(), argsCloned) : undefined | ||
|  |   } else if (typeof msg === 'string') msg = format(argsCloned.shift(), argsCloned) | ||
|  |   if (msg !== undefined) o.msg = msg | ||
|  |   return o | ||
|  | } | ||
|  | 
 | ||
|  | function applySerializers (args, serialize, serializers, stdErrSerialize) { | ||
|  |   for (const i in args) { | ||
|  |     if (stdErrSerialize && args[i] instanceof Error) { | ||
|  |       args[i] = pino.stdSerializers.err(args[i]) | ||
|  |     } else if (typeof args[i] === 'object' && !Array.isArray(args[i])) { | ||
|  |       for (const k in args[i]) { | ||
|  |         if (serialize && serialize.indexOf(k) > -1 && k in serializers) { | ||
|  |           args[i][k] = serializers[k](args[i][k]) | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | function bind (parent, bindings, level) { | ||
|  |   return function () { | ||
|  |     const args = new Array(1 + arguments.length) | ||
|  |     args[0] = bindings | ||
|  |     for (var i = 1; i < args.length; i++) { | ||
|  |       args[i] = arguments[i - 1] | ||
|  |     } | ||
|  |     return parent[level].apply(this, args) | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | function transmit (logger, opts, args) { | ||
|  |   const send = opts.send | ||
|  |   const ts = opts.ts | ||
|  |   const methodLevel = opts.methodLevel | ||
|  |   const methodValue = opts.methodValue | ||
|  |   const val = opts.val | ||
|  |   const bindings = logger._logEvent.bindings | ||
|  | 
 | ||
|  |   applySerializers( | ||
|  |     args, | ||
|  |     logger._serialize || Object.keys(logger.serializers), | ||
|  |     logger.serializers, | ||
|  |     logger._stdErrSerialize === undefined ? true : logger._stdErrSerialize | ||
|  |   ) | ||
|  |   logger._logEvent.ts = ts | ||
|  |   logger._logEvent.messages = args.filter(function (arg) { | ||
|  |     // bindings can only be objects, so reference equality check via indexOf is fine
 | ||
|  |     return bindings.indexOf(arg) === -1 | ||
|  |   }) | ||
|  | 
 | ||
|  |   logger._logEvent.level.label = methodLevel | ||
|  |   logger._logEvent.level.value = methodValue | ||
|  | 
 | ||
|  |   send(methodLevel, logger._logEvent, val) | ||
|  | 
 | ||
|  |   logger._logEvent = createLogEventShape(bindings) | ||
|  | } | ||
|  | 
 | ||
|  | function createLogEventShape (bindings) { | ||
|  |   return { | ||
|  |     ts: 0, | ||
|  |     messages: [], | ||
|  |     bindings: bindings || [], | ||
|  |     level: { label: '', value: 0 } | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | function asErrValue (err) { | ||
|  |   const obj = { | ||
|  |     type: err.constructor.name, | ||
|  |     msg: err.message, | ||
|  |     stack: err.stack | ||
|  |   } | ||
|  |   for (const key in err) { | ||
|  |     if (obj[key] === undefined) { | ||
|  |       obj[key] = err[key] | ||
|  |     } | ||
|  |   } | ||
|  |   return obj | ||
|  | } | ||
|  | 
 | ||
|  | function getTimeFunction (opts) { | ||
|  |   if (typeof opts.timestamp === 'function') { | ||
|  |     return opts.timestamp | ||
|  |   } | ||
|  |   if (opts.timestamp === false) { | ||
|  |     return nullTime | ||
|  |   } | ||
|  |   return epochTime | ||
|  | } | ||
|  | 
 | ||
|  | function mock () { return {} } | ||
|  | function passthrough (a) { return a } | ||
|  | function noop () {} | ||
|  | 
 | ||
|  | function nullTime () { return false } | ||
|  | function epochTime () { return Date.now() } | ||
|  | function unixTime () { return Math.round(Date.now() / 1000.0) } | ||
|  | function isoTime () { return new Date(Date.now()).toISOString() } // using Date.now() for testability
 | ||
|  | 
 | ||
|  | /* eslint-disable */ | ||
|  | /* istanbul ignore next */ | ||
|  | function pfGlobalThisOrFallback () { | ||
|  |   function defd (o) { return typeof o !== 'undefined' && o } | ||
|  |   try { | ||
|  |     if (typeof globalThis !== 'undefined') return globalThis | ||
|  |     Object.defineProperty(Object.prototype, 'globalThis', { | ||
|  |       get: function () { | ||
|  |         delete Object.prototype.globalThis | ||
|  |         return (this.globalThis = this) | ||
|  |       }, | ||
|  |       configurable: true | ||
|  |     }) | ||
|  |     return globalThis | ||
|  |   } catch (e) { | ||
|  |     return defd(self) || defd(window) || defd(this) || {} | ||
|  |   } | ||
|  | } | ||
|  | /* eslint-enable */ |