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.
		
		
		
		
		
			
		
			
				
					234 lines
				
				6.6 KiB
			
		
		
			
		
	
	
					234 lines
				
				6.6 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								'use strict'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* eslint no-prototype-builtins: 0 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const { EventEmitter } = require('events')
							 | 
						||
| 
								 | 
							
								const SonicBoom = require('sonic-boom')
							 | 
						||
| 
								 | 
							
								const flatstr = require('flatstr')
							 | 
						||
| 
								 | 
							
								const warning = require('./deprecations')
							 | 
						||
| 
								 | 
							
								const {
							 | 
						||
| 
								 | 
							
								  lsCacheSym,
							 | 
						||
| 
								 | 
							
								  levelValSym,
							 | 
						||
| 
								 | 
							
								  setLevelSym,
							 | 
						||
| 
								 | 
							
								  getLevelSym,
							 | 
						||
| 
								 | 
							
								  chindingsSym,
							 | 
						||
| 
								 | 
							
								  parsedChindingsSym,
							 | 
						||
| 
								 | 
							
								  mixinSym,
							 | 
						||
| 
								 | 
							
								  asJsonSym,
							 | 
						||
| 
								 | 
							
								  writeSym,
							 | 
						||
| 
								 | 
							
								  mixinMergeStrategySym,
							 | 
						||
| 
								 | 
							
								  timeSym,
							 | 
						||
| 
								 | 
							
								  timeSliceIndexSym,
							 | 
						||
| 
								 | 
							
								  streamSym,
							 | 
						||
| 
								 | 
							
								  serializersSym,
							 | 
						||
| 
								 | 
							
								  formattersSym,
							 | 
						||
| 
								 | 
							
								  useOnlyCustomLevelsSym,
							 | 
						||
| 
								 | 
							
								  needsMetadataGsym,
							 | 
						||
| 
								 | 
							
								  redactFmtSym,
							 | 
						||
| 
								 | 
							
								  stringifySym,
							 | 
						||
| 
								 | 
							
								  formatOptsSym,
							 | 
						||
| 
								 | 
							
								  stringifiersSym
							 | 
						||
| 
								 | 
							
								} = require('./symbols')
							 | 
						||
| 
								 | 
							
								const {
							 | 
						||
| 
								 | 
							
								  getLevel,
							 | 
						||
| 
								 | 
							
								  setLevel,
							 | 
						||
| 
								 | 
							
								  isLevelEnabled,
							 | 
						||
| 
								 | 
							
								  mappings,
							 | 
						||
| 
								 | 
							
								  initialLsCache,
							 | 
						||
| 
								 | 
							
								  genLsCache,
							 | 
						||
| 
								 | 
							
								  assertNoLevelCollisions
							 | 
						||
| 
								 | 
							
								} = require('./levels')
							 | 
						||
| 
								 | 
							
								const {
							 | 
						||
| 
								 | 
							
								  asChindings,
							 | 
						||
| 
								 | 
							
								  asJson,
							 | 
						||
| 
								 | 
							
								  buildFormatters,
							 | 
						||
| 
								 | 
							
								  stringify
							 | 
						||
| 
								 | 
							
								} = require('./tools')
							 | 
						||
| 
								 | 
							
								const {
							 | 
						||
| 
								 | 
							
								  version
							 | 
						||
| 
								 | 
							
								} = require('./meta')
							 | 
						||
| 
								 | 
							
								const redaction = require('./redaction')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// note: use of class is satirical
							 | 
						||
| 
								 | 
							
								// https://github.com/pinojs/pino/pull/433#pullrequestreview-127703127
							 | 
						||
| 
								 | 
							
								const constructor = class Pino {}
							 | 
						||
| 
								 | 
							
								const prototype = {
							 | 
						||
| 
								 | 
							
								  constructor,
							 | 
						||
| 
								 | 
							
								  child,
							 | 
						||
| 
								 | 
							
								  bindings,
							 | 
						||
| 
								 | 
							
								  setBindings,
							 | 
						||
| 
								 | 
							
								  flush,
							 | 
						||
| 
								 | 
							
								  isLevelEnabled,
							 | 
						||
| 
								 | 
							
								  version,
							 | 
						||
| 
								 | 
							
								  get level () { return this[getLevelSym]() },
							 | 
						||
| 
								 | 
							
								  set level (lvl) { this[setLevelSym](lvl) },
							 | 
						||
| 
								 | 
							
								  get levelVal () { return this[levelValSym] },
							 | 
						||
| 
								 | 
							
								  set levelVal (n) { throw Error('levelVal is read-only') },
							 | 
						||
| 
								 | 
							
								  [lsCacheSym]: initialLsCache,
							 | 
						||
| 
								 | 
							
								  [writeSym]: write,
							 | 
						||
| 
								 | 
							
								  [asJsonSym]: asJson,
							 | 
						||
| 
								 | 
							
								  [getLevelSym]: getLevel,
							 | 
						||
| 
								 | 
							
								  [setLevelSym]: setLevel
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Object.setPrototypeOf(prototype, EventEmitter.prototype)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// exporting and consuming the prototype object using factory pattern fixes scoping issues with getters when serializing
							 | 
						||
| 
								 | 
							
								module.exports = function () {
							 | 
						||
| 
								 | 
							
								  return Object.create(prototype)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const resetChildingsFormatter = bindings => bindings
							 | 
						||
| 
								 | 
							
								function child (bindings, options) {
							 | 
						||
| 
								 | 
							
								  if (!bindings) {
							 | 
						||
| 
								 | 
							
								    throw Error('missing bindings for child Pino')
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  options = options || {} // default options to empty object
							 | 
						||
| 
								 | 
							
								  const serializers = this[serializersSym]
							 | 
						||
| 
								 | 
							
								  const formatters = this[formattersSym]
							 | 
						||
| 
								 | 
							
								  const instance = Object.create(this)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (bindings.hasOwnProperty('serializers') === true) {
							 | 
						||
| 
								 | 
							
								    warning.emit('PINODEP004')
							 | 
						||
| 
								 | 
							
								    options.serializers = bindings.serializers
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  if (bindings.hasOwnProperty('formatters') === true) {
							 | 
						||
| 
								 | 
							
								    warning.emit('PINODEP005')
							 | 
						||
| 
								 | 
							
								    options.formatters = bindings.formatters
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  if (bindings.hasOwnProperty('customLevels') === true) {
							 | 
						||
| 
								 | 
							
								    warning.emit('PINODEP006')
							 | 
						||
| 
								 | 
							
								    options.customLevels = bindings.customLevels
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  if (bindings.hasOwnProperty('level') === true) {
							 | 
						||
| 
								 | 
							
								    warning.emit('PINODEP007')
							 | 
						||
| 
								 | 
							
								    options.level = bindings.level
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  if (options.hasOwnProperty('serializers') === true) {
							 | 
						||
| 
								 | 
							
								    instance[serializersSym] = Object.create(null)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for (const k in serializers) {
							 | 
						||
| 
								 | 
							
								      instance[serializersSym][k] = serializers[k]
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    const parentSymbols = Object.getOwnPropertySymbols(serializers)
							 | 
						||
| 
								 | 
							
								    /* eslint no-var: off */
							 | 
						||
| 
								 | 
							
								    for (var i = 0; i < parentSymbols.length; i++) {
							 | 
						||
| 
								 | 
							
								      const ks = parentSymbols[i]
							 | 
						||
| 
								 | 
							
								      instance[serializersSym][ks] = serializers[ks]
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for (const bk in options.serializers) {
							 | 
						||
| 
								 | 
							
								      instance[serializersSym][bk] = options.serializers[bk]
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    const bindingsSymbols = Object.getOwnPropertySymbols(options.serializers)
							 | 
						||
| 
								 | 
							
								    for (var bi = 0; bi < bindingsSymbols.length; bi++) {
							 | 
						||
| 
								 | 
							
								      const bks = bindingsSymbols[bi]
							 | 
						||
| 
								 | 
							
								      instance[serializersSym][bks] = options.serializers[bks]
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  } else instance[serializersSym] = serializers
							 | 
						||
| 
								 | 
							
								  if (options.hasOwnProperty('formatters')) {
							 | 
						||
| 
								 | 
							
								    const { level, bindings: chindings, log } = options.formatters
							 | 
						||
| 
								 | 
							
								    instance[formattersSym] = buildFormatters(
							 | 
						||
| 
								 | 
							
								      level || formatters.level,
							 | 
						||
| 
								 | 
							
								      chindings || resetChildingsFormatter,
							 | 
						||
| 
								 | 
							
								      log || formatters.log
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								  } else {
							 | 
						||
| 
								 | 
							
								    instance[formattersSym] = buildFormatters(
							 | 
						||
| 
								 | 
							
								      formatters.level,
							 | 
						||
| 
								 | 
							
								      resetChildingsFormatter,
							 | 
						||
| 
								 | 
							
								      formatters.log
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  if (options.hasOwnProperty('customLevels') === true) {
							 | 
						||
| 
								 | 
							
								    assertNoLevelCollisions(this.levels, options.customLevels)
							 | 
						||
| 
								 | 
							
								    instance.levels = mappings(options.customLevels, instance[useOnlyCustomLevelsSym])
							 | 
						||
| 
								 | 
							
								    genLsCache(instance)
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // redact must place before asChindings and only replace if exist
							 | 
						||
| 
								 | 
							
								  if ((typeof options.redact === 'object' && options.redact !== null) || Array.isArray(options.redact)) {
							 | 
						||
| 
								 | 
							
								    instance.redact = options.redact // replace redact directly
							 | 
						||
| 
								 | 
							
								    const stringifiers = redaction(instance.redact, stringify)
							 | 
						||
| 
								 | 
							
								    const formatOpts = { stringify: stringifiers[redactFmtSym] }
							 | 
						||
| 
								 | 
							
								    instance[stringifySym] = stringify
							 | 
						||
| 
								 | 
							
								    instance[stringifiersSym] = stringifiers
							 | 
						||
| 
								 | 
							
								    instance[formatOptsSym] = formatOpts
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  instance[chindingsSym] = asChindings(instance, bindings)
							 | 
						||
| 
								 | 
							
								  const childLevel = options.level || this.level
							 | 
						||
| 
								 | 
							
								  instance[setLevelSym](childLevel)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return instance
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function bindings () {
							 | 
						||
| 
								 | 
							
								  const chindings = this[chindingsSym]
							 | 
						||
| 
								 | 
							
								  const chindingsJson = `{${chindings.substr(1)}}` // at least contains ,"pid":7068,"hostname":"myMac"
							 | 
						||
| 
								 | 
							
								  const bindingsFromJson = JSON.parse(chindingsJson)
							 | 
						||
| 
								 | 
							
								  delete bindingsFromJson.pid
							 | 
						||
| 
								 | 
							
								  delete bindingsFromJson.hostname
							 | 
						||
| 
								 | 
							
								  return bindingsFromJson
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function setBindings (newBindings) {
							 | 
						||
| 
								 | 
							
								  const chindings = asChindings(this, newBindings)
							 | 
						||
| 
								 | 
							
								  this[chindingsSym] = chindings
							 | 
						||
| 
								 | 
							
								  delete this[parsedChindingsSym]
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Default strategy for creating `mergeObject` from arguments and the result from `mixin()`.
							 | 
						||
| 
								 | 
							
								 * Fields from `mergeObject` have higher priority in this strategy.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param {Object} mergeObject The object a user has supplied to the logging function.
							 | 
						||
| 
								 | 
							
								 * @param {Object} mixinObject The result of the `mixin` method.
							 | 
						||
| 
								 | 
							
								 * @return {Object}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function defaultMixinMergeStrategy (mergeObject, mixinObject) {
							 | 
						||
| 
								 | 
							
								  return Object.assign(mixinObject, mergeObject)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function write (_obj, msg, num) {
							 | 
						||
| 
								 | 
							
								  const t = this[timeSym]()
							 | 
						||
| 
								 | 
							
								  const mixin = this[mixinSym]
							 | 
						||
| 
								 | 
							
								  const mixinMergeStrategy = this[mixinMergeStrategySym] || defaultMixinMergeStrategy
							 | 
						||
| 
								 | 
							
								  const objError = _obj instanceof Error
							 | 
						||
| 
								 | 
							
								  let obj
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (_obj === undefined || _obj === null) {
							 | 
						||
| 
								 | 
							
								    obj = mixin ? mixin({}) : {}
							 | 
						||
| 
								 | 
							
								  } else {
							 | 
						||
| 
								 | 
							
								    obj = mixinMergeStrategy(_obj, mixin ? mixin(_obj) : {})
							 | 
						||
| 
								 | 
							
								    if (!msg && objError) {
							 | 
						||
| 
								 | 
							
								      msg = _obj.message
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (objError) {
							 | 
						||
| 
								 | 
							
								      obj.stack = _obj.stack
							 | 
						||
| 
								 | 
							
								      if (!obj.type) {
							 | 
						||
| 
								 | 
							
								        obj.type = 'Error'
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const s = this[asJsonSym](obj, msg, num, t)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const stream = this[streamSym]
							 | 
						||
| 
								 | 
							
								  if (stream[needsMetadataGsym] === true) {
							 | 
						||
| 
								 | 
							
								    stream.lastLevel = num
							 | 
						||
| 
								 | 
							
								    stream.lastObj = obj
							 | 
						||
| 
								 | 
							
								    stream.lastMsg = msg
							 | 
						||
| 
								 | 
							
								    stream.lastTime = t.slice(this[timeSliceIndexSym])
							 | 
						||
| 
								 | 
							
								    stream.lastLogger = this // for child loggers
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  if (stream instanceof SonicBoom) stream.write(s)
							 | 
						||
| 
								 | 
							
								  else stream.write(flatstr(s))
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function flush () {
							 | 
						||
| 
								 | 
							
								  const stream = this[streamSym]
							 | 
						||
| 
								 | 
							
								  if ('flush' in stream) stream.flush()
							 | 
						||
| 
								 | 
							
								}
							 |