fh-fhc
Version:
A Command Line Interface for FeedHenry
219 lines (198 loc) • 5.47 kB
JavaScript
/*
log levels:
0,1,2,3
verbose,info,warn,error
Default setting for logs is "info"
Default setting to show is "info"
Possible values of level/loglevel:
silly,verbose,info,warn,error,win,silent
silent quiets everything
*/
// TODO review and refactor module. See output.js and error-handler.js for other related areas for refactoring
module.exports = log;
var _ = require('underscore');
var output = require("./output.js");
function colorize(msg, color) {
return msg ? "\x1b["+color+"m"+msg+"\x1b[0m" : "";
}
var l = -1
, LEVEL = { silly : l++
, verbose : l++
, info : l++
, WARN : l++
, "ERR!" : l++
, ERROR : "ERR!"
, ERR : "ERR!"
, win : 0x15AAC5
, paused : 0x19790701
, silent : 0xDECAFBAD
}
, COLOR = {}
, SHOWLEVEL
, normalNames = {};
log.LEVEL = LEVEL;
normalNames[LEVEL["ERR!"]] = "error";
normalNames[LEVEL.WARN] = "warn";
normalNames[LEVEL.info] = "info";
normalNames[LEVEL.verbose] = "verbose";
normalNames[LEVEL.silly] = "silly";
normalNames[LEVEL.win] = "win";
Object.keys(LEVEL).forEach(function(l) {
if (typeof LEVEL[l] === "string") {
LEVEL[l] = LEVEL[LEVEL[l]];
} else {
LEVEL[LEVEL[l]] = l;
}
LEVEL[l.toLowerCase()] = LEVEL[l];
if (l === "silent" || l === "paused") {
return;
}
log[l] = log[l.toLowerCase()] =
function(msg, pref, cb) {
return log(msg, pref, l, cb);
};
});
COLOR[LEVEL.silly] = 30;
COLOR[LEVEL.verbose] = "34;40";
COLOR[LEVEL.info] = 32;
COLOR[LEVEL.warn] = "30;41";
COLOR[LEVEL.error] = "31;40";
_.keys(COLOR, function(c) {
COLOR[LEVEL[c]] = COLOR[c];
});
COLOR.fhc = "37;40";
COLOR.pref = 35;
var logBuffer = [];
var ini = require("./ini");
var waitForConfig;
log.waitForConfig = function() {
waitForConfig = true;
};
// now the required stuff has been loaded,
// so the transitive module dep will work
var util = require("util");
var fhc = require("../fhc");
Object.defineProperty(log, "level",
{
get : function() {
if (typeof SHOWLEVEL !== "undefined") {
return SHOWLEVEL;
}
var show = fhc.config && fhc.config.get("loglevel") || 'warn';
show = show.split(",")[0];
if (!isNaN(show)) {
show = +show;
} else if (!LEVEL.hasOwnProperty(show)) {
util.error("Invalid loglevel config: "+JSON.stringify(show));
show = "info";
}
if (isNaN(show)) {
show = LEVEL[show];
} else {
show = +show;
}
if (!waitForConfig || ini.resolved) {
SHOWLEVEL = show;
}
return show;
},
set : function(l) {
SHOWLEVEL = undefined;
fhc.config.set("showlevel", l);
}
});
function log(msg, pref, level, cb) {
if (typeof level === "function") {
cb = level;
level = null;
}
var show = log.level;
if (show === LEVEL.silent || show === LEVEL.paused) {
return cb && cb();
}
if (level === null) {
level = LEVEL.info;
}
if (isNaN(level)) {
level = LEVEL[level];
} else {
level = +level;
}
// logging just undefined is almost never the right thing.
// a lot of these are kicking around throughout the codebase
// with relatively unhelpful prefixes.
if (msg === undefined && level > LEVEL.silly) {
msg = new Error("undefined log message");
}
if (typeof msg === "object" && (msg instanceof Error)) {
level = LEVEL.error;
}
if (!ini.resolved && waitForConfig || level === LEVEL.paused) {
return logBuffer.push([msg, pref, level, cb]);
}
if (logBuffer.length && !logBuffer.discharging) {
logBuffer.push([msg, pref, level, cb]);
logBuffer.discharging = true;
logBuffer.forEach(function(l) {
log.apply(null, l);
});
logBuffer.length = 0;
delete logBuffer.discharging;
return;
}
log.level = show;
fhc.emit("log", { level : level, msg : msg, pref : pref, cb : cb });
fhc.emit("log."+normalNames[level], { msg : msg, pref : pref, cb : cb });
}
var loglog = log.history = [];
var loglogLen = 0;
fhc.on("log", function(logData) {
var level = logData.level
, msg = logData.msg
, pref = logData.pref
, cb = logData.cb || function() {}
, show = log.level
, spaces = " "
, logFD = fhc.config.get("logfd");
if (msg instanceof Error) {
if (fhc.config.get('stack')) {
msg = logData.msg = msg.stack || msg.toString();
} else {
msg = logData.msg || msg.stack || msg.toString();
msg = msg.toString();
}
}
loglog.push(logData);
loglogLen ++;
if (loglogLen > 2000) {
loglog = loglog.slice(loglogLen - 1000);
loglogLen = 1000;
}
if (!isFinite(level) || level < show) {
return cb();
}
if (typeof msg !== "string" && !(msg instanceof Error)) {
msg = util.inspect(msg, 0, 4, true);
}
// console.error("level, showlevel, show", level, show, (level >= show))
pref = colorize("fhc", COLOR.fhc)
+ (COLOR[level] ? " "+colorize(
(LEVEL[level]+spaces).substr(0,4), COLOR[level]) : "")
+ (pref && COLOR.pref ? " " + colorize(pref, COLOR.pref) : "");
if (msg.indexOf("\n") !== -1) {
msg = msg.split(/\n/).join("\n"+pref+" ");
}
msg = pref+" "+msg;
return output.write(msg, logFD, cb);
});
log.er = function(cb, msg) {
if (!msg) {
throw new Error("Logging message required");
}
return function(er) {
if (er) {
log.error(msg);
}
cb.apply(this, arguments);
};
};