diff options
| author | Ruben Beltran del Rio <ruben@unlimited.pizza> | 2020-09-21 01:00:19 +0200 |
|---|---|---|
| committer | Ruben Beltran del Rio <ruben@unlimited.pizza> | 2020-09-21 01:00:19 +0200 |
| commit | ae85c067634676251e812765c81adfdef8f85f9d (patch) | |
| tree | ea1557df2172aeb30a363afec6a2183f05469d22 /lib | |
| parent | 58906d77975b35fe93569f8083b90140124f9c41 (diff) | |
Update the code.
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/cologne.js | 240 | ||||
| -rw-r--r-- | lib/formatters/simple.js (renamed from lib/cologne/formatter/simple.js) | 35 | ||||
| -rw-r--r-- | lib/formatters/token.js (renamed from lib/cologne/formatter/token.js) | 49 | ||||
| -rw-r--r-- | lib/loggers/console.js (renamed from lib/cologne/logger/console.js) | 55 | ||||
| -rw-r--r-- | lib/loggers/file.js (renamed from lib/cologne/logger/file.js) | 39 | ||||
| -rw-r--r-- | lib/utilities.js (renamed from lib/cologne/log_utilities.js) | 74 |
6 files changed, 223 insertions, 269 deletions
diff --git a/lib/cologne.js b/lib/cologne.js index 646fe79..392b452 100644 --- a/lib/cologne.js +++ b/lib/cologne.js @@ -1,49 +1,64 @@ 'use strict'; -let LogUtilities = require('./cologne/log_utilities'); +const Utilities = require('./utilities'); + +const internals = { + + // Maps log levels to their syslog labels + + kLevelStrings: [ + 'emerg', + 'alert', + 'crit', + 'error', + 'warning', + 'notice', + 'info', + 'debug' + ], + + // Version of the Cologne Log Format used + + kLogVersion: '2.0.0' +}; /** TYPE DEFINITIONS **/ /** * Main interface for Cologne Loggers * - * @memberof Cologne * @interface ILogger */ /** * Receives any number of cologne log objects and logs them. * - * @memberof Cologne.ILogger + * @memberof ILogger * @function * @name log - * @returns {undefined} */ /** * Main interface for Cologne Formatters * - * @memberof Cologne * @interface IFormatter */ /** * Receives a cologne log object and returns a formatted string. * - * @memberof Cologne.IFormatter + * @memberof IFormatter * @function * @name format - * @param {Cologne.tCologneLog} logObject the log to be formatted + * @param {tCologneLog} logObject the log to be formatted * @returns {string} the formatted log */ /** * The main cologne log format. * - * @memberof Cologne * @typedef {object} tCologneLog - * @property {Number} _timestamp the timestamp in miliseconds with decimal - * numbers representing fractions of miliseconds + * @property {Bigint} _timestamp the timestamp in nanoseconds * @property {String} _cologneLog main identifier, encodes the version of the * cologne log format being used. * @property {String} _from the origin of the log message. @@ -54,32 +69,14 @@ let LogUtilities = require('./cologne/log_utilities'); */ /** - * Cologne is a logger multiplexer that works mainly with a JSON format. It - * can be instantiated with several loggers, or they can be changed after - * the fact. - * - * ## Usage - * - * ``` - * require('cologne'); - * - * let co = new Cologne({ - * from: "Special Worker Logger", - * loggers: [ - * new Cologne.Logger.Console({ - * formatter: new Cologne.Formatter.Token({ - * formatString: '[{{_timestamp}}]{{_from}}: {{message}}' - * }) - * }) - * ] - * }); - * ``` + * The main logger class. It can be instantiated with loggers in order to + * send messages to different destinations. * * @class Cologne */ -let Cologne = class Cologne { +const Cologne = class Cologne { - constructor (config) { + constructor(config) { /** * The name of this logger, useful to distinguish between different @@ -99,12 +96,12 @@ let Cologne = class Cologne { * @name loggers * @instance * @memberof Cologne - * @type Cologne.ILogger[] + * @type ILogger[] * @default [] */ this.loggers = []; - Object.assign(this, config || {}); + Object.assign(this, config); } /** @@ -113,10 +110,10 @@ let Cologne = class Cologne { * @function addLogger * @instance * @memberof Cologne - * @param {Cologne.ILogger} logger the logger to add - * @return {undefined} + * @param {ILogger} logger the logger to add */ - addLogger (logger) { + addLogger(logger) { + this.loggers.push(logger); } @@ -126,55 +123,58 @@ let Cologne = class Cologne { * @function removeLogger * @instance * @memberof Cologne - * @param {Cologne.ILogger} logger the logger to remove - * @return {Cologne.ILogger[]} the removed log, inside an array. + * @param {ILogger} logger the logger to remove + * @return {ILogger[]} the removed log, inside an array. */ - removeLogger (logger) { - let index; + removeLogger(logger) { - index = this.loggers.indexOf(logger); + const index = this.loggers.indexOf(logger); if (index >= 0) { this.loggers.splice(index, 1); } } /** - * Given an item, it builds a cologne log object. this is done - * automatically by the logger, though this is useful if you need - * to attach metadata before logging. + * Given a message, it builds a cologne log object without logging it. + * If you send a cologne log object, it will only update the level. + * + * If the message is an object, the log object will be extended with + * its properties. * * @function buildLog * @instance * @memberof Cologne - * @param {*} item The item to log - * @return {Cologne.tCologneLog} a cologne log object + * @param {*} message The message to log + * @param {number} [level=6] The level of the message to log + * @return {tCologneLog} a cologne log object */ - buildLog (item, level, meta) { - let logObject; + buildLog(rawMessage, level) { + + if (typeof rawMessage === 'undefined' || rawMessage === null || !rawMessage._cologneLog) { - logObject = {}; + const message = typeof rawMessage === 'object' ? Utilities.stringify(rawMessage) : rawMessage; - if (typeof item === 'undefined' || item === null || !item._cologneLog) { - logObject.message = item; - logObject._cologneLog = this.constructor._version; - logObject._from = this.from; - logObject._level = level || 6; - logObject._levelString = this._levelString(logObject._level); - logObject._timestamp = LogUtilities.now(); + const logObject = { + message: String(message), + _cologneLog: internals.kLogVersion, + _from: this.from, + _level: level || 6, + _timestamp: Utilities.now() + }; - if (meta && typeof meta === 'object') { - Object.assign(logObject, meta); + logObject._levelString = internals.kLevelStrings[logObject._level]; + + if (typeof rawMessage === 'object') { + Object.assign(logObject, rawMessage); } return logObject; } - if (item._cologneLog) { - item._level = level || item._level || 6; - item._levelString = this._levelString(item._level); - } + rawMessage._level = level || rawMessage._level; + rawMessage._levelString = internals.kLevelStrings[rawMessage._level]; - return item; + return rawMessage; } /** @@ -184,10 +184,10 @@ let Cologne = class Cologne { * @function log * @instance * @memberof Cologne - * @return {undefined} */ - log () { - this._log.apply(this, [null].concat(Array.prototype.slice.call(arguments))); + log(...logs) { + + this._log(null, ...logs); } /** @@ -196,10 +196,10 @@ let Cologne = class Cologne { * @function debug * @instance * @memberof Cologne - * @return {undefined} */ - debug () { - this._log.apply(this, [7].concat(Array.prototype.slice.call(arguments))); + debug(...logs) { + + this._log(7, ...logs); } /** @@ -208,10 +208,10 @@ let Cologne = class Cologne { * @function info * @instance * @memberof Cologne - * @return {undefined} */ - info () { - this._log.apply(this, [6].concat(Array.prototype.slice.call(arguments))); + info(...logs) { + + this._log(6, ...logs); } /** @@ -220,10 +220,10 @@ let Cologne = class Cologne { * @function notice * @instance * @memberof Cologne - * @return {undefined} */ - notice () { - this._log.apply(this, [5].concat(Array.prototype.slice.call(arguments))); + notice(...logs) { + + this._log(5, ...logs); } /** @@ -232,10 +232,10 @@ let Cologne = class Cologne { * @function warn * @instance * @memberof Cologne - * @return {undefined} */ - warn () { - this._log.apply(this, [4].concat(Array.prototype.slice.call(arguments))); + warn(...logs) { + + this._log(4, ...logs); } /** @@ -244,85 +244,45 @@ let Cologne = class Cologne { * @function error * @instance * @memberof Cologne - * @return {undefined} */ - error () { - this._log.apply(this, [3].concat(Array.prototype.slice.call(arguments))); + error(...logs) { + + this._log(3, ...logs); } // Private method that builds all the logs and sends them to the loggers. - _log (severity) { - let remainingArguments, logObjectArray, log, logger; - remainingArguments = Array.prototype.slice.call(arguments, 1); - logObjectArray = []; + _log(level, ...logs) { - for (log of remainingArguments) { - if (typeof log === 'undefined') { - logObjectArray.push(this.buildLog('undefined', severity)); - continue; - } - - if (log === null) { - logObjectArray.push(this.buildLog('null', severity)); - continue; - } + const structuredLogs = logs.map((log) => this.buildLog(log, level)); - logObjectArray.push(this.buildLog(log, severity)); - } - - for (logger of this.loggers) { - logger.log.apply(logger, logObjectArray); - } - } - - // Private utility method that will return the string for any given - // numerical severity level - _levelString (level) { - switch(level) { - case 0: - return 'emerg'; - case 1: - return 'alert'; - case 2: - return 'crit'; - case 3: - return 'error'; - case 4: - return 'warning'; - case 5: - return 'notice'; - case 6: - return 'info'; - case 7: - return 'debug'; + for (const logger of this.loggers) { + logger.log(...structuredLogs); } } }; -// Version of the Cologne Log Format used. -Cologne._version = '1.0.0'; - /** * Namespace that includes the built-in formatters. * - * @namespace Formatter - * @memberof Cologne + * @namespace Formatters */ -Cologne.Formatter = {}; -Cologne.Formatter.Simple = require('./cologne/formatter/simple'); -Cologne.Formatter.Token = require('./cologne/formatter/token'); +const Formatters = {}; +Formatters.Simple = require('./formatters/simple'); +Formatters.Token = require('./formatters/token'); /** * Namespace that includes the built-in loggers. * - * @namespace Logger - * @memberof Cologne + * @namespace Loggers */ -Cologne.Logger = {}; -Cologne.Logger.Console = require('./cologne/logger/console'); -Cologne.Logger.File = require('./cologne/logger/file'); - -Cologne.LogUtilities = require('./cologne/log_utilities'); +const Loggers = {}; +Loggers.Console = require('./loggers/console'); +Loggers.File = require('./loggers/file'); -module.exports = Cologne; +module.exports = { + Cologne, + Formatters, + Loggers, + Utilities +}; diff --git a/lib/cologne/formatter/simple.js b/lib/formatters/simple.js index 48821fc..bfaa76c 100644 --- a/lib/cologne/formatter/simple.js +++ b/lib/formatters/simple.js @@ -1,18 +1,18 @@ 'use strict'; -let LogUtilities = require('../log_utilities'); +const Utilities = require('../utilities'); /** * Simple formatter. Outputs a predefined format: * `[{{_timestamp}}][{{_levelString}}] {{_from}}: {{message}}`; * - * @memberof Cologne.Formatter - * @implements Cologne.IFormatter + * @memberof Formatters + * @implements IFormatter * @class Simple */ -let SimpleFormatter = class SimpleFormatter { +module.exports = class SimpleFormatter { - constructor (config) { + constructor(config) { /** * Flag that tells us whether or not to use ANSI color. Defaults to @@ -20,7 +20,7 @@ let SimpleFormatter = class SimpleFormatter { * * @name colorize * @instance - * @memberof Cologne.Formatter.Simple + * @memberof Formatters.Simple * @type Boolean * @default false */ @@ -35,33 +35,28 @@ let SimpleFormatter = class SimpleFormatter { * * @function format * @instance - * @memberof Cologne.Formatter.Simple - * @param {Cologne.tCologneLog} logObjet the log to format + * @memberof Formatters.Simple + * @param {tCologneLog} logObjet the log to format * @return {String} the formatted object */ - format (logObject) { - let date, levelString; + format(logObject) { - date = new Date(logObject._timestamp); - date = date.toISOString(); - levelString = this._colorize(logObject._levelString, logObject._level); + const date = (new Date(Number(logObject._timestamp) / 1000000)).toISOString(); + const levelString = this._colorize(logObject._levelString, logObject._level); return `[${date}][${levelString}] ${logObject._from}: ${logObject.message}`; } - _colorize (levelString, level) { - let escapeCode, color, reset; + _colorize(levelString, level) { if (!this.colorize) { return levelString; } - escapeCode = String.fromCharCode(27); - color = escapeCode + LogUtilities.getAnsiCode(LogUtilities.getLevelAnsi(level)); - reset = escapeCode + LogUtilities.getAnsiCode('reset'); + const escapeCode = String.fromCharCode(27); + const color = escapeCode + Utilities.getAnsiCode(Utilities.getLevelAnsi(level)); + const reset = escapeCode + Utilities.getAnsiCode('reset'); return color + levelString + reset; } }; - -module.exports = SimpleFormatter; diff --git a/lib/cologne/formatter/token.js b/lib/formatters/token.js index bb905ca..2ec3a17 100644 --- a/lib/cologne/formatter/token.js +++ b/lib/formatters/token.js @@ -1,17 +1,17 @@ 'use strict'; -let LogUtilities = require('../log_utilities'); +const Utilities = require('../utilities'); /** * Token formatter. Given a format string it will attempt to output * a message. * - * @memberof Cologne.Formatter - * @implements Cologne.IFormatter + * @memberof Formatters + * @implements IFormatter * @class Token */ -let TokenFormatter = class TokenFormatter { - constructor (config) { +module.exports = class TokenFormatter { + constructor(config) { /** * The string to use as a template string. By default, any property @@ -21,7 +21,7 @@ let TokenFormatter = class TokenFormatter { * * @name formatString * @instance - * @memberof Cologne.Formatter.Token + * @memberof Formatters.Token * @type String * @default '{{message}}' */ @@ -32,7 +32,7 @@ let TokenFormatter = class TokenFormatter { * * @name replaceRule * @instance - * @memberof Cologne.Formatter.Token + * @memberof Formatters.Token * @type RegExp * @default /{{(.*)}}/g */ @@ -44,7 +44,7 @@ let TokenFormatter = class TokenFormatter { * * @name isoDate * @instance - * @memberof Cologne.Formatter.Token + * @memberof Formatters.Token * @type Boolean * @default true */ @@ -62,43 +62,32 @@ let TokenFormatter = class TokenFormatter { * * @function format * @instance - * @memberof Cologne.Formatter.Token - * @param {Cologne.tCologneLog} logObjet the log to format + * @memberof Formatters.Token + * @param {tCologneLog} log the log to format * @return {String} the formatted object */ - format (logObject) { - let resultString, escapeCode; + format(log) { - escapeCode = String.fromCharCode(27); - - resultString = this.formatString.replace(this.replaceRule, function (match, token) { - let date, ansiType; + const escapeCode = String.fromCharCode(27); + return this.formatString.replace(this.replaceRule, (match, token) => { if (token === '_timestamp' && this.isoDate) { - date = new Date(logObject._timestamp); + const date = new Date(Number(log._timestamp) / 1000000); return date.toISOString(); } if (token.match(this._ansiRe)) { - ansiType = token.split(':')[1]; + const ansiType = token.split(':')[1]; // Smartish coloring if (ansiType === '_level') { - return escapeCode + LogUtilities.getAnsiCode(LogUtilities.getLevelAnsi(logObject._level)); + return escapeCode + Utilities.getAnsiCode(Utilities.getLevelAnsi(log._level)); } - return escapeCode + LogUtilities.getAnsiCode(ansiType); - } - - if (!logObject.hasOwnProperty(token)) { - return match; + return escapeCode + Utilities.getAnsiCode(ansiType); } - return logObject[token]; - }.bind(this)); - - return resultString; + return log[token] || match; + }); } }; - -module.exports = TokenFormatter; diff --git a/lib/cologne/logger/console.js b/lib/loggers/console.js index 3a73e42..116b04b 100644 --- a/lib/cologne/logger/console.js +++ b/lib/loggers/console.js @@ -1,16 +1,15 @@ 'use strict'; -let LogUtilities = require('../log_utilities'); +const Utilities = require('../utilities'); /** * Logger for the javascript console. * - * @memberof Cologne.Logger - * @implements Cologne.ILogger + * @implements ILogger * @class Console */ -let ConsoleLogger = class ConsoleLogger { - constructor (config) { +module.exports = class ConsoleLogger { + constructor(config) { /** * The console it will write to, can be any object that looks @@ -18,7 +17,7 @@ let ConsoleLogger = class ConsoleLogger { * * @name console * @instance - * @memberof Cologne.Logger.Console + * @memberof Loggers.Console * @type Object * @default global.console */ @@ -30,13 +29,13 @@ let ConsoleLogger = class ConsoleLogger { * * @name formatter * @instance - * @memberof Cologne.Logger.Console - * @type Cologne.IFormatter + * @memberof Loggers.Console + * @type IFormatter * @default null */ this.formatter = null; - Object.assign(this, config || {}); + Object.assign(this, config); } @@ -46,50 +45,50 @@ let ConsoleLogger = class ConsoleLogger { * * @function log * @instance - * @memberof Cologne.Logger.Console + * @memberof Loggers.Console * @return {undefined} */ - log () { - let logObject, messages, severity; + log(...logs) { - messages = []; + const formattedLogs = logs.map((log) => ({ log: this._format(log), level: log._level })); - for (logObject of arguments) { - messages.push(this._format(logObject)); - - if (!severity) { - severity = logObject._level; - } + for (const { log, level } of formattedLogs) { + this._log(log, level ); } - switch(severity) { + } + + // Routes an individual log to the appropriatet console + + _log(log, level) { + + switch (level) { case 0: case 1: case 2: case 3: - this.console.error.apply(this.console, messages); + this.console.error(log); break; case 4: - this.console.warn.apply(this.console, messages); + this.console.warn(log); break; case 5: case 6: - this.console.info.apply(this.console, messages); + this.console.info(log); break; case 7: default: - this.console.log.apply(this.console, messages); + this.console.log(log); break; } } - _format (logObject) { + _format(logObject) { + if (this.formatter) { return this.formatter.format(logObject); } - return LogUtilities.stringify(logObject); + return Utilities.stringify(logObject); } }; - -module.exports = ConsoleLogger; diff --git a/lib/cologne/logger/file.js b/lib/loggers/file.js index e9a56e7..50a251e 100644 --- a/lib/cologne/logger/file.js +++ b/lib/loggers/file.js @@ -1,25 +1,24 @@ 'use strict'; -let fs = require('fs'); - -let LogUtilities = require('../log_utilities'); +const Fs = require('fs'); +const Utilities = require('../utilities'); /** * Logger for files. * - * @memberof Cologne.Logger - * @implements Cologne.ILogger + * @memberof Loggers + * @implements ILogger * @class File */ -let FileLogger = class FileLogger { - constructor (config) { +module.exports = class FileLogger { + constructor(config) { /** * Path to the file it will write to, must be readable. * * @name file * @instance - * @memberof Cologne.Logger.File + * @memberof Loggers.File * @type string * @default null */ @@ -31,15 +30,15 @@ let FileLogger = class FileLogger { * * @name formatter * @instance - * @memberof Cologne.Logger.File - * @type Cologne.IFormatter + * @memberof Loggers.File + * @type IFormatter * @default null */ this.formatter = null; - Object.assign(this, config || {}); + Object.assign(this, config); - this._stream = fs.createWriteStream(this.file, {flags: 'a'}); + this._stream = Fs.createWriteStream(this.file, { flags: 'a' }); } /** @@ -48,24 +47,22 @@ let FileLogger = class FileLogger { * * @function log * @instance - * @memberof Cologne.Logger.File + * @memberof Loggers.File * @return {undefined} */ - log () { - let logObject; + log(...logs) { - for (logObject of arguments) { - this._stream.write(this.format(logObject) + '\n'); + for (const log of logs) { + this._stream.write(this._format(log) + '\n'); } } - format (logObject) { + _format(logObject) { + if (this.formatter) { return this.formatter.format(logObject); } - return LogUtilities.stringify(logObject); + return Utilities.stringify(logObject); } }; - -module.exports = FileLogger; diff --git a/lib/cologne/log_utilities.js b/lib/utilities.js index fc15a8a..1c930af 100644 --- a/lib/cologne/log_utilities.js +++ b/lib/utilities.js @@ -1,63 +1,81 @@ 'use strict'; -let microtime = require('microtime'); +const internals = { + kCircularString: '[Circular]', + + // Get High Res time depending on platform. Currently only supporting node. + + getHighResTime() { + + return process.hrtime.bigint(); + } +}; + +// Initialise relative time. + +internals.initialTimestamp = BigInt(Date.now()) * 1000000n; +internals.initialHighResTime = internals.getHighResTime(); /** * Container object for utilities used by loggers. * - * @memberof Cologne - * @class LogUtilities + * @class Utilities */ -let LogUtilities = { +module.exports = { /** - * Returns the current timestamp in miliseconds as a floating point that - * includes fractions (ie. microseconds) + * Returns the current timestamp in nanoseconds as a bigint. * * @function now - * @memberof Cologne.LogUtilities - * @return {Number} current time in miliseconds, including fractions. + * @memberof Utilities + * @return {bigint} current time in nanoseconds, including fractions. */ - now: function now() { - return microtime.nowDouble() * 1000; + now() { + + return internals.initialTimestamp + internals.getHighResTime() - internals.initialHighResTime; }, /** * Stringifies objects, avoiding circular references. * * @function stringify - * @memberof Cologne.LogUtilities + * @memberof Utilities * @param {Object} object the object to stringify * @return {String} the stringified object */ - stringify: function stringify(object) { - let cache; + stringify(object) { - cache = []; + const cache = new Set(); + + return JSON.stringify(object, (key, value) => { + + if (typeof value === 'bigint') { + return String(value) + 'n'; + } - return JSON.stringify(object, function (key, value) { if (typeof value === 'object' && value !== null) { - if (cache.indexOf(value) !== -1) { - return this._circularString; + if (cache.has(value)) { + return internals.kCircularString; } - cache.push(value); + cache.add(value); } return value; - }.bind(this)); + }); }, /** * Given an ansi keyword, it will return the appropriate code. * * @function getAnsiCode - * @memberof Cologne.LogUtilities + * @memberof Utilities * @param {String} ansiString the name of the desired code * @return {String} the ansi code */ - getAnsiCode: function getAnsiCode(ansiString) { - switch(ansiString) { + getAnsiCode(ansiString) { + + switch (ansiString) { case 'bold': return '[1m'; case 'italics': @@ -125,12 +143,13 @@ let LogUtilities = { * to it. * * @function getLevelAnsi - * @memberof Cologne.LogUtilities + * @memberof Utilities * @param {number} level the level of the log * @return {String} the ansi keyword */ - getLevelAnsi: function getLevelAnsi(level) { - switch(level) { + getLevelAnsi(level) { + + switch (level) { case 0: case 1: case 2: @@ -148,8 +167,3 @@ let LogUtilities = { } } }; - -// String used as default circular reference. -LogUtilities._circularString = '[Circular]'; - -module.exports = LogUtilities; |