diff --git a/browser.js b/browser.js index 522de1a05..d50bac4a7 100644 --- a/browser.js +++ b/browser.js @@ -109,6 +109,7 @@ function pino (opts) { transmit, serialize, asObject: opts.browser.asObject, + asObjectBindingsOnly: opts.browser.asObjectBindingsOnly, formatters: opts.browser.formatters, levels, timestamp: getTimeFunction(opts), @@ -317,7 +318,7 @@ function createWrap (self, opts, rootLogger, level) { argsIsSerialized = true } if (opts.asObject || opts.formatters) { - write.call(proto, asObject(this, level, args, ts, opts)) + write.call(proto, ...asObject(this, level, args, ts, opts)) } else write.apply(proto, args) if (opts.transmit) { @@ -347,6 +348,10 @@ function asObject (logger, level, args, ts, opts) { const argsCloned = args.slice() let msg = argsCloned[0] const logObject = {} + + let lvl = (logger._childLevel | 0) + 1 + if (lvl < 1) lvl = 1 + if (ts) { logObject.time = ts } @@ -358,19 +363,28 @@ function asObject (logger, level, args, ts, opts) { logObject.level = logger.levels.values[level] } - let lvl = (logger._childLevel | 0) + 1 - if (lvl < 1) lvl = 1 - // deliberate, catching objects, arrays - if (msg !== null && typeof msg === 'object') { - while (lvl-- && typeof argsCloned[0] === 'object') { - Object.assign(logObject, argsCloned.shift()) + if (opts.asObjectBindingsOnly) { + if (msg !== null && typeof msg === 'object') { + while (lvl-- && typeof argsCloned[0] === 'object') { + Object.assign(logObject, argsCloned.shift()) + } } - msg = argsCloned.length ? format(argsCloned.shift(), argsCloned) : undefined - } else if (typeof msg === 'string') msg = format(argsCloned.shift(), argsCloned) - if (msg !== undefined) logObject[opts.messageKey] = msg - const formattedLogObject = logObjectFormatter(logObject) - return formattedLogObject + const formattedLogObject = logObjectFormatter(logObject) + return [formattedLogObject, ...argsCloned] + } else { + // deliberate, catching objects, arrays + if (msg !== null && typeof msg === 'object') { + while (lvl-- && typeof argsCloned[0] === 'object') { + Object.assign(logObject, argsCloned.shift()) + } + msg = argsCloned.length ? format(argsCloned.shift(), argsCloned) : undefined + } else if (typeof msg === 'string') msg = format(argsCloned.shift(), argsCloned) + if (msg !== undefined) logObject[opts.messageKey] = msg + + const formattedLogObject = logObjectFormatter(logObject) + return [formattedLogObject] + } } function applySerializers (args, serialize, serializers, stdErrSerialize) { diff --git a/docs/browser.md b/docs/browser.md index a23ce8373..9578e0cea 100644 --- a/docs/browser.md +++ b/docs/browser.md @@ -27,6 +27,21 @@ pino.info('hi') // creates and logs {msg: 'hi', level: 30, time: } When `write` is set, `asObject` will always be `true`. +### `asObjectBindingsOnly` (Boolean) + +```js +const pino = require('pino')({browser: {asObjectBindingsOnly: true}}) +``` + +The `asObjectBindingsOnly` is similar to `asObject` but will keep the message +and arguments unformatted, this allows to defer formatting the message to the +actual call to `console` methods, where browsers then have richer formatting in +their devtools then when pino will format the message to a string first. + +```js +pino.info('hello %s', 'world') // creates and logs {level: 30, time: }, 'hello %s', 'world' +``` + ### `formatters` (Object) An object containing functions for formatting the shape of the log lines. When provided, it enables the logger to produce a pino-like log object with customized formatting. Currently, it supports formatting for the `level` object only. diff --git a/test/browser.test.js b/test/browser.test.js index 8684006b4..0712e48da 100644 --- a/test/browser.test.js +++ b/test/browser.test.js @@ -165,6 +165,7 @@ test('opts.browser.asObject logs pino-like object to console', ({ end, ok, is }) instance.info('test') end() }) + test('opts.browser.asObject uses opts.messageKey in logs', ({ end, ok, is }) => { const messageKey = 'message' const instance = require('../browser')({ @@ -183,6 +184,25 @@ test('opts.browser.asObject uses opts.messageKey in logs', ({ end, ok, is }) => end() }) +test('opts.browser.asObjectBindingsOnly passes the bindings but keep the message unformatted', ({ end, ok, is, deepEqual }) => { + const messageKey = 'message' + const instance = require('../browser')({ + messageKey, + browser: { + asObjectBindingsOnly: true, + write: function (o, msg, ...args) { + is(o.level, 30) + ok(o.time) + is(msg, 'test %s') + deepEqual(args, ['foo']) + } + } + }) + + instance.info('test %s', 'foo') + end() +}) + test('opts.browser.formatters (level) logs pino-like object to console', ({ end, ok, is }) => { const info = console.info console.info = function (o) {