Gracefully handle use of an unbound `Logger.{info,debug,...}`

master
Trent Mick 2014-12-08 10:43:33 -08:00
parent 1e793b182c
commit 2f95bb8091
2 changed files with 43 additions and 16 deletions

View File

@ -8,7 +8,15 @@ Known issues:
## bunyan 1.2.4 (not yet released) ## bunyan 1.2.4 (not yet released)
(nothing yet) - [issue #100] Gracefully handle the case of an unbound
`Logger.{info,debug,...}` being used for logging, e.g.:
myEmittingThing.on('data', log.info)
Before this change, bunyan would throw. Now it emits a warning to stderr
*once*, and then silently ignores those log attempts, e.g.:
bunyan usage error: /Users/trentm/tm/node-bunyan/foo.js:12: attempt to log with an unbound log method: `this` is: { _events: { data: [Function] } }
## bunyan 1.2.3 ## bunyan 1.2.3

View File

@ -54,8 +54,12 @@ var isBrowser = function () {
//---- Internal support stuff //---- Internal support stuff
/**
* A shallow copy of an object. Bunyan logging attempts to never cause
* exceptions, so this function attempts to handle non-objects gracefully.
*/
function objCopy(obj) { function objCopy(obj) {
if (obj == null) { if (obj == null) { // null or undefined
return obj; return obj;
} else if (Array.isArray(obj)) { } else if (Array.isArray(obj)) {
return obj.slice(); return obj.slice();
@ -143,22 +147,22 @@ function getCaller3Info() {
* If file/line are given, this makes an attempt to warn on stderr only once. * If file/line are given, this makes an attempt to warn on stderr only once.
* *
* @param msg {String} Message with which to warn. * @param msg {String} Message with which to warn.
* @param file {String} Optional. File path relevant for the warning. * @param dedupKey {String} Optional. A short string key for this warning to
* @param line {String} Optional. Line number in `file` path relevant for * have its warning only printed once.
* the warning.
*/ */
function _warn(msg, file, line) { function _warn(msg, dedupKey) {
assert.ok(msg); assert.ok(msg);
var key; if (dedupKey) {
if (file && line) { if (_warned[dedupKey]) {
key = file + ':' + line;
if (_warned[key]) {
return; return;
} }
_warned[key] = true; _warned[dedupKey] = true;
} }
process.stderr.write(msg + '\n'); process.stderr.write(msg + '\n');
} }
function _haveWarned(dedupKey) {
return _warned[dedupKey];
}
var _warned = {}; var _warned = {};
@ -758,10 +762,9 @@ Logger.prototype._applySerializers = function (fields, excludeFields) {
try { try {
fields[name] = self.serializers[name](fields[name]); fields[name] = self.serializers[name](fields[name]);
} catch (err) { } catch (err) {
_warn(format('bunyan: ERROR: This should never happen. ' _warn(format('bunyan: ERROR: Exception thrown from the "%s" '
+ 'This is a bug in <https://github.com/trentm/node-bunyan> ' + 'Bunyan serializer. This should never happen. This is a bug'
+ 'or in this application. Exception from "%s" Logger ' + 'in that serializer function.\n%s',
+ 'serializer: %s',
name, err.stack || err)); name, err.stack || err));
fields[name] = format('(Error in Bunyan log "%s" serializer ' fields[name] = format('(Error in Bunyan log "%s" serializer '
+ 'broke field. See stderr for details.)', name); + 'broke field. See stderr for details.)', name);
@ -884,7 +887,23 @@ function mkLogEmitter(minLevel) {
var msgArgs = arguments; var msgArgs = arguments;
var str = null; var str = null;
var rec = null; var rec = null;
if (arguments.length === 0) { // `log.<level>()` if (! this._emit) {
/*
* Show this invalid Bunyan usage warning *once*.
*
* See <https://github.com/trentm/node-bunyan/issues/100> for
* an example of how this can happen.
*/
var dedupKey = 'unbound';
if (!_haveWarned[dedupKey]) {
var caller = getCaller3Info();
_warn(format('bunyan usage error: %s:%s: attempt to log '
+ 'with an unbound log method: `this` is: %s',
caller.file, caller.line, util.inspect(this)),
dedupKey);
}
return;
} else if (arguments.length === 0) { // `log.<level>()`
return (this._level <= minLevel); return (this._level <= minLevel);
} else if (this._level > minLevel) { } else if (this._level > minLevel) {
/* pass through */ /* pass through */