exclude domain keys on error objects for 'err' serializer

master
Trent Mick 2013-03-01 16:58:56 -08:00
parent b2438ddb2c
commit f096b303c1
6 changed files with 52 additions and 39 deletions

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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.<level>(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];
}
});

View File

@ -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",

View File

@ -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();