Skip to content

Commit

Permalink
feat: pass logger/child logger as param to mixin (#1709)
Browse files Browse the repository at this point in the history
  • Loading branch information
mmarchini authored May 5, 2023
1 parent d741fbe commit 962bc2b
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 2 deletions.
37 changes: 36 additions & 1 deletion docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ Default: `undefined`

If provided, the `mixin` function is called each time one of the active
logging methods is called. The first parameter is the value `mergeObject` or an empty object. The second parameter is the log level number.
The third parameter is the logger or child logger itself, which can be used to
retrieve logger-specific context from within the `mixin` function.
The function must synchronously return an object. The properties of the returned object will be added to the
logged JSON.

Expand Down Expand Up @@ -177,7 +179,40 @@ logger.error('Message 2')
```

If the `mixin` feature is being used merely to add static metadata to each log message,
then a [child logger ⇗](/docs/child-loggers.md) should be used instead.
then a [child logger ⇗](/docs/child-loggers.md) should be used instead. Unless your application
needs to concatenate values for a specific key multiple times, in which case `mixin` can be
used to avoid the [duplicate keys caveat](/docs/child-loggers.md#duplicate-keys-caveat):

```js
const logger = pino({
mixin (obj, num, logger) {
return {
tags: logger.tags
}
}
})
logger.tags = {}

logger.addTag = function (key, value) {
logger.tags[key] = value
}

function createChild (parent, ...context) {
const newChild = logger.child(...context)
newChild.tags = { ...logger.tags }
newChild.addTag = function (key, value) {
newChild.tags[key] = value
}
return newChild
}

logger.addTag('foo', 1)
const child = createChild(logger, {})
child.addTag('bar', 2)
logger.info('this will only have `foo: 1`')
child.info('this will have both `foo: 1` and `bar: 2`')
logger.info('this will still only have `foo: 1`')
```

As of pino 7.x, when the `mixin` is used with the [`nestedKey` option](#opt-nestedkey),
the object returned from the `mixin` method will also be nested. Prior versions would mix
Expand Down
2 changes: 1 addition & 1 deletion lib/proto.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ function write (_obj, msg, num) {
}

if (mixin) {
obj = mixinMergeStrategy(obj, mixin(obj, num))
obj = mixinMergeStrategy(obj, mixin(obj, num, this))
}

const s = this[asJsonSym](obj, msg, num, t)
Expand Down
56 changes: 56 additions & 0 deletions test/mixin.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,59 @@ test('mixin can use level number', async ({ ok, same }) => {
stack: 'stack'
}, 'test')
})

test('mixin receives logger as third parameter', async ({ ok, same }) => {
const stream = sink()
const instance = pino({
mixin (context, num, logger) {
ok(logger !== null, 'logger should be defined')
ok(logger !== undefined, 'logger should be defined')
same(logger, instance)
return { ...context, num }
}
}, stream)
instance.level = name
instance[name]({
message: '123'
}, 'test')
})

test('mixin receives child logger', async ({ ok, same }) => {
const stream = sink()
let child = null
const instance = pino({
mixin (context, num, logger) {
ok(logger !== null, 'logger should be defined')
ok(logger !== undefined, 'logger should be defined')
same(logger.expected, child.expected)
return { ...context, num }
}
}, stream)
instance.level = name
instance.expected = false
child = instance.child({})
child.expected = true
child[name]({
message: '123'
}, 'test')
})

test('mixin receives logger even if child exists', async ({ ok, same }) => {
const stream = sink()
let child = null
const instance = pino({
mixin (context, num, logger) {
ok(logger !== null, 'logger should be defined')
ok(logger !== undefined, 'logger should be defined')
same(logger.expected, instance.expected)
return { ...context, num }
}
}, stream)
instance.level = name
instance.expected = false
child = instance.child({})
child.expected = true
instance[name]({
message: '123'
}, 'test')
})

0 comments on commit 962bc2b

Please # to comment.