X-Git-Url: http://git.squeep.com/?p=squeep-logger-json-console;a=blobdiff_plain;f=lib%2Flogger.js;h=d5a0c908dae0f417832cbf0fb6864d3c0f34160c;hp=a040bb8ba3f9e759f3003e3af562c6c0fdc7d386;hb=8b684b27f20657c5e0de61b4f19981937915c484;hpb=dbff0fa5f018f7a302f73250e55f761c0ccf24b1 diff --git a/lib/logger.js b/lib/logger.js index a040bb8..d5a0c90 100644 --- a/lib/logger.js +++ b/lib/logger.js @@ -3,36 +3,52 @@ const jsonReplacers = require('./json-replacers'); const dataSanitizers = require('./data-sanitizers'); -/** - * Log as JSON to stdout/stderr. - */ - const nop = () => { /**/ }; - class Logger { /** - * Wrap backend calls with payload normalization. - * @param {Object} options - * @param {String} options.nodeId - unique identifier for running instance, usually a uuid - * @param {Object} options.logger - * @param {String} options.logger.ignoreBelowLevel - minimum level to log + * @typedef {Object} ConsoleLike + * @property {Function(...):void} error + * @property {Function(...):void} warn + * @property {Function(...):void} info + * @property {Function(...):void} log + * @property {Function(...):void} debug + */ + /** + * @typedef {Object} LoggerOptions + * @property {String} ignoreBelowLevel - minimum level to log, e.g. 'info' */ - constructor(options) { + /** + * Wrap backend calls with payload normalization and metadata. + * @param {LoggerOptions} options + * @param {Object} commonObject - object to be merged into logged json + * @param {AsyncLocalStorage} asyncLocalStorage - async storage for an object to be merged into logged json + * @param {ConsoleLike} backend - default is console + */ + constructor(options, commonObject, asyncLocalStorage, backend) { const logLevels = Object.keys(Logger.nullLogger); - const ignoreBelowLevel = options && options.logger && options.logger.ignoreBelowLevel || 'debug'; - this.backend = console; - this.nodeId = options.nodeId; + const ignoreBelowLevel = options?.ignoreBelowLevel || 'debug'; + this.backend = backend || console; + this.commonObject = commonObject || {}; this.jsonReplacers = Object.values(jsonReplacers); this.dataSanitizers = Object.values(dataSanitizers); + if (asyncLocalStorage) { + // Override the class getter. + Object.defineProperty(this, 'asyncLogObject', { + enumerable: true, + get: asyncLocalStorage.getStore.bind(asyncLocalStorage), + }); + } + if (!logLevels.includes(ignoreBelowLevel)) { throw new RangeError(`unrecognized minimum log level '${ignoreBelowLevel}'`); } const ignoreLevelIdx = logLevels.indexOf(ignoreBelowLevel); logLevels.forEach((level) => { + const includeBackendLevel = (logLevels.indexOf(level) > ignoreLevelIdx) && this.backend[level]; // eslint-disable-line security/detect-object-injection // eslint-disable-next-line security/detect-object-injection - this[level] = (logLevels.indexOf(level) > ignoreLevelIdx) ? + this[level] = (includeBackendLevel) ? nop : (...args) => this.backend[level](this.payload(level, ...args)); // eslint-disable-line security/detect-object-injection }); @@ -54,6 +70,16 @@ class Logger { } + /** + * Default of empty object when no asyncLocalStorage is defined. + * Overridden on instance when asyncLocalStorage is defined. + */ + // eslint-disable-next-line class-methods-use-this + get asyncLogObject() { + return {}; + } + + /** * Structure all expected log data into JSON string. * @param {String} level @@ -72,7 +98,7 @@ class Logger { const now = new Date(); return JSON.stringify({ - nodeId: this.nodeId, + ...this.commonObject, timestamp: now.toISOString(), timestampMs: now.getTime(), level: level, @@ -80,6 +106,7 @@ class Logger { message: message || '', data: data || {}, ...(other.length && { other }), + ...this.asyncLogObject, }, this.jsonReplacer.bind(this)); }