Skip to content

Commit 962bc2b

Browse files
authored
feat: pass logger/child logger as param to mixin (#1709)
1 parent d741fbe commit 962bc2b

File tree

3 files changed

+93
-2
lines changed

3 files changed

+93
-2
lines changed

docs/api.md

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ Default: `undefined`
121121

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

@@ -177,7 +179,40 @@ logger.error('Message 2')
177179
```
178180

179181
If the `mixin` feature is being used merely to add static metadata to each log message,
180-
then a [child logger ⇗](/docs/child-loggers.md) should be used instead.
182+
then a [child logger ⇗](/docs/child-loggers.md) should be used instead. Unless your application
183+
needs to concatenate values for a specific key multiple times, in which case `mixin` can be
184+
used to avoid the [duplicate keys caveat](/docs/child-loggers.md#duplicate-keys-caveat):
185+
186+
```js
187+
const logger = pino({
188+
mixin (obj, num, logger) {
189+
return {
190+
tags: logger.tags
191+
}
192+
}
193+
})
194+
logger.tags = {}
195+
196+
logger.addTag = function (key, value) {
197+
logger.tags[key] = value
198+
}
199+
200+
function createChild (parent, ...context) {
201+
const newChild = logger.child(...context)
202+
newChild.tags = { ...logger.tags }
203+
newChild.addTag = function (key, value) {
204+
newChild.tags[key] = value
205+
}
206+
return newChild
207+
}
208+
209+
logger.addTag('foo', 1)
210+
const child = createChild(logger, {})
211+
child.addTag('bar', 2)
212+
logger.info('this will only have `foo: 1`')
213+
child.info('this will have both `foo: 1` and `bar: 2`')
214+
logger.info('this will still only have `foo: 1`')
215+
```
181216

182217
As of pino 7.x, when the `mixin` is used with the [`nestedKey` option](#opt-nestedkey),
183218
the object returned from the `mixin` method will also be nested. Prior versions would mix

lib/proto.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ function write (_obj, msg, num) {
199199
}
200200

201201
if (mixin) {
202-
obj = mixinMergeStrategy(obj, mixin(obj, num))
202+
obj = mixinMergeStrategy(obj, mixin(obj, num, this))
203203
}
204204

205205
const s = this[asJsonSym](obj, msg, num, t)

test/mixin.test.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,59 @@ test('mixin can use level number', async ({ ok, same }) => {
160160
stack: 'stack'
161161
}, 'test')
162162
})
163+
164+
test('mixin receives logger as third parameter', async ({ ok, same }) => {
165+
const stream = sink()
166+
const instance = pino({
167+
mixin (context, num, logger) {
168+
ok(logger !== null, 'logger should be defined')
169+
ok(logger !== undefined, 'logger should be defined')
170+
same(logger, instance)
171+
return { ...context, num }
172+
}
173+
}, stream)
174+
instance.level = name
175+
instance[name]({
176+
message: '123'
177+
}, 'test')
178+
})
179+
180+
test('mixin receives child logger', async ({ ok, same }) => {
181+
const stream = sink()
182+
let child = null
183+
const instance = pino({
184+
mixin (context, num, logger) {
185+
ok(logger !== null, 'logger should be defined')
186+
ok(logger !== undefined, 'logger should be defined')
187+
same(logger.expected, child.expected)
188+
return { ...context, num }
189+
}
190+
}, stream)
191+
instance.level = name
192+
instance.expected = false
193+
child = instance.child({})
194+
child.expected = true
195+
child[name]({
196+
message: '123'
197+
}, 'test')
198+
})
199+
200+
test('mixin receives logger even if child exists', async ({ ok, same }) => {
201+
const stream = sink()
202+
let child = null
203+
const instance = pino({
204+
mixin (context, num, logger) {
205+
ok(logger !== null, 'logger should be defined')
206+
ok(logger !== undefined, 'logger should be defined')
207+
same(logger.expected, instance.expected)
208+
return { ...context, num }
209+
}
210+
}, stream)
211+
instance.level = name
212+
instance.expected = false
213+
child = instance.child({})
214+
child.expected = true
215+
instance[name]({
216+
message: '123'
217+
}, 'test')
218+
})

0 commit comments

Comments
 (0)