Merge pull request #29 from isaacs/cli-filtering
Filtering with -l|--level and -c|--condition
This commit is contained in:
commit
de4a2280a2
3 changed files with 144 additions and 3 deletions
69
bin/bunyan
69
bin/bunyan
|
@ -144,6 +144,24 @@ function printHelp() {
|
||||||
util.puts(" json-N: JSON output, N-space indent, e.g. 'json-4'");
|
util.puts(" json-N: JSON output, N-space indent, e.g. 'json-4'");
|
||||||
util.puts(" inspect: node.js `util.inspect` output");
|
util.puts(" inspect: node.js `util.inspect` output");
|
||||||
util.puts(" -j shortcut for `-o json`");
|
util.puts(" -j shortcut for `-o json`");
|
||||||
|
util.puts(" -l, --level LEVEL");
|
||||||
|
util.puts(" Only show messages at or above the specified level.");
|
||||||
|
util.puts(" (See 'Log Levels' below.)");
|
||||||
|
util.puts(" -c, --condition CONDITION");
|
||||||
|
util.puts(" Run each log message through the condition");
|
||||||
|
util.puts(" and only show those that resolve to a truish value.");
|
||||||
|
util.puts("");
|
||||||
|
util.puts("Log Levels:");
|
||||||
|
util.puts(" Either numeric values or their associated strings are valid for the");
|
||||||
|
util.puts(" -l --level argument. However, --condition scripts will see a numeric");
|
||||||
|
util.puts(" 'level' value, not a string.");
|
||||||
|
util.puts("");
|
||||||
|
Object.keys(levelFromName).forEach(function(name) {
|
||||||
|
var n = name;
|
||||||
|
while (n.length < 6)
|
||||||
|
n += " ";
|
||||||
|
console.log(" %s %d", n, levelFromName[name]);
|
||||||
|
});
|
||||||
util.puts("");
|
util.puts("");
|
||||||
util.puts("See <https://github.com/trentm/node-bunyan> for more complete docs.");
|
util.puts("See <https://github.com/trentm/node-bunyan> for more complete docs.");
|
||||||
}
|
}
|
||||||
|
@ -176,6 +194,23 @@ function gotRecord(file, line, rec, opts, stylize)
|
||||||
emitNextRecord(opts, stylize);
|
emitNextRecord(opts, stylize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function filterRecord(rec, opts)
|
||||||
|
{
|
||||||
|
if (opts.level && rec.level < opts.level) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.conditions) {
|
||||||
|
for (var i = 0; i < opts.conditions.length; i++) {
|
||||||
|
var pass = opts.conditions[i].runInNewContext(rec);
|
||||||
|
if (!pass)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
function emitNextRecord(opts, stylize)
|
function emitNextRecord(opts, stylize)
|
||||||
{
|
{
|
||||||
var ofile, ready, minfile, rec;
|
var ofile, ready, minfile, rec;
|
||||||
|
@ -252,13 +287,15 @@ function parseArgv(argv) {
|
||||||
help: false,
|
help: false,
|
||||||
color: process.stdout.isTTY,
|
color: process.stdout.isTTY,
|
||||||
outputMode: OM_PAUL,
|
outputMode: OM_PAUL,
|
||||||
jsonIndent: 2
|
jsonIndent: 2,
|
||||||
|
level: -Infinity,
|
||||||
|
conditions: null
|
||||||
};
|
};
|
||||||
|
|
||||||
// Turn '-iH' into '-i -H', except for argument-accepting options.
|
// Turn '-iH' into '-i -H', except for argument-accepting options.
|
||||||
var args = argv.slice(2); // drop ['node', 'scriptname']
|
var args = argv.slice(2); // drop ['node', 'scriptname']
|
||||||
var newArgs = [];
|
var newArgs = [];
|
||||||
var optTakesArg = {'d': true, 'o': true};
|
var optTakesArg = {'d': true, 'o': true, 'c': true, 'l': true};
|
||||||
for (var i = 0; i < args.length; i++) {
|
for (var i = 0; i < args.length; i++) {
|
||||||
if (args[i].charAt(0) === "-" && args[i].charAt(1) !== '-' && args[i].length > 2) {
|
if (args[i].charAt(0) === "-" && args[i].charAt(1) !== '-' && args[i].length > 2) {
|
||||||
var splitOpts = args[i].slice(1).split("");
|
var splitOpts = args[i].slice(1).split("");
|
||||||
|
@ -317,6 +354,26 @@ function parseArgv(argv) {
|
||||||
case "-j": // output with JSON.stringify
|
case "-j": // output with JSON.stringify
|
||||||
parsed.outputMode = OM_JSON;
|
parsed.outputMode = OM_JSON;
|
||||||
break;
|
break;
|
||||||
|
case "-l":
|
||||||
|
case "--level":
|
||||||
|
var levelArg = args.shift();
|
||||||
|
var level = +(levelArg);
|
||||||
|
if (isNaN(level)) {
|
||||||
|
level = +levelFromName[levelArg.toLowerCase()];
|
||||||
|
}
|
||||||
|
if (isNaN(level)) {
|
||||||
|
throw new Error("unknown level value: '"+levelArg+"'");
|
||||||
|
}
|
||||||
|
parsed.level = level;
|
||||||
|
break;
|
||||||
|
case "-c":
|
||||||
|
case "--condition":
|
||||||
|
var condition = args.shift();
|
||||||
|
parsed.conditions = parsed.conditions || []
|
||||||
|
var scriptName = 'bunyan-condition-'+parsed.conditions.length;
|
||||||
|
var script = vm.createScript(condition, scriptName);
|
||||||
|
parsed.conditions.push(script);
|
||||||
|
break
|
||||||
default: // arguments
|
default: // arguments
|
||||||
if (!endOfOptions && arg.length > 0 && arg[0] === '-') {
|
if (!endOfOptions && arg.length > 0 && arg[0] === '-') {
|
||||||
throw new Error("unknown option '"+arg+"'");
|
throw new Error("unknown option '"+arg+"'");
|
||||||
|
@ -411,7 +468,13 @@ function handleLogLine(file, line, opts, stylize) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file === null || !isValidRecord(rec))
|
if (!isValidRecord(rec))
|
||||||
|
return emitRecord(rec, line, opts, stylize);
|
||||||
|
|
||||||
|
if (!filterRecord(rec, opts))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (file === null)
|
||||||
return emitRecord(rec, line, opts, stylize);
|
return emitRecord(rec, line, opts, stylize);
|
||||||
|
|
||||||
return gotRecord(file, line, rec, opts, stylize);
|
return gotRecord(file, line, rec, opts, stylize);
|
||||||
|
|
|
@ -18,5 +18,9 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"tap": "0.2.0",
|
"tap": "0.2.0",
|
||||||
"ben": "0.0.0"
|
"ben": "0.0.0"
|
||||||
|
},
|
||||||
|
|
||||||
|
"scripts": {
|
||||||
|
"test": "tap test/*.js"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -200,3 +200,77 @@ test('mixed text and gzip logs', function (t) {
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('--level 40', function (t) {
|
||||||
|
expect = [
|
||||||
|
'# levels\n',
|
||||||
|
'[2012-02-08T22:56:53.856Z] WARN: myservice/123 on example.com: My message\n',
|
||||||
|
'[2012-02-08T22:56:54.856Z] ERROR: myservice/123 on example.com: My message\n',
|
||||||
|
'[2012-02-08T22:56:55.856Z] LVL55: myservice/123 on example.com: My message\n',
|
||||||
|
'[2012-02-08T22:56:56.856Z] FATAL: myservice/123 on example.com: My message\n',
|
||||||
|
'\n',
|
||||||
|
'# extra fields\n',
|
||||||
|
'\n',
|
||||||
|
'# bogus\n',
|
||||||
|
'not a JSON line\n',
|
||||||
|
'{"hi": "there"}\n'
|
||||||
|
].join('');
|
||||||
|
exec(BUNYAN + ' -l 40 corpus/all.log', function (err, stdout, stderr) {
|
||||||
|
t.error(err);
|
||||||
|
t.equal(stdout, expect);
|
||||||
|
t.end();
|
||||||
|
exec(BUNYAN + ' --level 40 corpus/all.log', function (err, stdout, stderr) {
|
||||||
|
t.error(err);
|
||||||
|
t.equal(stdout, expect);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('--condition "level === 10 && pid === 123"', function (t) {
|
||||||
|
var expect = [
|
||||||
|
'# levels\n',
|
||||||
|
'[2012-02-08T22:56:50.856Z] TRACE: myservice/123 on example.com: My message\n',
|
||||||
|
'\n',
|
||||||
|
'# extra fields\n',
|
||||||
|
'\n',
|
||||||
|
'# bogus\n',
|
||||||
|
'not a JSON line\n',
|
||||||
|
'{"hi": "there"}\n'
|
||||||
|
].join('');
|
||||||
|
exec(BUNYAN + ' -c "level === 10 && pid === 123" corpus/all.log',
|
||||||
|
function (err, stdout, stderr) {
|
||||||
|
t.error(err);
|
||||||
|
t.equal(stdout, expect);
|
||||||
|
t.end();
|
||||||
|
exec(BUNYAN + ' --condition "level === 10 && pid === 123" corpus/all.log',
|
||||||
|
function (err, stdout, stderr) {
|
||||||
|
t.error(err);
|
||||||
|
t.equal(stdout, expect);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// multiple
|
||||||
|
// not sure if this is a bug or a feature. let's call it a feature!
|
||||||
|
test('multiple --conditions', function (t) {
|
||||||
|
var expect = [
|
||||||
|
'# levels\n',
|
||||||
|
'[2012-02-08T22:56:53.856Z] WARN: myservice/1 on example.com: My message\n',
|
||||||
|
'\n',
|
||||||
|
'# extra fields\n',
|
||||||
|
'\n',
|
||||||
|
'# bogus\n',
|
||||||
|
'not a JSON line\n',
|
||||||
|
'{"hi": "there"}\n'
|
||||||
|
].join('');
|
||||||
|
t.end();
|
||||||
|
exec(BUNYAN + ' test/corpus/all.log ' +
|
||||||
|
'-c "if (level === 40) pid = 1; true" ' +
|
||||||
|
'-c "pid === 1"', function (err, stdout, stderr) {
|
||||||
|
t.error(err);
|
||||||
|
t.equal(stdout, expect);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in a new issue