appc-logger
Version:
Appcelerator Logger
197 lines (178 loc) • 5.36 kB
JavaScript
'use strict';
const bunyan = require('bunyan'),
chalk = require('chalk'),
util = require('util'),
_ = require('lodash'),
cluster = require('cluster'),
events = require('events'),
Logger = require('./logger'),
EventEmitter = events.EventEmitter,
grey = chalk.grey,
green = chalk.green,
cyan = chalk.cyan,
red = chalk.red,
yellow = chalk.yellow,
dash = grey.bold('|');
let defaultColorizeArg;
util.inherits(ConsoleLogger, events.EventEmitter);
/**
* Console logging functionality
*
* @param {Object} options - options
*/
function ConsoleLogger(options) {
EventEmitter.call(this);
this.options = options || {};
// allow use to customize if they want the label or not
this.prefix = this.options.prefix === undefined ? true : this.options.prefix;
this.showcr = this.options.showcr === undefined ? true : this.options.showcr;
this.showtab = this.options.showtab === undefined ? true : this.options.showtab;
this.colorize = this.options.colorize === undefined ? checkColorize() : this.options.colorize;
this.logPrepend = this.options.logPrepend;
chalk.enabled = !!this.colorize;
// if we are logging from a cluster worker, prepend the process PID
// istanbul ignore if
if (cluster.isWorker) {
if (chalk.enabled) {
this.logPrepend = chalk.black.inverse(String(process.pid)) + grey(' |');
} else {
this.logPrepend = process.pid + ' |';
}
}
this.remapLevels();
}
/**
* Check colorization
* @returns {boolean}
*/
function checkColorize() {
if (defaultColorizeArg !== undefined) {
return defaultColorizeArg;
}
// default is to only colorize if we have a TTY and not running on TTY
defaultColorizeArg = process.stdout.isTTY && !process.env.TRAVIS;
for (let c = 1; c < process.argv.length; c++) {
const arg = process.argv[c];
if (arg === '--colorize' || arg === '--color' || arg === '--colors') {
defaultColorizeArg = true;
break;
} else if (arg === '--no-colors' || arg === '--no-color') {
defaultColorizeArg = false;
break;
}
}
return defaultColorizeArg;
}
const CR_NC = '↩',
CR = chalk.blue.bold(CR_NC),
TAB_NC = '↠',
TAB = chalk.blue.bold(TAB_NC);
/**
* Remap levels
*/
ConsoleLogger.prototype.remapLevels = function remapLevels() {
this.LevelMapping = {};
this.LevelMapping[bunyan.TRACE] = { prefix: grey('TRACE '), color: grey, prefixNoColor: 'TRACE ' };
this.LevelMapping[bunyan.DEBUG] = { prefix: grey.bold('DEBUG '), color: cyan, prefixNoColor: 'DEBUG ' };
this.LevelMapping[bunyan.INFO] = { prefix: green('INFO '), prefixNoColor: 'INFO ' };
this.LevelMapping[bunyan.WARN] = { prefix: yellow('WARN '), prefixNoColor: 'WARN ' };
this.LevelMapping[bunyan.ERROR] = { prefix: red('ERROR '), prefixNoColor: 'ERROR ' };
this.LevelMapping[bunyan.FATAL] = { prefix: red.underline('FATAL') + ' ', color: red, prefixNoColor: 'FATAL ' };
};
/**
* called to write a formatted set of args (as an array) to
* console.log. allows subclasses to override after formatting
* has been applied
*
* @param {Object} args - args
*/
ConsoleLogger.prototype.writeFormatted = function (args) {
console.log.apply(console, args);
};
/**
* Write
*
* @param {Object} record - record
* @returns {boolean}
*/
ConsoleLogger.prototype.write = function (record) {
if (record.ignore) {
return true;
}
this.colorize = checkColorize();
const level = this.LevelMapping[record.level],
color = this.colorize;
let args = [];
if (this.prefix) {
// If the log level is tracing or debugging, add a timestamp to each log statement.
const setLevel = this.level;
if (setLevel === bunyan.TRACE || setLevel === bunyan.DEBUG) {
const ts = new Date().toISOString();
args.push(color ? grey(ts) : ts);
args.push(color ? dash : '|');
}
// Then add the prefix (such as INFO, WARN, etc).
args.push(color ? level.prefix : level.prefixNoColor);
args.push(color ? dash : '|');
if (this.logPrepend) {
args.push(this.logPrepend);
}
}
// Now add the message.
let msg = record.msg;
if (!msg || msg === ' ') {
// this is the case where you send in an object as the only argument
const fields = _.omit(record, 'name', 'prefix', 'showtab', 'showcr', 'hostname', 'pid', 'level', 'msg', 'time', 'v', 'problemLogName');
if (_.isEmpty(fields)) {
msg = '';
} else {
msg = util.inspect(fields, { colors: true });
}
}
if (this.showcr && msg.indexOf('\n') > 0) {
const lines = msg.split(/\n/),
cr = color ? CR : CR_NC;
msg = lines.join(cr + '\n') + (lines.length > 1 ? cr : '');
}
if (this.showtab && msg.indexOf('\t') > 0) {
const tlines = msg.split(/\t/),
tab = color ? TAB : TAB_NC;
msg = tlines.join('\t' + tab);
}
if (color) {
args.push(level.color && level.color(msg) || msg);
} else {
args.push(Logger.stripColors(msg));
}
this.writeFormatted(args);
return true;
};
/**
* End
*/
ConsoleLogger.prototype.end = function () {
if (arguments.length > 0) {
this.write.apply(this, Array.prototype.slice.call(arguments));
}
this.destroySoon();
};
/**
* Destroy
*/
ConsoleLogger.prototype.destroy = function () {
this.emit('close');
};
/**
* Destroy soon
*/
ConsoleLogger.prototype.destroySoon = function () {
this.destroy();
};
/**
* Reset colorization
*/
ConsoleLogger.resetColorize = function () {
defaultColorizeArg = undefined;
chalk.enabled = chalk.supportsColor;
};
module.exports = ConsoleLogger;