trentm/node-bunyan

Callable custom context serialized on object creation instead of logging call

tback opened this issue · 3 comments

tback commented

In #457 you recommend passing a callable to log the request id.

Is this limited to pure javascript? In typescript it seems I can pass custom strings only. I assume genRequestId in your example is a function, right? in @types/bunyan custom is an array of strings.

import bunyan from 'bunyan';
const genRequestId = () => {return 'an-id'}

const logger = bunyan.createLogger({name: 'app', requestId: genRequestId
});
logger.info('hi')

logs this:

{"name":"app","hostname":"xxxx.local","pid":19383,"level":30,"msg":"hi","time":"2021-08-05T14:58:44.999Z","v":0}

(Notice the request id is missing).

Node 12.22.4
Bunyan: 1.8.15 or 2.0.5
macos bigsur

This was initially a comment on #457, but I think it's rather a bug, than a request for support. Also, my comment didn't reopen the issue, so I feared it wouldn't be noticed.

tback commented

Found out that it's not typescript specific.

Defining a serializer for the field will work around the issue:

var logger = bunyan.createLogger({
    name:'app',
    serializers: {
        requestId: function(f) {
            return f()
        }
    },
    requestId: getRequestId
})
tback commented

Sorry, I've got to reopen this. Changing the title so it matches the problem.
Old title: Callable custom context broken in typescript?
New title: Callable custom context serialized on object creation instead of logging call.

I'm still trying to make bunyan log a request with an id.

Extra fields are serialized only once: When the logger is created. This makes it impossible to use an extra field for my purpose.
You sugessting exactly this strategy in #457 make me question this is an explicit design decision? What do you suggest instead?

siakc commented

I had to make such wrapper to make it work:
{ trace (arg0, ...args) { const ctx = ctxLocalStorage.getStore() if (typeof (arg0) === 'object' && !Array.isArray(arg0)) { arg0.logId = ctx?.logId _log.trace(arg0, ...args) } else { _log.trace({logId: ctx?.logId}, arg0, ...args) } }, debug (arg0, ...args) { const ctx = ctxLocalStorage.getStore() if (typeof (arg0) === 'object' && !Array.isArray(arg0)) { arg0.logId = ctx?.logId _log.debug(arg0, ...args) } else { _log.debug({logId: ctx?.logId}, arg0, ...args) } }, info (arg0, ...args) { const ctx = ctxLocalStorage.getStore() if (typeof (arg0) === 'object' && !Array.isArray(arg0)) { arg0.logId = ctx?.logId _log.info(arg0, ...args) } else { _log.info({logId: ctx?.logId}, arg0, ...args) } }, warn (arg0, ...args) { const ctx = ctxLocalStorage.getStore() if (typeof (arg0) === 'object' && !Array.isArray(arg0)) { arg0.logId = ctx?.logId _log.warn(arg0, ...args) } else { _log.warn({logId: ctx?.logId}, arg0, ...args) } }, error (arg0, ...args) { const ctx = ctxLocalStorage.getStore() if (typeof (arg0) === 'object' && !Array.isArray(arg0)) { arg0.logId = ctx?.logId _log.error(arg0, ...args) } else { _log.error({logId: ctx?.logId}, arg0, ...args) } }, fatal (arg0, ...args) { const ctx = ctxLocalStorage.getStore() if (typeof (arg0) === 'object' && !Array.isArray(arg0)) { arg0.logId = ctx?.logId _log.fatal(arg0, ...args) } else { _log.fatal({logId: ctx?.logId}, arg0, ...args) } }, getLoggerInstance () { return _log // The Bunyan instance } }