Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add asObjectBindingsOnly, allowing write to receive only the bindings as object #2051

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 26 additions & 12 deletions browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
}
Expand All @@ -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) {
Expand Down
15 changes: 15 additions & 0 deletions docs/browser.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,21 @@ pino.info('hi') // creates and logs {msg: 'hi', level: 30, time: <ts>}

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: <ts>}, '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.
Expand Down
20 changes: 20 additions & 0 deletions test/browser.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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')({
Expand All @@ -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) {
Expand Down