diff --git a/bin/bunyan b/bin/bunyan index 46d1f4db..6bb6006e 100755 --- a/bin/bunyan +++ b/bin/bunyan @@ -25,6 +25,7 @@ var child_process = require('child_process'), exec = child_process.exec, execFile = child_process.execFile; var assert = require('assert'); +var _ = null; var nodeSpawnSupportsStdio = ( Number(process.version.split('.')[0]) >= 0 || @@ -44,6 +45,7 @@ var OM_INSPECT = 3; var OM_SIMPLE = 4; var OM_SHORT = 5; var OM_BUNYAN = 6; +var OM_CUSTOM = 7; var OM_FROM_NAME = { 'long': OM_LONG, 'paul': OM_LONG, /* backward compat */ @@ -51,7 +53,8 @@ var OM_FROM_NAME = { 'inspect': OM_INSPECT, 'simple': OM_SIMPLE, 'short': OM_SHORT, - 'bunyan': OM_BUNYAN + 'bunyan': OM_BUNYAN, + 'custom': OM_CUSTOM }; @@ -225,6 +228,14 @@ function printHelp() { p(' bunyan: 0 indented JSON, bunyan\'s native format'); p(' inspect: node.js `util.inspect` output'); p(' short: like "long", but more concise'); + p(' custom: use custom template defined with --template'); + p(' -t, --template TEMPLATE'); + p(' Custom template (you need to set -o custom)'); + p(' Let you define your own templates, using mustache-like syntax.'); + p(' Keys from the current object will be the template free variable.'); + p(' You can put arbitrary code between {{ }}.'); + p(' Use _cS to start a color, and _cE to stop a color.'); + p(' Example: {{ _cS(\'grey\') }}{{ req.username }}{{ _cE(\'grey\') }}'); p(' -j shortcut for `-o json`'); p(' -0 shortcut for `-o bunyan`'); p(''); @@ -484,6 +495,20 @@ function parseArgv(argv) { throw new Error('unknown output mode: "'+name+'"'); } break; + case '-t': + case '--template': + try { + _ = require('underscore'); + } catch(e) { + throw new Error("you need to install 'underscore' to use the custom template."); + } + // Who want ERB? (not me) + // Let's go for mustache style parsing! + _.templateSettings = { + interpolate: /\{\{(.+?)\}\}/g + }; + parsed.template = _.template(args.shift()); + break; case '-j': // output with JSON.stringify parsed.outputMode = OM_JSON; break; @@ -618,17 +643,33 @@ function stylizeWithColor(str, color) { return ''; var codes = colors[color]; if (codes) { - return '\033[' + codes[0] + 'm' + str + - '\033[' + codes[1] + 'm'; + return stylizeWithColor.start(color) + str + stylizeWithColor.end(color); } else { return str; } } +stylizeWithColor.start = function(color) { + var codes = colors[color]; + if (codes) { + return '\033[' + codes[0] + 'm'; + } +}; + +stylizeWithColor.end = function(color) { + var codes = colors[color]; + if (codes) { + return '\033[' + codes[1] + 'm'; + } +}; + + function stylizeWithoutColor(str, color) { return str; } +stylizeWithoutColor.start = stylizeWithoutColor.end = function() {}; + /** * Is this a valid Bunyan log record. @@ -1018,6 +1059,29 @@ function emitRecord(rec, line, opts, stylize) { upperNameFromLevel[rec.level] || 'LVL' + rec.level, rec.msg)); break; + + case OM_CUSTOM: + if (!isValidRecord(rec)) { + return emit(line + '\n'); + } + + // Shortcut for "colorStart" + rec._cS = stylize.start; + // Shortcut for "colorEnd" + rec._cE = stylize.end; + // Shortcut for easy date access + rec._time = new Date(rec.time); + + var out; + try { + out = opts.template ? opts.template(rec) : 'No template defined. Use --template.'; + } + catch(e) { + // Unprocessable line, display default + return emit(line + '\n'); + } + emit(out + '\n'); + break; default: throw new Error('unknown output mode: '+opts.outputMode); } diff --git a/package.json b/package.json index f60e6c59..838dbc2f 100644 --- a/package.json +++ b/package.json @@ -14,11 +14,12 @@ }, "engines": ["node >=0.8.0"], "keywords": ["log", "logging", "log4j", "json", "bunyan"], - "// comment1": "'dtrace-provider' required for dtrace features", - "// comment2": "'mv' required for RotatingFileStream", + "// comment2": "'underscore' required for custom templating in Bunyan CLI", + "// comment3": "'mv' required for RotatingFileStream", "optionalDependencies": { "dtrace-provider": "~0.3 >0.3.0", + "underscore": "^1.7.0", "mv": "~2" }, "devDependencies": {