Skip to content

Commit dcebb40

Browse files
pearofducksjsumners
andauthoredNov 16, 2021
Add ability to format time and level with user-defined prettifiers (#263)
Co-authored-by: James Sumners <james@sumners.email>
1 parent 2f57958 commit dcebb40

File tree

5 files changed

+131
-15
lines changed

5 files changed

+131
-15
lines changed
 

‎Readme.md

+27
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,33 @@ const prettifyQuery = value => {
238238
}
239239
```
240240

241+
Additionally, `customPrettifiers` can be used to format the time and level
242+
outputs:
243+
```js
244+
{
245+
customPrettifiers: {
246+
// The argument for this function will be the same
247+
// string that's at the start of the log-line by default:
248+
time: timestamp => `🕰 ${timestamp}`,
249+
250+
// The argument for the level-prettifier may vary depending
251+
// on if the levelKey option is used or not.
252+
// By default this will be the same numerics as the Pino default:
253+
level: logLevel => `LEVEL: ${logLevel}`
254+
}
255+
}
256+
257+
Note that prettifiers do not include any coloring, if the stock coloring on
258+
`level` is desired, it can be accomplished using the following:
259+
```js
260+
const { colorizerFactory } = require('pino-pretty')
261+
const levelColorize = colorizerFactory(true)
262+
const levelPrettifier = logLevel => `LEVEL: ${levelColorize(logLevel)}`
263+
//...
264+
{
265+
customPrettifiers: { level: levelPrettifier }
266+
}
267+
241268
`messageFormat` option allows you to customize the message output. A template `string` like this can define the format:
242269
```js
243270
{

‎index.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,9 @@ function prettyFactory (options) {
9090
log = filterLog(log, ignoreKeys)
9191
}
9292

93-
const prettifiedLevel = prettifyLevel({ log, colorizer, levelKey })
93+
const prettifiedLevel = prettifyLevel({ log, colorizer, levelKey, prettifier: customPrettifiers.level })
9494
const prettifiedMetadata = prettifyMetadata({ log })
95-
const prettifiedTime = prettifyTime({ log, translateFormat: opts.translateTime, timestampKey })
95+
const prettifiedTime = prettifyTime({ log, translateFormat: opts.translateTime, timestampKey, prettifier: customPrettifiers.time })
9696

9797
let line = ''
9898
if (opts.levelFirst && prettifiedLevel) {
@@ -214,4 +214,5 @@ function build (opts = {}) {
214214

215215
module.exports = build
216216
module.exports.prettyFactory = prettyFactory
217+
module.exports.colorizerFactory = colors
217218
module.exports.default = build

‎lib/utils.js

+8-7
Original file line numberDiff line numberDiff line change
@@ -218,14 +218,16 @@ function prettifyErrorLog ({
218218
* @param {function} [input.colorizer] A colorizer function that accepts a level
219219
* value and returns a colorized string. Default: a no-op colorizer.
220220
* @param {string} [levelKey='level'] The key to find the level under.
221+
* @param {function} [input.prettifier] A user-supplied formatter to be called instead of colorizer.
221222
*
222223
* @returns {undefined|string} If `log` does not have a `level` property then
223224
* `undefined` will be returned. Otherwise, a string from the specified
224225
* `colorizer` is returned.
225226
*/
226-
function prettifyLevel ({ log, colorizer = defaultColorizer, levelKey = LEVEL_KEY }) {
227+
function prettifyLevel ({ log, colorizer = defaultColorizer, levelKey = LEVEL_KEY, prettifier }) {
227228
if (levelKey in log === false) return undefined
228-
return colorizer(log[levelKey])
229+
const output = log[levelKey]
230+
return prettifier ? prettifier(output) : colorizer(output)
229231
}
230232

231233
/**
@@ -423,12 +425,13 @@ function prettifyObject ({
423425
* timestamp will be prettified into a string at UTC using the default
424426
* `DATE_FORMAT`. If a string, then `translateFormat` will be used as the format
425427
* string to determine the output; see the `formatTime` function for details.
428+
* @param {function} [input.prettifier] A user-supplied formatter for altering output.
426429
*
427430
* @returns {undefined|string} If a timestamp property cannot be found then
428431
* `undefined` is returned. Otherwise, the prettified time is returned as a
429432
* string.
430433
*/
431-
function prettifyTime ({ log, timestampKey = TIMESTAMP_KEY, translateFormat = undefined }) {
434+
function prettifyTime ({ log, timestampKey = TIMESTAMP_KEY, translateFormat = undefined, prettifier }) {
432435
let time = null
433436

434437
if (timestampKey in log) {
@@ -438,11 +441,9 @@ function prettifyTime ({ log, timestampKey = TIMESTAMP_KEY, translateFormat = un
438441
}
439442

440443
if (time === null) return undefined
441-
if (translateFormat) {
442-
return '[' + formatTime(time, translateFormat) + ']'
443-
}
444+
const output = translateFormat ? formatTime(time, translateFormat) : time
444445

445-
return `[${time}]`
446+
return prettifier ? prettifier(output) : `[${output}]`
446447
}
447448

448449
/**

‎test/basic.test.js

+82-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ function prettyFactory (opts) {
2727

2828
// All dates are computed from 'Fri, 30 Mar 2018 17:35:28 GMT'
2929
const epoch = 1522431328992
30+
const formattedEpoch = '2018-03-30 17:35:28.992 +0000'
3031
const pid = process.pid
3132
const hostname = os.hostname()
3233

@@ -127,6 +128,86 @@ test('basic prettifier tests', (t) => {
127128
log.info({ msg: 'foo', bar: 'warn' })
128129
})
129130

131+
t.test('can use a customPrettifier on default level output', (t) => {
132+
t.plan(1)
133+
const veryCustomLevels = {
134+
30: 'ok',
135+
40: 'not great'
136+
}
137+
const customPrettifiers = {
138+
level: (level) => `LEVEL: ${veryCustomLevels[level]}`
139+
}
140+
const pretty = prettyFactory({ customPrettifiers })
141+
const log = pino({}, new Writable({
142+
write (chunk, enc, cb) {
143+
const formatted = pretty(chunk.toString())
144+
t.equal(
145+
formatted,
146+
`[${epoch}] LEVEL: ok (${pid} on ${hostname}): foo\n`
147+
)
148+
cb()
149+
}
150+
}))
151+
log.info({ msg: 'foo' })
152+
})
153+
154+
t.test('can use a customPrettifier on different-level-key output', (t) => {
155+
t.plan(1)
156+
const customPrettifiers = {
157+
level: (level) => `LEVEL: ${level.toUpperCase()}`
158+
}
159+
const pretty = prettyFactory({ levelKey: 'bar', customPrettifiers })
160+
const log = pino({}, new Writable({
161+
write (chunk, enc, cb) {
162+
const formatted = pretty(chunk.toString())
163+
t.equal(
164+
formatted,
165+
`[${epoch}] LEVEL: WARN (${pid} on ${hostname}): foo\n`
166+
)
167+
cb()
168+
}
169+
}))
170+
log.info({ msg: 'foo', bar: 'warn' })
171+
})
172+
173+
t.test('can use a customPrettifier on default time output', (t) => {
174+
t.plan(1)
175+
const customPrettifiers = {
176+
time: (timestamp) => `TIME: ${timestamp}`
177+
}
178+
const pretty = prettyFactory({ customPrettifiers })
179+
const log = pino({}, new Writable({
180+
write (chunk, enc, cb) {
181+
const formatted = pretty(chunk.toString())
182+
t.equal(
183+
formatted,
184+
`TIME: ${epoch} INFO (${pid} on ${hostname}): foo\n`
185+
)
186+
cb()
187+
}
188+
}))
189+
log.info('foo')
190+
})
191+
192+
t.test('can use a customPrettifier on translateTime-time output', (t) => {
193+
t.plan(1)
194+
const customPrettifiers = {
195+
time: (timestamp) => `TIME: ${timestamp}`
196+
}
197+
const pretty = prettyFactory({ customPrettifiers, translateTime: true })
198+
const log = pino({}, new Writable({
199+
write (chunk, enc, cb) {
200+
const formatted = pretty(chunk.toString())
201+
t.equal(
202+
formatted,
203+
`TIME: ${formattedEpoch} INFO (${pid} on ${hostname}): foo\n`
204+
)
205+
cb()
206+
}
207+
}))
208+
log.info('foo')
209+
})
210+
130211
t.test('will format time to UTC', (t) => {
131212
t.plan(1)
132213
const pretty = prettyFactory({ translateTime: true })
@@ -135,7 +216,7 @@ test('basic prettifier tests', (t) => {
135216
const formatted = pretty(chunk.toString())
136217
t.equal(
137218
formatted,
138-
`[2018-03-30 17:35:28.992 +0000] INFO (${pid} on ${hostname}): foo\n`
219+
`[${formattedEpoch}] INFO (${pid} on ${hostname}): foo\n`
139220
)
140221
cb()
141222
}

‎test/lib/colors.test.js

+11-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
'use strict'
22

33
const { test } = require('tap')
4-
const getColorizer = require('../../lib/colors')
4+
const getColorizerPrivate = require('../../lib/colors')
5+
const { colorizerFactory: getColorizerPublic } = require('../../index')
56

6-
test('returns default colorizer', async t => {
7+
const testDefaultColorizer = getColorizer => async t => {
78
const colorizer = getColorizer()
89
let colorized = colorizer(10)
910
t.equal(colorized, 'TRACE')
@@ -37,9 +38,9 @@ test('returns default colorizer', async t => {
3738

3839
colorized = colorizer.greyMessage('foo')
3940
t.equal(colorized, 'foo')
40-
})
41+
}
4142

42-
test('returns colorizing colorizer', async t => {
43+
const testColoringColorizer = getColorizer => async t => {
4344
const colorizer = getColorizer(true)
4445
let colorized = colorizer(10)
4546
t.equal(colorized, '\u001B[90mTRACE\u001B[39m')
@@ -73,4 +74,9 @@ test('returns colorizing colorizer', async t => {
7374

7475
colorized = colorizer.greyMessage('foo')
7576
t.equal(colorized, '\u001B[90mfoo\u001B[39m')
76-
})
77+
}
78+
79+
test('returns default colorizer - private export', testDefaultColorizer(getColorizerPrivate))
80+
test('returns default colorizer - public export', testDefaultColorizer(getColorizerPublic))
81+
test('returns colorizing colorizer - private export', testColoringColorizer(getColorizerPrivate))
82+
test('returns colorizing colorizer - public export', testColoringColorizer(getColorizerPublic))

0 commit comments

Comments
 (0)
Please sign in to comment.