| 1 | 'use strict'; |
| 2 | |
| 3 | const Utilities = require('./utilities'); |
| 4 | |
| 5 | const internals = { |
| 6 | |
| 7 | // Maps log levels to their syslog labels |
| 8 | |
| 9 | kLevelStrings: [ |
| 10 | 'emerg', |
| 11 | 'alert', |
| 12 | 'crit', |
| 13 | 'error', |
| 14 | 'warning', |
| 15 | 'notice', |
| 16 | 'info', |
| 17 | 'debug' |
| 18 | ], |
| 19 | |
| 20 | // Version of the Cologne Log Format used |
| 21 | |
| 22 | kLogVersion: '2.0.0' |
| 23 | }; |
| 24 | |
| 25 | /** TYPE DEFINITIONS **/ |
| 26 | |
| 27 | /** |
| 28 | * Main interface for Cologne Loggers |
| 29 | * |
| 30 | * @interface ILogger |
| 31 | */ |
| 32 | |
| 33 | /** |
| 34 | * Receives any number of cologne log objects and logs them. |
| 35 | * |
| 36 | * @memberof ILogger |
| 37 | * @function |
| 38 | * @name log |
| 39 | */ |
| 40 | |
| 41 | /** |
| 42 | * Main interface for Cologne Formatters |
| 43 | * |
| 44 | * @interface IFormatter |
| 45 | */ |
| 46 | |
| 47 | /** |
| 48 | * Receives a cologne log object and returns a formatted string. |
| 49 | * |
| 50 | * @memberof IFormatter |
| 51 | * @function |
| 52 | * @name format |
| 53 | * @param {tCologneLog} logObject the log to be formatted |
| 54 | * @returns {string} the formatted log |
| 55 | */ |
| 56 | |
| 57 | /** |
| 58 | * The main cologne log format. |
| 59 | * |
| 60 | * @typedef {object} tCologneLog |
| 61 | * @property {Bigint} _timestamp the timestamp in nanoseconds |
| 62 | * @property {String} _cologneLog main identifier, encodes the version of the |
| 63 | * cologne log format being used. |
| 64 | * @property {String} _from the origin of the log message. |
| 65 | * @property {String} _level the severity level of the log, uses syslog |
| 66 | * priorities. |
| 67 | * @property {String} _levelString the severity level keyword of the log, |
| 68 | * uses syslog priority keywords. |
| 69 | */ |
| 70 | |
| 71 | /** |
| 72 | * The main logger class. It can be instantiated with loggers in order to |
| 73 | * send messages to different destinations. |
| 74 | * |
| 75 | * @class Cologne |
| 76 | */ |
| 77 | const Cologne = class Cologne { |
| 78 | |
| 79 | constructor(config) { |
| 80 | |
| 81 | /** |
| 82 | * The name of this logger, useful to distinguish between different |
| 83 | * loggers. |
| 84 | * |
| 85 | * @name from |
| 86 | * @instance |
| 87 | * @memberof Cologne |
| 88 | * @type String |
| 89 | * @default 'Generic Cologne Logger |
| 90 | */ |
| 91 | this.from = 'Generic Cologne Logger'; |
| 92 | |
| 93 | /** |
| 94 | * The array containing all the loggers it will call to. |
| 95 | * |
| 96 | * @name loggers |
| 97 | * @instance |
| 98 | * @memberof Cologne |
| 99 | * @type ILogger[] |
| 100 | * @default [] |
| 101 | */ |
| 102 | this.loggers = []; |
| 103 | |
| 104 | Object.assign(this, config); |
| 105 | } |
| 106 | |
| 107 | /** |
| 108 | * Adds a logger to the current instance. |
| 109 | * |
| 110 | * @function addLogger |
| 111 | * @instance |
| 112 | * @memberof Cologne |
| 113 | * @param {ILogger} logger the logger to add |
| 114 | */ |
| 115 | addLogger(logger) { |
| 116 | |
| 117 | this.loggers.push(logger); |
| 118 | } |
| 119 | |
| 120 | /** |
| 121 | * Removes a logger from the current instance. |
| 122 | * |
| 123 | * @function removeLogger |
| 124 | * @instance |
| 125 | * @memberof Cologne |
| 126 | * @param {ILogger} logger the logger to remove |
| 127 | * @return {ILogger[]} the removed log, inside an array. |
| 128 | */ |
| 129 | removeLogger(logger) { |
| 130 | |
| 131 | const index = this.loggers.indexOf(logger); |
| 132 | if (index >= 0) { |
| 133 | this.loggers.splice(index, 1); |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | /** |
| 138 | * Given a message, it builds a cologne log object without logging it. |
| 139 | * If you send a cologne log object, it will only update the level. |
| 140 | * |
| 141 | * If the message is an object, the log object will be extended with |
| 142 | * its properties. |
| 143 | * |
| 144 | * @function buildLog |
| 145 | * @instance |
| 146 | * @memberof Cologne |
| 147 | * @param {*} message The message to log |
| 148 | * @param {number} [level=6] The level of the message to log |
| 149 | * @return {tCologneLog} a cologne log object |
| 150 | */ |
| 151 | buildLog(rawMessage, level) { |
| 152 | |
| 153 | if (typeof rawMessage === 'undefined' || rawMessage === null || !rawMessage._cologneLog) { |
| 154 | |
| 155 | const message = typeof rawMessage === 'object' ? Utilities.stringify(rawMessage) : rawMessage; |
| 156 | |
| 157 | const logObject = { |
| 158 | message: String(message), |
| 159 | _cologneLog: internals.kLogVersion, |
| 160 | _from: this.from, |
| 161 | _level: level || 6, |
| 162 | _timestamp: Utilities.now() |
| 163 | }; |
| 164 | |
| 165 | logObject._levelString = internals.kLevelStrings[logObject._level]; |
| 166 | |
| 167 | if (typeof rawMessage === 'object') { |
| 168 | Object.assign(logObject, rawMessage); |
| 169 | } |
| 170 | |
| 171 | return logObject; |
| 172 | } |
| 173 | |
| 174 | rawMessage._level = level || rawMessage._level; |
| 175 | rawMessage._levelString = internals.kLevelStrings[rawMessage._level]; |
| 176 | |
| 177 | return rawMessage; |
| 178 | } |
| 179 | |
| 180 | /** |
| 181 | * Default log function. Sends arguments to loggers. If not specified in log |
| 182 | * object, it will set the severity to 6 - INFO. |
| 183 | * |
| 184 | * @function log |
| 185 | * @instance |
| 186 | * @memberof Cologne |
| 187 | */ |
| 188 | log(...logs) { |
| 189 | |
| 190 | this._log(null, ...logs); |
| 191 | } |
| 192 | |
| 193 | /** |
| 194 | * Logs with debug level |
| 195 | * |
| 196 | * @function debug |
| 197 | * @instance |
| 198 | * @memberof Cologne |
| 199 | */ |
| 200 | debug(...logs) { |
| 201 | |
| 202 | this._log(7, ...logs); |
| 203 | } |
| 204 | |
| 205 | /** |
| 206 | * Logs with info level |
| 207 | * |
| 208 | * @function info |
| 209 | * @instance |
| 210 | * @memberof Cologne |
| 211 | */ |
| 212 | info(...logs) { |
| 213 | |
| 214 | this._log(6, ...logs); |
| 215 | } |
| 216 | |
| 217 | /** |
| 218 | * Logs with notice level |
| 219 | * |
| 220 | * @function notice |
| 221 | * @instance |
| 222 | * @memberof Cologne |
| 223 | */ |
| 224 | notice(...logs) { |
| 225 | |
| 226 | this._log(5, ...logs); |
| 227 | } |
| 228 | |
| 229 | /** |
| 230 | * Logs with warn level |
| 231 | * |
| 232 | * @function warn |
| 233 | * @instance |
| 234 | * @memberof Cologne |
| 235 | */ |
| 236 | warn(...logs) { |
| 237 | |
| 238 | this._log(4, ...logs); |
| 239 | } |
| 240 | |
| 241 | /** |
| 242 | * Logs with error level |
| 243 | * |
| 244 | * @function error |
| 245 | * @instance |
| 246 | * @memberof Cologne |
| 247 | */ |
| 248 | error(...logs) { |
| 249 | |
| 250 | this._log(3, ...logs); |
| 251 | } |
| 252 | |
| 253 | // Private method that builds all the logs and sends them to the loggers. |
| 254 | |
| 255 | _log(level, ...logs) { |
| 256 | |
| 257 | const structuredLogs = logs.map((log) => this.buildLog(log, level)); |
| 258 | |
| 259 | for (const logger of this.loggers) { |
| 260 | logger.log(...structuredLogs); |
| 261 | } |
| 262 | } |
| 263 | }; |
| 264 | |
| 265 | /** |
| 266 | * Namespace that includes the built-in formatters. |
| 267 | * |
| 268 | * @namespace Formatters |
| 269 | */ |
| 270 | const Formatters = {}; |
| 271 | Formatters.Simple = require('./formatters/simple'); |
| 272 | Formatters.Token = require('./formatters/token'); |
| 273 | |
| 274 | /** |
| 275 | * Namespace that includes the built-in loggers. |
| 276 | * |
| 277 | * @namespace Loggers |
| 278 | */ |
| 279 | const Loggers = {}; |
| 280 | Loggers.Console = require('./loggers/console'); |
| 281 | Loggers.File = require('./loggers/file'); |
| 282 | |
| 283 | module.exports = { |
| 284 | Cologne, |
| 285 | Formatters, |
| 286 | Loggers, |
| 287 | Utilities |
| 288 | }; |