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
						
					
					
				'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()
 | 
						|
}
 |