diff --git a/bin/bunyan b/bin/bunyan index a14cf79..0a36cef 100755 --- a/bin/bunyan +++ b/bin/bunyan @@ -144,6 +144,20 @@ function printHelp() { util.puts(" json-N: JSON output, N-space indent, e.g. 'json-4'"); util.puts(" inspect: node.js `util.inspect` output"); 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(""); + util.puts("Log Levels:"); + util.puts(" Either numeric values or their associated strings are valid for the"); + util.puts(" -l --level argument."); + 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("See for more complete docs."); } @@ -176,6 +190,15 @@ function gotRecord(file, line, rec, opts, stylize) emitNextRecord(opts, stylize); } +function filterRecord(rec, opts) +{ + if (opts.level && rec.level < opts.level) { + return false; + } + + return true; +} + function emitNextRecord(opts, stylize) { var ofile, ready, minfile, rec; @@ -252,13 +275,14 @@ function parseArgv(argv) { help: false, color: process.stdout.isTTY, outputMode: OM_PAUL, - jsonIndent: 2 + jsonIndent: 2, + level: -Infinity }; // Turn '-iH' into '-i -H', except for argument-accepting options. var args = argv.slice(2); // drop ['node', 'scriptname'] var newArgs = []; - var optTakesArg = {'d': true, 'o': true}; + var optTakesArg = {'d': true, 'o': true, 'l': true}; for (var i = 0; i < args.length; i++) { if (args[i].charAt(0) === "-" && args[i].charAt(1) !== '-' && args[i].length > 2) { var splitOpts = args[i].slice(1).split(""); @@ -317,6 +341,18 @@ function parseArgv(argv) { case "-j": // output with JSON.stringify parsed.outputMode = OM_JSON; 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; default: // arguments if (!endOfOptions && arg.length > 0 && arg[0] === '-') { throw new Error("unknown option '"+arg+"'"); @@ -411,7 +447,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 gotRecord(file, line, rec, opts, stylize); diff --git a/test/cli.test.js b/test/cli.test.js index 1f29db9..89cf860 100644 --- a/test/cli.test.js +++ b/test/cli.test.js @@ -200,3 +200,29 @@ test('mixed text and gzip logs', function (t) { 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(); + }); + }); +});