diff --git a/CHANGES.md b/CHANGES.md index 3639565..a50701b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,7 +8,15 @@ Known issues: ## bunyan 0.18.3 (not yet released) -(nothing yet) +- Change the `bunyan.stdSerializers.err` serializer for errors to *exclude* + [the "domain*" keys](http://nodejs.org/docs/latest/api/all.html#all_additions_to_error_objects). + `err.domain` will include its assigned members which can arbitrarily large + objects that are not intended for logging. + +- Make the "dtrace-provider" dependency optional. I hate to do this, but + installing bunyan on Windows is made very difficult with this as a required + dep. Even though "dtrace-provider" stubs out for non-dtrace-y platforms, + without a compiler and Python around, node-gyp just falls over. ## bunyan 0.18.2 diff --git a/TODO.md b/TODO.md index fd74079..834ac52 100644 --- a/TODO.md +++ b/TODO.md @@ -1,3 +1,4 @@ +- upgrade to dtrace-provider@0.2.8 when it comes for 0.9 compat - man page for the bunyan CLI (refer to it in the readme) - `tail -f`-like support - 1.0 with `v: 1` in log records. Fwd/bwd compat in `bunyan` CLI diff --git a/bin/bunyan b/bin/bunyan index 98e1256..f066c1f 100755 --- a/bin/bunyan +++ b/bin/bunyan @@ -786,8 +786,10 @@ function emitRecord(rec, line, opts, stylize) { client_req.url, client_req.httpVersion || "1.1", hostHeaderLine, - Object.keys(headers).map( - function (h) { return h + ': ' + headers[h]; }).join('\n')); + (headers + ? Object.keys(headers).map( + function (h) { return h + ': ' + headers[h]; }).join('\n') + : '')); delete client_req.method; delete client_req.url; delete client_req.httpVersion; diff --git a/lib/bunyan.js b/lib/bunyan.js index a3e0d1c..d087bf0 100644 --- a/lib/bunyan.js +++ b/lib/bunyan.js @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Trent Mick. All rights reserved. + * Copyright (c) 2013 Trent Mick. All rights reserved. * * The bunyan logging library for node.js. */ @@ -627,26 +627,18 @@ Logger.prototype.levels = function levels(name, value) { * Pre-condition: This is only called if there is at least one serializer. * * @param fields (Object) The log record fields. - * @param keys (Array) Optional array of keys to which to limit processing. + * @param excludeFields (Object) Optional mapping of keys to `true` for + * keys to NOT apply a serializer. */ -Logger.prototype._applySerializers = function (fields, keys) { +Logger.prototype._applySerializers = function (fields, excludeFields) { var self = this; - // Mapping of keys to potentially serialize. - var applyKeys = fields; - if (keys) { - applyKeys = {}; - for (var i = 0; i < keys.length; i++) { - applyKeys[keys[i]] = true; - } - } - - xxx('_applySerializers: applyKeys', applyKeys); + xxx('_applySerializers: excludeFields', excludeFields); // Check each serializer against these (presuming number of serializers // is typically less than number of fields). Object.keys(this.serializers).forEach(function (name) { - if (applyKeys[name]) { + if (!excludeFields || !excludeFields[name]) { xxx('_applySerializers; apply to "%s" key', name) try { fields[name] = self.serializers[name](fields[name]); @@ -732,9 +724,11 @@ function mkLogEmitter(minLevel) { var log = this; function mkRecord(args) { + var excludeFields; if (args[0] instanceof Error) { // `log.(err, ...)` fields = {err: errSerializer(args[0])}; + excludeFields = {err: true}; if (args.length === 1) { msgArgs = [fields.err.message]; } else { @@ -759,7 +753,7 @@ function mkLogEmitter(minLevel) { var recFields = (fields ? objCopy(fields) : null); if (recFields) { if (log.serializers) { - log._applySerializers(recFields); + log._applySerializers(recFields, excludeFields); } Object.keys(recFields).forEach(function (k) { rec[k] = recFields[k]; @@ -885,6 +879,14 @@ function getFullErrorStack(ex) // Serialize an Error object // (Core error properties are enumerable in node 0.4, not in 0.6). +var errSkips = { + // Skip domain keys. `domain` especially can have huge objects that can + // OOM your app when trying to JSON.stringify. + domain: true, + domain_emitter: true, + domain_bound: true, + domain_thrown: true +}; var errSerializer = Logger.stdSerializers.err = function err(err) { if (!err || !err.stack) return err; @@ -894,7 +896,7 @@ var errSerializer = Logger.stdSerializers.err = function err(err) { stack: getFullErrorStack(err) } Object.keys(err).forEach(function (k) { - if (err[k] !== undefined) { + if (err[k] !== undefined && !errSkips[k]) { obj[k] = err[k]; } }); diff --git a/package.json b/package.json index d581bcf..668e070 100644 --- a/package.json +++ b/package.json @@ -16,11 +16,11 @@ "keywords": ["log", "logging", "log4j", "json"], "dependencies": { - "dtrace-provider": "0.2.7" }, "// comment": "'mv' required for RotatingFileStream", "optionalDependencies": { - "mv": "0.0.4" + "mv": "0.0.4", + "dtrace-provider": "0.2.8" }, "devDependencies": { "nodeunit": "0.7.4", diff --git a/test/std-serializers.test.js b/test/std-serializers.test.js index 98cf99c..1c5095d 100644 --- a/test/std-serializers.test.js +++ b/test/std-serializers.test.js @@ -198,37 +198,37 @@ test('err serializer: long stack', function (t) { topErr = new verror.VError('top err'); log.info(topErr, 'the error'); var lastRecord = records[records.length-1]; - t.equal(lastRecord.err.message, topErr.message); - t.equal(lastRecord.err.name, topErr.name); - t.equal(lastRecord.err.stack, topErr.stack); + t.equal(lastRecord.err.message, topErr.message, 'Just a VError'); + t.equal(lastRecord.err.name, topErr.name, 'Just a VError'); + t.equal(lastRecord.err.stack, topErr.stack, 'Just a VError'); // Just a WError. topErr = new verror.WError('top err'); log.info(topErr, 'the error'); var lastRecord = records[records.length-1]; - t.equal(lastRecord.err.message, topErr.message); - t.equal(lastRecord.err.name, topErr.name); - t.equal(lastRecord.err.stack, topErr.stack); + t.equal(lastRecord.err.message, topErr.message, 'Just a WError'); + t.equal(lastRecord.err.name, topErr.name, 'Just a WError'); + t.equal(lastRecord.err.stack, topErr.stack, 'Just a WError'); // WError <- TypeError bottomErr = new TypeError('bottom err'); topErr = new verror.WError(bottomErr, 'top err'); log.info(topErr, 'the error'); var lastRecord = records[records.length-1]; - t.equal(lastRecord.err.message, topErr.message); - t.equal(lastRecord.err.name, topErr.name); + t.equal(lastRecord.err.message, topErr.message, 'WError <- TypeError'); + t.equal(lastRecord.err.name, topErr.name, 'WError <- TypeError'); var expectedStack = topErr.stack + '\nCaused by: ' + bottomErr.stack; - t.equal(lastRecord.err.stack, expectedStack); + t.equal(lastRecord.err.stack, expectedStack, 'WError <- TypeError'); // WError <- WError bottomErr = new verror.WError('bottom err'); topErr = new verror.WError(bottomErr, 'top err'); log.info(topErr, 'the error'); var lastRecord = records[records.length-1]; - t.equal(lastRecord.err.message, topErr.message); - t.equal(lastRecord.err.name, topErr.name); + t.equal(lastRecord.err.message, topErr.message, 'WError <- WError'); + t.equal(lastRecord.err.name, topErr.name, 'WError <- WError'); var expectedStack = topErr.stack + '\nCaused by: ' + bottomErr.stack; - t.equal(lastRecord.err.stack, expectedStack); + t.equal(lastRecord.err.stack, expectedStack, 'WError <- WError'); // WError <- WError <- TypeError bottomErr = new TypeError('bottom err'); @@ -236,12 +236,12 @@ test('err serializer: long stack', function (t) { topErr = new verror.WError(midErr, 'top err'); log.info(topErr, 'the error'); var lastRecord = records[records.length-1]; - t.equal(lastRecord.err.message, topErr.message); - t.equal(lastRecord.err.name, topErr.name); + t.equal(lastRecord.err.message, topErr.message, 'WError <- WError <- TypeError'); + t.equal(lastRecord.err.name, topErr.name, 'WError <- WError <- TypeError'); var expectedStack = (topErr.stack + '\nCaused by: ' + midErr.stack + '\nCaused by: ' + bottomErr.stack); - t.equal(lastRecord.err.stack, expectedStack); + t.equal(lastRecord.err.stack, expectedStack, 'WError <- WError <- TypeError'); // WError <- WError <- WError bottomErr = new verror.WError('bottom err'); @@ -249,12 +249,12 @@ test('err serializer: long stack', function (t) { topErr = new verror.WError(midErr, 'top err'); log.info(topErr, 'the error'); var lastRecord = records[records.length-1]; - t.equal(lastRecord.err.message, topErr.message); - t.equal(lastRecord.err.name, topErr.name); + t.equal(lastRecord.err.message, topErr.message, 'WError <- WError <- WError'); + t.equal(lastRecord.err.name, topErr.name, 'WError <- WError <- WError'); var expectedStack = (topErr.stack + '\nCaused by: ' + midErr.stack + '\nCaused by: ' + bottomErr.stack); - t.equal(lastRecord.err.stack, expectedStack); + t.equal(lastRecord.err.stack, expectedStack, 'WError <- WError <- WError'); t.end();