logger: add logger "contexts".

This commit is contained in:
Christopher Jeffrey 2017-03-12 10:00:46 -07:00
parent b104e664a7
commit 81b565fc85
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD

View File

@ -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);
};
/*