add ring buffer stream

This commit is contained in:
Dave Pacheco 2012-06-19 14:36:02 -07:00
parent f8de9a35d5
commit f1996fccef
5 changed files with 133 additions and 1 deletions

View file

@ -459,6 +459,36 @@ Supported stream types are:
// Handle stream write or create error here. // Handle stream write or create error here.
}); });
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
(including 'trace') to a ringbuffer that you can access via a debugger, or your
own HTTP interface, or a post-mortem facility like MDB or node-panic.
To use a RingBuffer:
/* Create a ring buffer that stores the last 100 entries. */
var bunyan = require('bunyan');
var ringbuffer = new bunyan.RingBuffer({ limit: 100 });
var log = new bunyan({
name: "foo",
stream: ringbuffer,
level: "debug"
});
log.info('hello world');
console.log(ringbuffer.entries);
This example emits:
[ { name: 'foo',
hostname: '912d2b29',
pid: 50346,
level: 30,
msg: 'hello world',
time: '2012-06-19T21:34:19.906Z',
v: 0 } ]
# License # License

View file

@ -15,7 +15,6 @@
works *and* that an existing field in the parent is not *re-serialized*. works *and* that an existing field in the parent is not *re-serialized*.
- a "rolling-file" stream: but specifically by time, e.g. hourly. (MarkC - a "rolling-file" stream: but specifically by time, e.g. hourly. (MarkC
requested) requested)
- ringBuffer stream
- split out `bunyan` cli to a "bunyan" or "bunyan-reader" or "node-bunyan-reader" - split out `bunyan` cli to a "bunyan" or "bunyan-reader" or "node-bunyan-reader"
as the basis for tools to consume bunyan logs. It can grow indep of node-bunyan as the basis for tools to consume bunyan logs. It can grow indep of node-bunyan
for generating the logs. for generating the logs.

11
examples/ringbuffer.js Normal file
View file

@ -0,0 +1,11 @@
/* Create a ring buffer that stores the last 100 entries. */
var bunyan = require('..');
var ringbuffer = new bunyan.RingBuffer({ limit: 100 });
var log = new bunyan({
name: 'foo',
stream: ringbuffer,
level: 'debug'
});
log.info('hello world');
console.log(ringbuffer.entries);

View file

@ -954,6 +954,58 @@ var errSerializer = Logger.stdSerializers.err = function err(err) {
}; };
/**
* RingBuffer is a Writable Stream that just stores the last N entries in
* memory.
*
* @param options {Object}, with the following fields:
*
* - limit: number of entries to keep in memory
*/
function RingBuffer(options) {
this.limit = options && options.limit ? options.limit : 100;
this.writable = true;
this.entries = [];
EventEmitter.call(this);
}
util.inherits(RingBuffer, EventEmitter);
RingBuffer.prototype.write = function (str) {
var json;
if (!this.writable)
throw (new Error('RingBuffer has been ended already'));
try {
json = JSON.parse(str);
this.entries.push(json);
} catch (ex) {
this.entries.push(str);
}
if (this.entries.length > this.limit)
this.entries.shift();
return (true);
};
RingBuffer.prototype.end = function () {
if (arguments.length > 0)
this.write.apply(this, Array.prototype.slice.call(arguments));
this.writable = false;
};
RingBuffer.prototype.destroy = function () {
this.writable = false;
this.emit('close');
};
RingBuffer.prototype.destroySoon = function () {
this.destroy();
this.emit('close');
};
//---- Exports //---- Exports
@ -972,3 +1024,5 @@ module.exports.LOG_VERSION = LOG_VERSION;
module.exports.createLogger = function createLogger(options) { module.exports.createLogger = function createLogger(options) {
return new Logger(options); return new Logger(options);
}; };
module.exports.RingBuffer = RingBuffer;

38
test/ringbuffer.test.js Normal file
View file

@ -0,0 +1,38 @@
/*
* Test the RingBuffer output stream.
*/
var test = require('tap').test;
var Logger = require('../lib/bunyan');
var ringbuffer = new Logger.RingBuffer({ 'limit': 5 });
var log1 = new Logger({
name: 'log1',
streams: [
{
stream: ringbuffer,
level: 'info'
}
]
});
test('ringbuffer', function (t) {
log1.info('hello');
log1.trace('there');
log1.error('chucklebucket');
t.equal(ringbuffer.entries.length, 2);
t.equal(ringbuffer.entries[0]['msg'], 'hello');
t.equal(ringbuffer.entries[1]['msg'], 'chucklebucket');
log1.error('one');
log1.error('two');
log1.error('three');
t.equal(ringbuffer.entries.length, 5);
log1.error('four');
t.equal(ringbuffer.entries.length, 5);
t.equal(ringbuffer.entries[0]['msg'], 'chucklebucket');
t.equal(ringbuffer.entries[1]['msg'], 'one');
t.equal(ringbuffer.entries[2]['msg'], 'two');
t.equal(ringbuffer.entries[3]['msg'], 'three');
t.equal(ringbuffer.entries[4]['msg'], 'four');
t.end();
});