From 99ecaf2845e166579bd022f1c04fe7cb78e39511 Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Mon, 30 Jan 2012 12:01:15 -0800 Subject: [PATCH] log.clone --- TODO.md | 9 +++++++-- hi.js | 52 +++++++++++++-------------------------------------- lib/bunyan.js | 50 ++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 67 insertions(+), 44 deletions(-) diff --git a/TODO.md b/TODO.md index feb73c0..6ebaf4f 100644 --- a/TODO.md +++ b/TODO.md @@ -1,10 +1,15 @@ -- node-bunyan and push to priv -- .bind or equiv with diff name - info's siblings - `bunyan` cli - expand set of fields + + + require: facility and hostname - renderer support (i.e. repr of a restify request obj) - docs - feel out usage +- not sure about `log.info()` for is-enabled. Perhaps `log.isInfo()` because + can then use that for `log.isInfo(true)` for 'ring' argument. Separate level + and ringLevel. - Logger.set to mutate config or `this.fields` - Logger.del to remove a field +- test suite diff --git a/hi.js b/hi.js index b4de68e..ec5d726 100644 --- a/hi.js +++ b/hi.js @@ -1,4 +1,5 @@ var Logger = require('./lib/bunyan'); + var log = new Logger({facility: "myapp", level: "info"}); console.log("log.info() is:", log.info()) log.info("hi"); @@ -9,43 +10,16 @@ log.info({foo:"bar"}, "hi %d", 1, "two", 3); console.log("\n--\n") +function Wuzzle(options) { + this.log = options.log; + this.log.info("creating a wuzzle") +} + +Wuzzle.prototype.woos = function () { + this.log.info("This wuzzle is woosey.") +} + +var wuzzle = new Wuzzle({log: log.clone({component: "wuzzle"})}); +wuzzle.woos(); +log.info("done with the wuzzle") -//console.log("\n--\n") -//xxx = console.log; -//var INFO = 2; -// -//function foo() { -// console.log("function foo arguments:", arguments) -//} -// -//function Bar() { -// this.level = 1; -//} -//Bar.prototype.info = function (fields, msg) { -// console.log("function info arguments:", arguments) -// var msgArgs; -// if (arguments.length === 0) { // `log.info()` -// return (this.level <= INFO); -// } else if (this.level > INFO) { -// return; -// } else if (typeof fields === 'string') { // `log.info(msg, ...)` -// fields = null; -// msgArgs = Array.prototype.slice.call(arguments); -// xxx("msgArgs: ", msgArgs, arguments) -// } else { // `log.info(fields, msg, ...)` -// msgArgs = Array.prototype.slice.call(arguments, 1); -// } -// xxx("info start: arguments:", arguments.length, arguments, msgArgs) -// //var rec = this._mkRecord(fields, INFO, msgArgs); -// //this._emit(rec); -//} -// -// -//foo() -//foo("one") -//foo("one", "two") -// -//bar = new Bar(); -//bar.info() -//bar.info("one") -//bar.info("one", "two") diff --git a/lib/bunyan.js b/lib/bunyan.js index fabff4f..8d933ff 100644 --- a/lib/bunyan.js +++ b/lib/bunyan.js @@ -9,12 +9,14 @@ // "CHANGES.md" (the change log). var VERSION = 0; + var paul = function paul(s) { // internal dev/debug logging var args = ["PAUL: "+s].concat(Array.prototype.slice.call(arguments, 1)); console.error.apply(this, args); }; var paul = function paul() {}; // uncomment to turn of debug logging + var fs = require('fs'); var util = require('util'); @@ -103,11 +105,14 @@ function Logger(options) { if (! this instanceof Logger) { return new Logger(options); } + if (!options) { + throw new TypeError("options (object) is required"); + } // These are the default fields for log records (minus the attributes // removed in this constructor). To allow storing raw log records - // (unrendered), `this.fields` must never be mutated. Create a copy, if - // necessary. + // (unrendered), `this.fields` must never be mutated. Create a copy for + // any changes. this.fields = objCopy(options); if (options.stream) { @@ -127,7 +132,38 @@ function Logger(options) { } else { this.level = 2; // INFO is default level. } - paul('Logger default fields:', this.fields); + + //XXX Non-core fields should go in 'x' sub-object. +} + + +/** + * Clone this logger to a new one, additionally adding the given config + * options. + * + * This can be useful when passing a logger to a sub-component, e.g. a + * "wuzzle" component of your service: + * + * var wuzzleLog = log.clone({component: "wuzzle"}) + * var wuzzle = new Wuzzle({..., log: wuzzleLog}) + * + * Then log records from the wuzzle code will have the same structure as + * the app log, *plus the component="wuzzle" field*. + * + * @param options {Object} Optional. Set of options to apply to the clone. + * Supports the same set of options as the constructor. + */ +Logger.prototype.clone = function (options) { + paul("keys", Object.keys(this)) + var cloneOptions = objCopy(this.fields); + cloneOptions.level = this.level; + cloneOptions.stream = this.stream; + if (options) { + Object.keys(options).forEach(function(k) { + cloneOptions[k] = options[k]; + }); + } + return new Logger(cloneOptions); } @@ -145,6 +181,12 @@ Logger.prototype._mkRecord = function (fields, level, msgArgs) { return [this.fields, recFields, level, msgArgs]; } + +/** + * Emit a log record. + * + * @param rec {log record} + */ Logger.prototype._emit = function (rec) { var obj = objCopy(rec[0]); var recFields = rec[1]; @@ -160,6 +202,7 @@ Logger.prototype._emit = function (rec) { this.stream.write(JSON.stringify(obj) + '\n'); } + /** * Usages: * log.info( fields, msg, ...) @@ -183,6 +226,7 @@ Logger.prototype.info = function () { this._emit(rec); } + module.exports = Logger;