diff --git a/CHANGES.md b/CHANGES.md index ea7d76a..9735516 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,8 @@ ## bunyan 0.9.0 (not yet released) +- [pull #16] Bullet proof the `bunyan.stdSerializers` (by github.com/rlidwka). + - [pull #15] The `bunyan` CLI will now chronologically merge multiple log streams when it is given multiple file arguments. (by github.com/davepacheco) diff --git a/lib/bunyan.js b/lib/bunyan.js index f950d67..93ccdae 100644 --- a/lib/bunyan.js +++ b/lib/bunyan.js @@ -942,6 +942,7 @@ Logger.stdSerializers = {}; // Serialize an HTTP request. Logger.stdSerializers.req = function req(req) { + if (!req || !req.connection) return req; return { method: req.method, url: req.url, @@ -958,6 +959,7 @@ Logger.stdSerializers.req = function req(req) { // Serialize an HTTP response. Logger.stdSerializers.res = function res(res) { + if (!res || !res.statusCode) return res; return { statusCode: res.statusCode, header: res._header @@ -967,6 +969,7 @@ Logger.stdSerializers.res = function res(res) { // Serialize an Error object // (Core error properties are enumerable in node 0.4, not in 0.6). var errSerializer = Logger.stdSerializers.err = function err(err) { + if (!err || !err.stack) return err; var obj = { message: err.message, name: err.name, diff --git a/test/std-serializers.test.js b/test/std-serializers.test.js new file mode 100644 index 0000000..132bb4f --- /dev/null +++ b/test/std-serializers.test.js @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2012 Trent Mick. All rights reserved. + * + * Test the standard serializers in Bunyan. + */ + +var test = require('tap').test; +var bunyan = require('../lib/bunyan'); +var http = require('http'); + + +function CapturingStream(recs) { + this.recs = recs; +} +CapturingStream.prototype.write = function (rec) { + this.recs.push(rec); +} + + +test('req serializer', function (t) { + var records = []; + var log = bunyan.createLogger({ + name: 'serializer-test', + streams: [ + { + stream: new CapturingStream(records), + type: 'raw' + } + ], + serializers: { + req: bunyan.stdSerializers.req + } + }); + + // None of these should blow up. + var bogusReqs = [ + undefined, + null, + {}, + 1, + 'string', + [1,2,3], + {'foo':'bar'} + ]; + for (var i = 0; i < bogusReqs.length; i++) { + log.info({req: bogusReqs[i]}, "hi"); + t.equal(records[i].req, bogusReqs[i]); + } + + // Get http request and response objects to play with and test. + var theReq, theRes; + var server = http.createServer(function (req, res) { + theReq = req; + theRes = res; + res.writeHead(200, {'Content-Type': 'text/plain'}); + res.end('Hello World\n'); + }) + server.listen(8765, function () { + http.get({host: '127.0.0.1', port: 8765, path: '/'}, function(res) { + log.info({req: theReq}, 'the request'); + var lastRecord = records[records.length-1]; + t.equal(lastRecord.req.method, 'GET'); + t.equal(lastRecord.req.url, theReq.url); + t.equal(lastRecord.req.remoteAddress, theReq.connection.remoteAddress); + t.equal(lastRecord.req.remotePort, theReq.connection.remotePort); + server.close(); + t.end(); + }).on('error', function (err) { + t.ok(false, 'error requesting to our test server: ' + err); + server.close(); + t.end(); + }); + }); +}); + + +test('res serializer', function (t) { + var records = []; + var log = bunyan.createLogger({ + name: 'serializer-test', + streams: [ + { + stream: new CapturingStream(records), + type: 'raw' + } + ], + serializers: { + res: bunyan.stdSerializers.res + } + }); + + // None of these should blow up. + var bogusRess = [ + undefined, + null, + {}, + 1, + 'string', + [1,2,3], + {'foo':'bar'} + ]; + for (var i = 0; i < bogusRess.length; i++) { + log.info({res: bogusRess[i]}, "hi"); + t.equal(records[i].res, bogusRess[i]); + } + + // Get http request and response objects to play with and test. + var theReq, theRes; + var server = http.createServer(function (req, res) { + theReq = req; + theRes = res; + res.writeHead(200, {'Content-Type': 'text/plain'}); + res.end('Hello World\n'); + }) + server.listen(8765, function () { + http.get({host: '127.0.0.1', port: 8765, path: '/'}, function(res) { + log.info({res: theRes}, 'the response'); + var lastRecord = records[records.length-1]; + t.equal(lastRecord.res.statusCode, theRes.statusCode); + t.equal(lastRecord.res.header, theRes._header); + server.close(); + t.end(); + }).on('error', function (err) { + t.ok(false, 'error requesting to our test server: ' + err); + server.close(); + t.end(); + }); + }); +}); + + +test('err serializer', function (t) { + var records = []; + var log = bunyan.createLogger({ + name: 'serializer-test', + streams: [ + { + stream: new CapturingStream(records), + type: 'raw' + } + ], + serializers: { + err: bunyan.stdSerializers.err + } + }); + + // None of these should blow up. + var bogusErrs = [ + undefined, + null, + {}, + 1, + 'string', + [1,2,3], + {'foo':'bar'} + ]; + for (var i = 0; i < bogusErrs.length; i++) { + log.info({err: bogusErrs[i]}, "hi"); + t.equal(records[i].err, bogusErrs[i]); + } + + var theErr = new TypeError('blah'); + + log.info(theErr, 'the error'); + var lastRecord = records[records.length-1]; + t.equal(lastRecord.err.message, theErr.message); + t.equal(lastRecord.err.name, theErr.name); + t.equal(lastRecord.err.stack, theErr.stack); + t.end(); +});