diff --git a/CHANGES.md b/CHANGES.md index 08e797a..50c955c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,17 +13,19 @@ recent, and thus hopefully relevant, log messages. (by @dapsays, github.com/davepacheco) - Potential uses: Live debugging - if a running process could inspect those messages. One could dump recent - log messages at a finer log level than is typically logged on + Potential uses: Live debugging if a running process could inspect those + messages. One could dump recent log messages at a finer log level than is + typically logged on [`uncaughtException`](http://nodejs.org/docs/latest/api/all.html#all_event_uncaughtexception). var ringbuffer = new bunyan.RingBuffer({ limit: 100 }); var log = new bunyan({ - name: "foo", - raw: true, - stream: ringbuffer, - level: "debug" + name: 'foo', + streams: [{ + type: 'raw', + stream: ringbuffer, + level: 'debug' + }] }); log.info('hello world'); @@ -40,16 +42,18 @@ } var log = new Logger({ name: 'mylog', - stream: new Collector(), - raw: true + streams: [{ + type: 'raw', + stream: new Collector() + }] }); See "examples/raw-stream.js". I expect raw streams to be useful for - piping Bunyan logging to separate services (e.g. , + piping Bunyan logging to separate services (e.g. , ) or to separate in-process handling. -- Add test/corpus/*.log files (accidentally excluded) so that test suite - works(!). +- Add test/corpus/*.log files (accidentally excluded) so the test suite + actually works(!). ## bunyan 0.8.0 diff --git a/README.md b/README.md index 54d3714..f291db8 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ Also: log4j is way more than you need. # Current Status -Basic functionality there. Still a fair amount of planned work, but I'm using -it for some production services. +Solid core functionality is there. Joyent is using this for a number of +production services. Currently supports node 0.4+, but I'll probably make the jump to node 0.6+ as a base soonish. @@ -420,8 +420,7 @@ In general streams are specified with the "streams" option: }) For convenience, if there is only one stream, it can specified with the -"stream", "level" and "raw" options (internal converted to a -`Logger.streams`): +"stream" and "level" options (internal converted to a `Logger.streams`): var log = new Logger({ name: "foo", @@ -434,19 +433,22 @@ If none are specified, the default is a stream on `process.stdout` at the `Logger.streams` is an array of stream objects with the following attributes: -- `type`: Typically implied. E.g. "stream" or "file". See supported types - below. +- `type`: One of "stream", "file" or "raw". See below. Often this is + implied from the other arguments. +- `path`: A file path for a file stream. If `path` is given and `type` is + not specified, then `type` will be set to "file". - `stream`: This is the "Writable Stream", e.g. a std handle or an open - file write stream. + file write stream. If `stream` is given and `type` is not specified, then + `type` will be set to "stream". - `level`: The level at which logging to this stream is enabled. If not specified it defaults to INFO. -- `raw`: A boolean indicating if the `write()` method of this stream should - be given the raw log record object instead of the JSON-stringified - string. See "examples/raw-stream.js". Supported stream types are: -- `stream`: A "stream" argument is given. +- `stream`: A plain ol' node.js [Writable + Stream](http://nodejs.org/docs/latest/api/all.html#writable_Stream). + A "stream" (the writeable stream) value is required. + - `file`: A "path" argument is given. Bunyan will open this file for appending. E.g.: @@ -463,6 +465,14 @@ Supported stream types are: // Handle stream write or create error here. }); +- `raw`: Similar to a "stream" writeable stream, except that the write method + is given raw log record *Object*s instead of a JSON-stringified string. + This can be useful for hooking on further processing to all Bunyan logging: + pushing to an external service, a RingBuffer (see below), etc. + + +## RingBuffer Stream + Bunyan comes with a special stream called a RingBuffer which keeps the last N records in memory and does *not* write the data anywhere else. One common strategy is to log 'info' and higher to a normal log file but log all records @@ -475,10 +485,18 @@ To use a RingBuffer: var bunyan = require('bunyan'); var ringbuffer = new bunyan.RingBuffer({ limit: 100 }); var log = new bunyan({ - name: "foo", - raw: true, - stream: ringbuffer, - level: "debug" + name: 'foo', + streams: [ + { + level: 'info', + stream: process.stdout + }, + { + level: 'trace', + type: 'raw', // use 'raw' to get raw log record objects + stream: ringbuffer + } + ] }); log.info('hello world'); @@ -495,11 +513,13 @@ This example emits: v: 0 } ] + # License MIT. + # Future See "TODO.md". diff --git a/examples/raw-stream.js b/examples/raw-stream.js index d5c625e..32b905b 100644 --- a/examples/raw-stream.js +++ b/examples/raw-stream.js @@ -27,7 +27,7 @@ var log = new Logger({ { level: 'info', stream: new MyRawStream(), - raw: true + type: 'raw' }, ] }); diff --git a/examples/ringbuffer.js b/examples/ringbuffer.js index 4dd7842..6364fd0 100644 --- a/examples/ringbuffer.js +++ b/examples/ringbuffer.js @@ -3,9 +3,11 @@ var bunyan = require('..'); var ringbuffer = new bunyan.RingBuffer({ limit: 100 }); var log = new bunyan({ name: 'foo', - raw: true, - stream: ringbuffer, - level: 'debug' + streams: [{ + type: 'raw', + stream: ringbuffer, + level: 'debug' + }] }); log.info('hello world'); diff --git a/lib/bunyan.js b/lib/bunyan.js index 875c8b9..5b7d1e4 100644 --- a/lib/bunyan.js +++ b/lib/bunyan.js @@ -175,13 +175,17 @@ function resolveLevel(nameOrNum) { * * @param options {Object} See documentation for full details. At minimum * this must include a 'name' string key. Configuration keys: - * - streams: specify the logger output streams. This is an array of - * objects of the form: - * { - * 'level': 'info', // optional, "info" default - * 'stream': process.stdout, // 'stream' or "path" is required - * 'closeOnExit': false // optional, default depends - * } + * - `streams`: specify the logger output streams. This is an array of + * objects with these fields: + * - `type`: The stream type. See README.md for full details. + * Often this is implied by the other fields. Examples are + * "file", "stream" and "raw". + * - `level`: Defaults to "info". + * - `path` or `stream`: The specify the file path or writeable + * stream to which log records are written. E.g. + * `stream: process.stdout`. + * - `closeOnExit` (boolean): Optional. Default is true for a + * "file" stream when `path` is given, false otherwise. * See README.md for full details. * - `level`: set the level for a single output stream (cannot be used * with `streams`) @@ -300,6 +304,7 @@ function Logger(options, _childOptions, _childSimple) { s.type = 'file' } } + s.raw = (s.type === 'raw'); // PERF: Allow for faster check in `_emit`. if (s.level) { s.level = resolveLevel(s.level); @@ -310,8 +315,6 @@ function Logger(options, _childOptions, _childSimple) { self._level = s.level; } - s.raw = !!s.raw; - switch (s.type) { case 'stream': if (!s.closeOnExit) { @@ -334,6 +337,11 @@ function Logger(options, _childOptions, _childSimple) { } } break; + case 'raw': + if (!s.closeOnExit) { + s.closeOnExit = false; + } + break; default: throw new TypeError('unknown stream type "' + s.type + '"'); } @@ -362,8 +370,7 @@ function Logger(options, _childOptions, _childSimple) { type: 'stream', stream: options.stream, closeOnExit: false, - level: (options.level ? resolveLevel(options.level) : INFO), - raw: (options.raw ? options.raw : false) + level: (options.level ? resolveLevel(options.level) : INFO) }); } else if (options.streams) { options.streams.forEach(addStream); @@ -372,8 +379,7 @@ function Logger(options, _childOptions, _childSimple) { type: 'stream', stream: process.stdout, closeOnExit: false, - level: (options.level ? resolveLevel(options.level) : INFO), - raw: (options.raw ? options.raw : false) + level: (options.level ? resolveLevel(options.level) : INFO) }); } if (options.serializers) { @@ -683,8 +689,8 @@ Logger.prototype._emit = function (rec) { for (i = 0; i < this.streams.length; i++) { var s = this.streams[i]; if (s.level <= level) { - xxx('writing log rec "%s" to "%s" stream (%s, %d <= %d): %j', - obj.msg, s.type, (s.raw ? 'raw' : 'not raw'), s.level, level, obj); + xxx('writing log rec "%s" to "%s" stream (%d <= %d): %j', + obj.msg, s.type, s.level, level, obj); s.stream.write(s.raw ? obj : str); } }; diff --git a/test/raw-stream.test.js b/test/raw-stream.test.js index 74aeee7..8eb1336 100644 --- a/test/raw-stream.test.js +++ b/test/raw-stream.test.js @@ -1,7 +1,7 @@ /* * Copyright (c) 2012 Trent Mick. All rights reserved. * - * Test `raw: true` option on a Logger stream. + * Test `type: 'raw'` Logger streams. */ var format = require('util').format; @@ -26,7 +26,7 @@ test('raw stream', function (t) { streams: [ { stream: new CapturingStream(recs), - raw: true + type: 'raw' } ] }); @@ -40,24 +40,6 @@ test('raw stream', function (t) { }); -test('raw stream (short constructor)', function (t) { - var recs = []; - - var log = new Logger({ - name: 'raw-stream-test', - stream: new CapturingStream(recs), - raw: true - }); - log.info('first'); - log.info({two: 'deux'}, 'second'); - - t.equal(recs.length, 2); - t.equal(typeof (recs[0]), 'object', 'first rec is an object'); - t.equal(recs[1].two, 'deux', '"two" field made it through'); - t.end(); -}); - - test('raw streams and regular streams can mix', function (t) { var rawRecs = []; var nonRawRecs = []; @@ -67,7 +49,7 @@ test('raw streams and regular streams can mix', function (t) { streams: [ { stream: new CapturingStream(rawRecs), - raw: true + type: 'raw' }, { stream: new CapturingStream(nonRawRecs) @@ -98,7 +80,7 @@ test('child adding a non-raw stream works', function (t) { streams: [ { stream: new CapturingStream(parentRawRecs), - raw: true + type: 'raw' } ] }); @@ -107,7 +89,7 @@ test('child adding a non-raw stream works', function (t) { streams: [ { stream: new CapturingStream(rawRecs), - raw: true + type: 'raw' }, { stream: new CapturingStream(nonRawRecs) diff --git a/test/ringbuffer.test.js b/test/ringbuffer.test.js index 3589be5..4f8ae61 100644 --- a/test/ringbuffer.test.js +++ b/test/ringbuffer.test.js @@ -11,7 +11,7 @@ var log1 = new Logger({ streams: [ { stream: ringbuffer, - raw: true, + type: 'raw', level: 'info' } ]