diff --git a/lib/node/logger.js b/lib/node/logger.js index 9b1d3a6f..9c0ceffc 100644 --- a/lib/node/logger.js +++ b/lib/node/logger.js @@ -69,6 +69,21 @@ Logger.levelsByVal = [ 'spam' ]; +/** + * Available log levels. + * @const {String[]} + * @default + */ + +Logger.prefixByVal = [ + 'N', + 'E', + 'W', + 'I', + 'D', + 'S' +]; + /** * Default CSI colors. * @const {String[]} @@ -122,6 +137,7 @@ Logger.prototype.init = function init(options) { /** * Open the logger. + * @returns {Promise} */ Logger.prototype.open = co(function* open() { @@ -137,6 +153,7 @@ Logger.prototype.open = co(function* open() { /** * Destroy the write stream. + * @returns {Promise} */ Logger.prototype.close = co(function* close() { @@ -233,7 +250,338 @@ Logger.prototype.error = function error(err) { return; if (err instanceof Error) - return this._error(err); + return this.logError(Logger.levels.ERROR, null, err); + + args = new Array(arguments.length); + + for (i = 0; i < args.length; i++) + args[i] = arguments[i]; + + this.log(Logger.levels.ERROR, null, args); +}; + +/** + * Output a log to the `warning` log level. + * @param {String|Object} obj + * @param {...Object} args + */ + +Logger.prototype.warning = function warning(err) { + var i, args; + + if (this.level < Logger.levels.WARNING) + return; + + if (err instanceof Error) + return this.logError(Logger.levels.WARNING, null, err); + + args = new Array(arguments.length); + + for (i = 0; i < args.length; i++) + args[i] = arguments[i]; + + this.log(Logger.levels.WARNING, null, args); +}; + +/** + * Output a log to the `info` log level. + * @param {String|Object} obj + * @param {...Object} args + */ + +Logger.prototype.info = function info(err) { + var i, args; + + if (this.level < Logger.levels.INFO) + return; + + if (err instanceof Error) + return this.logError(Logger.levels.INFO, null, err); + + args = new Array(arguments.length); + + for (i = 0; i < args.length; i++) + args[i] = arguments[i]; + + this.log(Logger.levels.INFO, null, args); +}; + +/** + * Output a log to the `debug` log level. + * @param {String|Object} obj + * @param {...Object} args + */ + +Logger.prototype.debug = function debug(err) { + var i, args; + + if (this.level < Logger.levels.DEBUG) + return; + + if (err instanceof Error) + return this.logError(Logger.levels.DEBUG, null, err); + + args = new Array(arguments.length); + + for (i = 0; i < args.length; i++) + args[i] = arguments[i]; + + this.log(Logger.levels.DEBUG, null, args); +}; + +/** + * Output a log to the `spam` log level. + * @param {String|Object} obj + * @param {...Object} args + */ + +Logger.prototype.spam = function spam(err) { + var i, args; + + if (this.level < Logger.levels.SPAM) + return; + + if (err instanceof Error) + return this.logError(Logger.levels.SPAM, null, err); + + args = new Array(arguments.length); + + for (i = 0; i < args.length; i++) + args[i] = arguments[i]; + + this.log(Logger.levels.SPAM, null, args); +}; + +/** + * Output a log to the desired log level. + * Note that this bypasses the level check. + * @param {String} level + * @param {String|null} module + * @param {Object[]} args + */ + +Logger.prototype.log = function log(level, module, args) { + if (this.closed) + return; + + if (this.level < level) + return; + + this.writeConsole(level, module, args); + this.writeStream(level, module, args); +}; + +/** + * Create logger context. + * @param {String} module + * @returns {LoggerContext} + */ + +Logger.prototype.context = function context(module) { + return new LoggerContext(this, module); +}; + +/** + * Write log to the console. + * @param {String} level + * @param {String|null} module + * @param {Object[]} args + */ + +Logger.prototype.writeConsole = function writeConsole(level, module, args) { + var name = Logger.prefixByVal[level]; + var msg = ''; + var fmt, color; + + assert(name, 'Invalid log level.'); + + if (!this.console) + return; + + if (util.isBrowser) { + fmt = args[0]; + msg += '[' + name + '] '; + + if (module) + msg += '(' + module + ') '; + + if (typeof args[0] !== 'object') + fmt = util.format(args, false); + + msg += fmt; + + return level === Logger.levels.ERROR + ? console.error(msg) + : console.log(msg); + } + + if (this.colors) { + color = Logger.colors[level]; + msg += '\x1b[' + color + 'm'; + msg += '[' + name + '] '; + msg += '\x1b[m'; + } + + if (module) + msg += '(' + module + ') '; + + msg += util.format(args, this.colors); + + return level === Logger.levels.ERROR + ? process.stderr.write(msg + '\n') + : process.stdout.write(msg + '\n'); +}; + +/** + * Write a string to the output stream (usually a file). + * @param {String} level + * @param {String|null} module + * @param {Object[]} args + */ + +Logger.prototype.writeStream = function writeStream(level, module, args) { + var name = Logger.prefixByVal[level]; + var stream = this.stream; + var msg = ''; + var prefix; + + assert(name, 'Invalid log level.'); + + if (!stream) + return; + + msg += '[' + msg += name; + msg += ':' + util.date(); + msg += '] '; + + if (module) + msg += '(' + module + ') '; + + msg += util.format(args, false); + msg += '\n'; + + stream.write(msg); +}; + +/** + * Helper to parse an error into a nicer + * format. Call's `log` internally. + * @private + * @param {Number} level + * @param {String|null} module + * @param {Error} err + */ + +Logger.prototype.logError = function logError(level, module, err) { + var msg; + + if (this.closed) + return; + + if (util.isBrowser && this.console && level >= Logger.levels.DEBUG) + console.error(err); + + msg = (err.message + '').replace(/^ *Error: */, ''); + + this.log(level, module, [msg]); + + if (this.level >= Logger.levels.DEBUG) { + if (this.stream) + this.stream.write(err.stack + '\n'); + } +}; + +/** + * Log the current memory usage. + * @param {String|null} module + */ + +Logger.prototype.memory = function memory(module) { + var mem; + + if (!process.memoryUsage) + return; + + mem = process.memoryUsage(); + + this.log(Logger.levels.DEBUG, module, + ['Memory: rss=%dmb, js-heap=%d/%dmb native-heap=%dmb', + util.mb(mem.rss), + util.mb(mem.heapUsed), + util.mb(mem.heapTotal), + util.mb(mem.rss - mem.heapTotal)]); +}; + +/** + * Basic stdout and file logger. + * @constructor + * @ignore + * @param {Logger} logger + * @param {String} module + */ + +function LoggerContext(logger, module) { + if (!(this instanceof LoggerContext)) + return new LoggerContext(logger, module); + + assert(typeof module === 'string'); + + this.logger = logger; + this.module = module; +} + +/** + * Open the logger. + * @returns {Promise} + */ + +LoggerContext.prototype.open = function open() { + return this.logger.open(); +}; + +/** + * Destroy the write stream. + * @returns {Promise} + */ + +LoggerContext.prototype.close = function close() { + return this.logger.close(); +}; + +/** + * Set the log file location. + * @param {String} filename + */ + +LoggerContext.prototype.setFile = function setFile(filename) { + this.logger.setFile(filename); +}; + +/** + * Set or reset the log level. + * @param {String} level + */ + +LoggerContext.prototype.setLevel = function setLevel(name) { + this.logger.setLevel(name); +}; + + +/** + * Output a log to the `error` log level. + * @param {String|Object|Error} err + * @param {...Object} args + */ + +LoggerContext.prototype.error = function error(err) { + var i, args; + + if (this.logger.level < Logger.levels.ERROR) + return; + + if (err instanceof Error) + return this.logError(Logger.levels.ERROR, err); args = new Array(arguments.length); @@ -243,18 +591,33 @@ Logger.prototype.error = function error(err) { this.log(Logger.levels.ERROR, args); }; +/** + * Helper to parse an error into a nicer + * format. Call's `log` internally. + * @private + * @param {Number} level + * @param {Error} err + */ + +LoggerContext.prototype.logError = function logError(level, err) { + this.logger.logError(level, this.module, err); +}; + /** * Output a log to the `warning` log level. * @param {String|Object} obj * @param {...Object} args */ -Logger.prototype.warning = function warning() { +LoggerContext.prototype.warning = function warning(err) { var i, args; - if (this.level < Logger.levels.WARNING) + if (this.logger.level < Logger.levels.WARNING) return; + if (err instanceof Error) + return this.logError(Logger.levels.WARNING, err); + args = new Array(arguments.length); for (i = 0; i < args.length; i++) @@ -269,12 +632,15 @@ Logger.prototype.warning = function warning() { * @param {...Object} args */ -Logger.prototype.info = function info() { +LoggerContext.prototype.info = function info(err) { var i, args; - if (this.level < Logger.levels.INFO) + if (this.logger.level < Logger.levels.INFO) return; + if (err instanceof Error) + return this.logError(Logger.levels.INFO, err); + args = new Array(arguments.length); for (i = 0; i < args.length; i++) @@ -289,12 +655,15 @@ Logger.prototype.info = function info() { * @param {...Object} args */ -Logger.prototype.debug = function debug() { +LoggerContext.prototype.debug = function debug(err) { var i, args; - if (this.level < Logger.levels.DEBUG) + if (this.logger.level < Logger.levels.DEBUG) return; + if (err instanceof Error) + return this.logError(Logger.levels.DEBUG, err); + args = new Array(arguments.length); for (i = 0; i < args.length; i++) @@ -309,12 +678,15 @@ Logger.prototype.debug = function debug() { * @param {...Object} args */ -Logger.prototype.spam = function spam() { +LoggerContext.prototype.spam = function spam(err) { var i, args; - if (this.level < Logger.levels.SPAM) + if (this.logger.level < Logger.levels.SPAM) return; + if (err instanceof Error) + return this.logError(Logger.levels.SPAM, err); + args = new Array(arguments.length); for (i = 0; i < args.length; i++) @@ -330,127 +702,26 @@ Logger.prototype.spam = function spam() { * @param {Object[]} args */ -Logger.prototype.log = function log(level, args) { - if (this.closed) - return; - - if (this.level < level) - return; - - this.writeConsole(level, args); - this.writeStream(level, args); +LoggerContext.prototype.log = function log(level, args) { + this.logger.log(level, this.module, args); }; /** - * Write log to the console. - * @param {String} level - * @param {Object[]} args + * Create logger context. + * @param {String} module + * @returns {LoggerContext} */ -Logger.prototype.writeConsole = function writeConsole(level, args) { - var name = Logger.levelsByVal[level]; - var prefix, msg, color; - - assert(name, 'Invalid log level.'); - - if (!this.console) - return; - - prefix = '[' + name + '] '; - - if (util.isBrowser) { - msg = typeof args[0] !== 'object' - ? util.format(args, false) - : args[0]; - - msg = prefix + msg; - - return level === Logger.levels.ERROR - ? console.error(msg) - : console.log(msg); - } - - if (this.colors) { - color = Logger.colors[level]; - prefix = '\x1b[' + color + 'm' + prefix + '\x1b[m'; - } - - msg = prefix + util.format(args, this.colors); - - return level === Logger.levels.ERROR - ? process.stderr.write(msg + '\n') - : process.stdout.write(msg + '\n'); -}; - -/** - * Write a string to the output stream (usually a file). - * @param {String} level - * @param {Object[]} args - */ - -Logger.prototype.writeStream = function writeStream(level, args) { - var name = Logger.levelsByVal[level]; - var stream = this.stream; - var prefix, msg; - - assert(name, 'Invalid log level.'); - - if (!stream) - return; - - prefix = '[' + name + '] '; - msg = prefix + util.format(args, false); - msg = '(' + util.date() + '): ' + msg + '\n'; - - if (!util.isBrowser) - msg = process.pid + ' ' + msg; - - stream.write(msg); -}; - -/** - * Helper to parse an error into a nicer - * format. Call's `log` internally. - * @private - * @param {Error} err - */ - -Logger.prototype._error = function error(err) { - var msg; - - if (this.closed) - return; - - if (util.isBrowser && this.console) - console.error(err); - - msg = (err.message + '').replace(/^ *Error: */, ''); - - this.log(Logger.levels.ERROR, [msg]); - - if (this.level >= Logger.levels.DEBUG) { - if (this.stream) - this.stream.write(err.stack + '\n'); - } +LoggerContext.prototype.context = function context(module) { + return new LoggerContext(this.logger, module); }; /** * Log the current memory usage. */ -Logger.prototype.memory = function memory() { - var mem; - - if (!process.memoryUsage) - return; - - mem = process.memoryUsage(); - - this.debug('Memory: rss=%dmb, js-heap=%d/%dmb native-heap=%dmb', - util.mb(mem.rss), - util.mb(mem.heapUsed), - util.mb(mem.heapTotal), - util.mb(mem.rss - mem.heapTotal)); +LoggerContext.prototype.memory = function memory() { + this.logger.memory(this.module); }; /*