node-bunyan icon indicating copy to clipboard operation
node-bunyan copied to clipboard

child logger with dynamic bound fields

Open yelworc opened this issue 10 years ago • 8 comments

I like the concept of child loggers with additional bound fields. However, they would be more useful for me if the fields were serialized "on the fly". My use case is something like this:

var log = ...  // global logger, defined elsewhere

function Session(id, socket) {  // create a session object for a new connection
    this.id = id;
    this.socket = socket;
    this.log = log.child({session: this, serializers: {
        session: function serialize(s) {
            return s.id + (s.user ? '/' + s.user.id : '');
        }
    }});
}

Where the session's user property is initialized at a later stage (after authentication). Currently, the session field is serialized during initialization of the child logger, so it never changes after that, i.e. the user ID is never included. If I am reading bunyan correctly, this behavior is by design, but I think dynamically serializable bound fields would be useful.

yelworc avatar Sep 11 '14 23:09 yelworc

I understand the desire for that kind of feature, but I can't change the current behaviour. (I was independently asked for something like this today, too.)

There is value in the current behaviour too: only serializing the object once at Logger creation time.

To support this we'd need a reasonable design that allowed both forms... or punt on this feature and require the app using bunyan to wrap log record writing to delay serializing "session" (in this case), or delay creating the log.child until s.user is set (in this case).

trentm avatar Sep 12 '14 23:09 trentm

Thanks for the reply. I understand the reasoning behind the current behavior, in many cases it makes perfect sense. At first glance, it would seem to be fairly straightforward to integrate this as an option, which is disabled (ie. the current behavior) by default, and can be enabled by supplying a dynBoundFields property in the createLogger options. It's quite possible I'm missing some pitfalls there though. If you would consider including such a feature, I might have a go at it if I can find the time.

yelworc avatar Sep 15 '14 11:09 yelworc

Being able to pass a function (executed on every log msg) whose object return value is merged into the logged JSON would be useful.

raine avatar Oct 21 '15 07:10 raine

Being able to pass a function (executed on every log msg) whose object return value is merged into the logged JSON would be useful.

This is an old issue, but I still think this idea is useful. I think if the field is a function and has no serializer, then bunyan could call the function and save the value it returns on the record. This would probably be a breaking change, but you can do it yourself with a custom object stream.

gabegorelick avatar Dec 18 '19 15:12 gabegorelick

Another case: I want to use Datadog's log and trace correlation feature.

The active trace and span IDs are maintained continuation-local-storage-type management.

I need to dynamically fetch these and add them to each log message.

pauldraper avatar Mar 22 '20 14:03 pauldraper

No updates on this?

sigglep avatar Jan 16 '23 14:01 sigglep

Any updates on this?

jmaver-plume avatar Apr 09 '24 17:04 jmaver-plume

For anyone who wants to use something similar, you can take advantage of the get accessor property.

const logger = bunyan.createLogger({ ...options })
Object.defineProperty(log.fields, 'traceId', {
  enumable: true,
  get: function () {
    return 'some-id' // e.g., you can retrieve it from AsyncLocalStorage
  }
})

jmaver-plume avatar Apr 10 '24 11:04 jmaver-plume