Skip to content

Commit b33b7e5

Browse files
committedMar 8, 2017
add notes about writing good serializer functions, prompted from issue #464
1 parent b66571f commit b33b7e5

File tree

2 files changed

+50
-4
lines changed

2 files changed

+50
-4
lines changed
 

‎README.md

+49-3
Original file line numberDiff line numberDiff line change
@@ -374,10 +374,56 @@ var log = bunyan.createLogger({name: 'myapp'});
374374
log.addSerializers({req: reqSerializer});
375375
```
376376

377+
### Requirements for serializers functions
377378

378-
**Note**: Your own serializers should never throw, otherwise you'll get an
379-
ugly message on stderr from Bunyan (along with the traceback) and the field
380-
in your log record will be replaced with a short error message.
379+
A serializer function is passed unprotected objects that are passed to the
380+
`log.info`, `log.debug`, etc. call. This means a poorly written serializer
381+
function can case side-effects. Logging shouldn't do that. Here are a few
382+
rules and best practices for serializer functions:
383+
384+
- A serializer function *should never throw*. The bunyan library *does*
385+
protect somewhat from this: if the serializer throws an error, then
386+
bunyan will (a) write an ugly message on stderr (along with the traceback),
387+
and (b) the field in the log record will be replace with a short error message.
388+
For example:
389+
390+
```
391+
bunyan: ERROR: Exception thrown from the "foo" Bunyan serializer. This should never happen. This is a bug in that serializer function.
392+
TypeError: Cannot read property 'not' of undefined
393+
at Object.fooSerializer [as foo] (/Users/trentm/tm/node-bunyan/bar.js:8:26)
394+
at /Users/trentm/tm/node-bunyan/lib/bunyan.js:873:50
395+
at Array.forEach (native)
396+
at Logger._applySerializers (/Users/trentm/tm/node-bunyan/lib/bunyan.js:865:35)
397+
at mkRecord (/Users/trentm/tm/node-bunyan/lib/bunyan.js:978:17)
398+
at Logger.info (/Users/trentm/tm/node-bunyan/lib/bunyan.js:1044:19)
399+
at Object.<anonymous> (/Users/trentm/tm/node-bunyan/bar.js:13:5)
400+
at Module._compile (module.js:409:26)
401+
at Object.Module._extensions..js (module.js:416:10)
402+
at Module.load (module.js:343:32)
403+
{"name":"bar","hostname":"danger0.local","pid":47411,"level":30,"foo":"(Error in Bunyan log \"foo\" serializer broke field. See stderr for details.)","msg":"one","time":"2017-03-08T02:53:51.173Z","v":0}
404+
```
405+
406+
- A serializer function *should never mutate the given object*. Doing so will
407+
change the object in your application.
408+
409+
- A serializer function *should be defensive*. In my experience it is common to
410+
set a serializer in an app, say for field name "foo", and then accidentally
411+
have a log line that passes a "foo" that is undefined, or null, or of some
412+
unexpected type. A good start at defensiveness is to start with this:
413+
414+
```javascript
415+
function fooSerializers(foo) {
416+
// Guard against foo be null/undefined. Check that expected fields
417+
// are defined.
418+
if (!foo || !foo.bar)
419+
return foo;
420+
var obj = {
421+
// Create the object to be logged.
422+
bar: foo.bar
423+
}
424+
return obj;
425+
};
426+
```
381427
382428
383429
### Standard Serializers

‎lib/bunyan.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -873,7 +873,7 @@ Logger.prototype._applySerializers = function (fields, excludeFields) {
873873
fields[name] = self.serializers[name](fields[name]);
874874
} catch (err) {
875875
_warn(format('bunyan: ERROR: Exception thrown from the "%s" '
876-
+ 'Bunyan serializer. This should never happen. This is a bug'
876+
+ 'Bunyan serializer. This should never happen. This is a bug '
877877
+ 'in that serializer function.\n%s',
878878
name, err.stack || err));
879879
fields[name] = format('(Error in Bunyan log "%s" serializer '

0 commit comments

Comments
 (0)
Please sign in to comment.