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
						
					
					
				| '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 */
 |