Skip to content

Commit acaad23

Browse files
rluvatonjsumners
andauthored
Allow message prefix - #544 (#1635)
* allow message prefix WIP * fix tests * trigger ci * add tests * added docs * added support for msgPrefix for the root logger * Update docs/api.md Co-authored-by: James Sumners <[email protected]> * revert change based on benchmark --------- Co-authored-by: James Sumners <[email protected]>
1 parent c3ea262 commit acaad23

File tree

7 files changed

+148
-8
lines changed

7 files changed

+148
-8
lines changed

docs/api.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,24 @@ See `errorKey` option to change `err` namespace.
384384

385385
* See [pino.stdSerializers](#pino-stdserializers)
386386

387+
#### `msgPrefix` (String)
388+
389+
Default: `undefined`
390+
391+
The `msgPrefix` property allows you to specify a prefix for every message of the logger and its children.
392+
393+
```js
394+
const logger = pino({
395+
msgPrefix: '[HTTP] '
396+
})
397+
logger.info('got new request!')
398+
// > [HTTP] got new request!
399+
400+
const child = logger.child({})
401+
child.info('User authenticated!')
402+
// > [HTTP] User authenticated!
403+
```
404+
387405
#### `base` (Object)
388406

389407
Default: `{pid: process.pid, hostname: os.hostname}`
@@ -842,6 +860,26 @@ const child = logger.child({foo: 'bar'}, {level: 'debug'})
842860
child.debug('debug!') // will log as the `level` property set the level to debug
843861
```
844862
863+
##### `options.msgPrefix` (String)
864+
865+
Default: `undefined`
866+
867+
The `msgPrefix` property allows you to specify a prefix for every message of the child logger.
868+
By default, the parent prefix is inherited.
869+
If the parent already has a prefix, the prefix of the parent and then the child will be displayed.
870+
871+
```js
872+
const logger = pino({
873+
msgPrefix: '[HTTP] '
874+
})
875+
logger.info('got new request!')
876+
// > [HTTP] got new request!
877+
878+
const child = logger.child({avengers: 'assemble'}, {msgPrefix: '[Proxy] '})
879+
child.info('message proxied!')
880+
// > [HTTP] [Proxy] message proxied!
881+
```
882+
845883
##### `options.redact` (Array | Object)
846884
847885
Setting `options.redact` to an array or object will override the parent `redact` options. To remove `redact` options inherited from the parent logger set this value as an empty array (`[]`).

lib/proto.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ const {
2525
redactFmtSym,
2626
stringifySym,
2727
formatOptsSym,
28-
stringifiersSym
28+
stringifiersSym,
29+
msgPrefixSym
2930
} = require('./symbols')
3031
const {
3132
getLevel,
@@ -138,6 +139,10 @@ function child (bindings, options) {
138139
instance[formatOptsSym] = formatOpts
139140
}
140141

142+
if (typeof options.msgPrefix === 'string') {
143+
instance[msgPrefixSym] = (this[msgPrefixSym] || '') + options.msgPrefix
144+
}
145+
141146
instance[chindingsSym] = asChindings(instance, bindings)
142147
const childLevel = options.level || this.level
143148
instance[setLevelSym](childLevel)

lib/symbols.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const errorKeySym = Symbol('pino.errorKey')
2727
const nestedKeySym = Symbol('pino.nestedKey')
2828
const nestedKeyStrSym = Symbol('pino.nestedKeyStr')
2929
const mixinMergeStrategySym = Symbol('pino.mixinMergeStrategy')
30+
const msgPrefixSym = Symbol('pino.msgPrefix')
3031

3132
const wildcardFirstSym = Symbol('pino.wildcardFirst')
3233

@@ -66,5 +67,6 @@ module.exports = {
6667
formattersSym,
6768
hooksSym,
6869
nestedKeyStrSym,
69-
mixinMergeStrategySym
70+
mixinMergeStrategySym,
71+
msgPrefixSym
7072
}

lib/tools.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@ const {
2121
formattersSym,
2222
messageKeySym,
2323
errorKeySym,
24-
nestedKeyStrSym
24+
nestedKeyStrSym,
25+
msgPrefixSym
2526
} = require('./symbols')
2627
const { isMainThread } = require('worker_threads')
2728
const transport = require('./transport')
2829

29-
function noop () {}
30+
function noop () {
31+
}
3032

3133
function genLog (level, hook) {
3234
if (!hook) return LOG
@@ -52,9 +54,21 @@ function genLog (level, hook) {
5254
msg = n.shift()
5355
formatParams = n
5456
}
57+
// We do not use a coercive check for `msg` as it is
58+
// measurably slower than the explicit checks.
59+
if (typeof this[msgPrefixSym] === 'string' && msg !== undefined && msg !== null) {
60+
msg = this[msgPrefixSym] + msg
61+
}
5562
this[writeSym](o, format(msg, formatParams, this[formatOptsSym]), level)
5663
} else {
57-
this[writeSym](null, format(o === undefined ? n.shift() : o, n, this[formatOptsSym]), level)
64+
let msg = o === undefined ? n.shift() : o
65+
66+
// We do not use a coercive check for `msg` as it is
67+
// measurably slower than the explicit checks.
68+
if (typeof this[msgPrefixSym] === 'string' && msg !== undefined && msg !== null) {
69+
msg = this[msgPrefixSym] + msg
70+
}
71+
this[writeSym](null, format(msg, n, this[formatOptsSym]), level)
5872
}
5973
}
6074
}

pino.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,11 @@ declare namespace pino {
588588
log?: (object: Record<string, unknown>) => Record<string, unknown>;
589589
};
590590

591+
/**
592+
* A string that would be prefixed to every message (and child message)
593+
*/
594+
msgPrefix?: string
595+
591596
/**
592597
* An object mapping to hook functions. Hook functions allow for customizing internal logger operations.
593598
* Hook functions must be synchronous functions.
@@ -628,6 +633,7 @@ declare namespace pino {
628633
log?: (object: object) => object;
629634
};
630635
redact?: string[] | redactOptions;
636+
msgPrefix?: string
631637
}
632638

633639
/**

pino.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ const {
4040
formattersSym,
4141
hooksSym,
4242
nestedKeyStrSym,
43-
mixinMergeStrategySym
43+
mixinMergeStrategySym,
44+
msgPrefixSym
4445
} = symbols
4546
const { epochTime, nullTime } = time
4647
const { pid } = process
@@ -103,7 +104,8 @@ function pino (...args) {
103104
hooks,
104105
depthLimit,
105106
edgeLimit,
106-
onChild
107+
onChild,
108+
msgPrefix
107109
} = opts
108110

109111
const stringifySafe = configure({
@@ -150,6 +152,7 @@ function pino (...args) {
150152

151153
if (useOnlyCustomLevels && !customLevels) throw Error('customLevels is required if useOnlyCustomLevels is set true')
152154
if (mixin && typeof mixin !== 'function') throw Error(`Unknown mixin type "${typeof mixin}" - expected "function"`)
155+
if (msgPrefix && typeof msgPrefix !== 'string') throw Error(`Unknown msgPrefix type "${typeof msgPrefix}" - expected "string"`)
153156

154157
assertDefaultLevelFound(level, customLevels, useOnlyCustomLevels)
155158
const levels = mappings(customLevels, useOnlyCustomLevels)
@@ -177,7 +180,8 @@ function pino (...args) {
177180
[formattersSym]: allFormatters,
178181
[hooksSym]: hooks,
179182
silent: noop,
180-
onChild
183+
onChild,
184+
[msgPrefixSym]: msgPrefix
181185
})
182186

183187
Object.setPrototypeOf(instance, proto())

test/basic.test.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,3 +751,74 @@ test('Should invoke `onChild` with the newly created child', async ({ equal }) =
751751
}).child({ foo: 'bar' })
752752
equal(child, innerChild)
753753
})
754+
755+
test('logger message should have the prefix message that defined in the logger creation', async ({ equal }) => {
756+
const stream = sink()
757+
const logger = pino({
758+
msgPrefix: 'My name is Bond '
759+
}, stream)
760+
logger.info('James Bond')
761+
const { msg } = await once(stream, 'data')
762+
equal(msg, 'My name is Bond James Bond')
763+
})
764+
765+
test('child message should have the prefix message that defined in the child creation', async ({ equal }) => {
766+
const stream = sink()
767+
const instance = pino(stream)
768+
const child = instance.child({}, { msgPrefix: 'My name is Bond ' })
769+
child.info('James Bond')
770+
const { msg } = await once(stream, 'data')
771+
equal(msg, 'My name is Bond James Bond')
772+
})
773+
774+
test('child message should have the prefix message that defined in the child creation when logging with log meta', async ({ equal }) => {
775+
const stream = sink()
776+
const instance = pino(stream)
777+
const child = instance.child({}, { msgPrefix: 'My name is Bond ' })
778+
child.info({ hello: 'world' }, 'James Bond')
779+
const { msg, hello } = await once(stream, 'data')
780+
equal(hello, 'world')
781+
equal(msg, 'My name is Bond James Bond')
782+
})
783+
784+
test('logged message should not have the prefix when not providing any message', async ({ equal }) => {
785+
const stream = sink()
786+
const instance = pino(stream)
787+
const child = instance.child({}, { msgPrefix: 'This should not be shown ' })
788+
child.info({ hello: 'world' })
789+
const { msg, hello } = await once(stream, 'data')
790+
equal(hello, 'world')
791+
equal(msg, undefined)
792+
})
793+
794+
test('child message should append parent prefix to current prefix that defined in the child creation', async ({ equal }) => {
795+
const stream = sink()
796+
const instance = pino({
797+
msgPrefix: 'My name is Bond '
798+
}, stream)
799+
const child = instance.child({}, { msgPrefix: 'James ' })
800+
child.info('Bond')
801+
const { msg } = await once(stream, 'data')
802+
equal(msg, 'My name is Bond James Bond')
803+
})
804+
805+
test('child message should inherent parent prefix', async ({ equal }) => {
806+
const stream = sink()
807+
const instance = pino({
808+
msgPrefix: 'My name is Bond '
809+
}, stream)
810+
const child = instance.child({})
811+
child.info('James Bond')
812+
const { msg } = await once(stream, 'data')
813+
equal(msg, 'My name is Bond James Bond')
814+
})
815+
816+
test('grandchild message should inherent parent prefix', async ({ equal }) => {
817+
const stream = sink()
818+
const instance = pino(stream)
819+
const child = instance.child({}, { msgPrefix: 'My name is Bond ' })
820+
const grandchild = child.child({})
821+
grandchild.info('James Bond')
822+
const { msg } = await once(stream, 'data')
823+
equal(msg, 'My name is Bond James Bond')
824+
})

0 commit comments

Comments
 (0)