309 lines
7.1 KiB
JavaScript
309 lines
7.1 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
const assert = require('assert');
|
|
|
|
const dbug = require('dbug')('intel:logger');
|
|
|
|
const klass = require('./utils/klass');
|
|
const LEVELS = require('./levels');
|
|
const Filterer = require('./filterer');
|
|
const Record = require('./record');
|
|
const Trace = Record._Trace;
|
|
|
|
var __loggers = {};
|
|
var __levelCache = {};
|
|
const ROOT = 'root';
|
|
const DIVIDER = '.';
|
|
const OTHER_DIVIDERS = /[\/\\]/g;
|
|
|
|
function emptyStr() { return ''; }
|
|
function traceStr() { return 'Trace'; }
|
|
|
|
function getEffectiveParent(name) {
|
|
if (name === ROOT) {
|
|
return;
|
|
}
|
|
|
|
var parent;
|
|
while (name.indexOf(DIVIDER) !== -1 && !parent) {
|
|
name = name.substring(0, name.lastIndexOf(DIVIDER));
|
|
parent = __loggers[name];
|
|
}
|
|
return parent || __loggers[ROOT];
|
|
}
|
|
|
|
function getChildren(name) {
|
|
var children = [];
|
|
for (var k in __loggers) {
|
|
if ((name === ROOT || k.indexOf(name) === 0) &&
|
|
k !== name &&
|
|
getEffectiveParent(k) === __loggers[name]) {
|
|
children.push(__loggers[k]);
|
|
}
|
|
}
|
|
return children;
|
|
}
|
|
|
|
function logNoop() {}
|
|
|
|
function disableLevels(logger) {
|
|
for (var name in LEVELS) {
|
|
if (typeof LEVELS[name] === 'number') {
|
|
var level = LEVELS[name];
|
|
name = name.toLowerCase();
|
|
if (logger[name]) {
|
|
if (logger.isEnabledFor(level)) {
|
|
// delete any noops
|
|
delete logger[name];
|
|
} else {
|
|
Object.defineProperty(logger, name, {
|
|
configurable: true,
|
|
value: logNoop
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
var children = getChildren(logger._name);
|
|
children.forEach(function(child) {
|
|
disableLevels(child);
|
|
});
|
|
}
|
|
|
|
function logAtLevel(level) {
|
|
return function(msg /*, args...*/) {
|
|
switch (arguments.length) {
|
|
//faster cases
|
|
case 0:
|
|
case 1:
|
|
return this._log(level, msg);
|
|
case 2:
|
|
return this._log(level, msg, arguments[1]);
|
|
default:
|
|
//turtles
|
|
var args = new Array(arguments.length + 1);
|
|
args[0] = level;
|
|
for (var i = 1; i < args.length; i++) {
|
|
args[i] = arguments[i - 1];
|
|
}
|
|
return this._log.apply(this, args);
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
function Logger(name) {
|
|
if (!name) {
|
|
name = ROOT;
|
|
}
|
|
name = name.replace(OTHER_DIVIDERS, DIVIDER);
|
|
if (name in __loggers) {
|
|
return __loggers[name];
|
|
}
|
|
__loggers[name] = this;
|
|
this._name = name;
|
|
disableLevels(this);
|
|
|
|
Filterer.call(this);
|
|
|
|
this._handlers = [];
|
|
|
|
dbug('Logger (%s) created', name);
|
|
}
|
|
|
|
klass(Logger).inherit(Filterer).mixin({
|
|
|
|
//_handlers: [],
|
|
|
|
_name: null,
|
|
|
|
_level: null,
|
|
|
|
_handlesExceptions: false,
|
|
|
|
_exitOnError: true,
|
|
|
|
propagate: true,
|
|
|
|
setLevel: function setLevel(val) {
|
|
var level = LEVELS.getLevel(val);
|
|
assert(level != null, 'Cannot set level with provided value: ' + val);
|
|
this._level = level;
|
|
// clean __levelsCache
|
|
__levelCache = {};
|
|
disableLevels(this);
|
|
return this;
|
|
},
|
|
|
|
|
|
getEffectiveLevel: function getEffectiveLevel() {
|
|
if (this._level != null) {
|
|
return this._level;
|
|
} else if (this._name in __levelCache) {
|
|
return __levelCache[this._name];
|
|
} else {
|
|
var parent = getEffectiveParent(this._name);
|
|
return __levelCache[this._name] = parent ?
|
|
parent.getEffectiveLevel() :
|
|
LEVELS.NOTSET;
|
|
}
|
|
},
|
|
|
|
isEnabledFor: function isEnabledFor(level) {
|
|
return level >= this.getEffectiveLevel();
|
|
},
|
|
|
|
addHandler: function addHandler(handler) {
|
|
this._handlers.push(handler);
|
|
return this;
|
|
},
|
|
|
|
removeHandler: function removeHandler(handler) {
|
|
var index = this._handlers.indexOf(handler);
|
|
if (index !== -1) {
|
|
this._handlers.splice(index, 1);
|
|
}
|
|
return this;
|
|
},
|
|
|
|
removeAllHandlers: function removeAllHandlers() {
|
|
this._handlers = [];
|
|
},
|
|
|
|
handleExceptions: function handleExceptions(exitOnError/* = true */) {
|
|
this._exitOnError = exitOnError === false ? false : true;
|
|
if (!this._uncaughtException) {
|
|
this._uncaughtException = this.catchException.bind(this);
|
|
this._process.on('uncaughtException', this._uncaughtException);
|
|
}
|
|
},
|
|
|
|
unhandleExceptions: function unhandleExceptions() {
|
|
this._process.removeListener('uncaughtException', this._uncaughtException);
|
|
delete this._uncaughtException;
|
|
},
|
|
|
|
catchException: function catchException(err) {
|
|
var exits = this._exitOnError;
|
|
|
|
err[Record._UNCAUGHT_SYMBOL] = true;
|
|
this.critical(err);
|
|
if (exits) {
|
|
this._exit();
|
|
}
|
|
},
|
|
|
|
_exit: function _exit() {
|
|
this._process.exit(1);
|
|
},
|
|
|
|
makeRecord: function makeRecord(name, level, msg) {
|
|
return new Record(name, level, msg);
|
|
},
|
|
|
|
handle: function handle(record) {
|
|
if (this.filter(record)) {
|
|
|
|
var i = this._handlers.length;
|
|
while (i--) {
|
|
if (record.level >= this._handlers[i].level) {
|
|
this._handlers[i].handle(record);
|
|
}
|
|
}
|
|
|
|
// if this.propagate, tell our parent
|
|
if (this.propagate) {
|
|
var par = getEffectiveParent(this._name);
|
|
if (par) {
|
|
par.handle(record);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
dbug('%s filtered message [%s]', this._name, record.message);
|
|
}
|
|
},
|
|
|
|
_log: function _log(_level, msg /*, args...*/) {
|
|
var level = LEVELS.getLevel(_level);
|
|
var args;
|
|
if (arguments.length < 3) {
|
|
args = [msg];
|
|
} else {
|
|
args = new Array(arguments.length - 1);
|
|
for (var i = 0; i < args.length; i++) {
|
|
args[i] = arguments[i + 1];
|
|
}
|
|
}
|
|
var record = this.makeRecord(this._name, level, args);
|
|
this.handle(record);
|
|
},
|
|
|
|
log: function log(_level /* msg, messageArs... */) {
|
|
var level = LEVELS.getLevel(_level);
|
|
// if level >= this.getEffectiveLevel(), tell our handlers
|
|
if (this.isEnabledFor(level)) {
|
|
this._log.apply(this, arguments);
|
|
}
|
|
},
|
|
|
|
trace: function trace(_msg) {
|
|
var obj = new Trace(trace);
|
|
|
|
var slice = 0;
|
|
var message = _msg;
|
|
if (typeof message === 'string') {
|
|
// [TRACE, msg, obj, ...arguments]
|
|
slice = 1;
|
|
message = '%s' + message;
|
|
obj.toString = emptyStr;
|
|
} else {
|
|
message = '%s';
|
|
obj.toString = traceStr;
|
|
}
|
|
|
|
var args = new Array(3 + arguments.length - slice);
|
|
args[0] = LEVELS.TRACE;
|
|
args[1] = message;
|
|
args[2] = obj;
|
|
for (var i = 3; i < args.length; i++) {
|
|
args[i] = arguments[i - 3 + slice];
|
|
}
|
|
return this._log.apply(this, args);
|
|
},
|
|
|
|
verbose: logAtLevel(LEVELS.VERBOSE),
|
|
debug: logAtLevel(LEVELS.DEBUG),
|
|
info: logAtLevel(LEVELS.INFO),
|
|
warn: logAtLevel(LEVELS.WARNING),
|
|
error: logAtLevel(LEVELS.ERROR),
|
|
critical: logAtLevel(LEVELS.CRITICAL),
|
|
|
|
// aliases
|
|
warning: function warning() {
|
|
return this.warn.apply(this, arguments);
|
|
},
|
|
|
|
/*jshint -W106*/ // ignore camelCase warning for this fun functions
|
|
o_O: function o_O() {
|
|
return this.warn.apply(this, arguments);
|
|
},
|
|
|
|
O_O: function O_O() {
|
|
return this.error.apply(this, arguments);
|
|
},
|
|
|
|
_process: process
|
|
|
|
});
|
|
|
|
for (var k in LEVELS) {
|
|
if (typeof LEVELS[k] === 'number') {
|
|
Logger[k] = Logger.prototype[k] = LEVELS[k];
|
|
}
|
|
}
|
|
|
|
module.exports = Logger;
|