pino-pretty
Advanced tools
Comparing version 7.4.0 to 7.5.0
@@ -36,2 +36,4 @@ #!/usr/bin/env node | ||
.option(['L', 'minimumLevel'], 'Hide messages below the specified log level') | ||
.option(['x', 'customLevels'], 'Override default levels (`-x err:99,info:1`)') | ||
.option(['X', 'customColors'], 'Override default colors using names from https://www.npmjs.com/package/colorette (`-X err:red,info:blue`)') | ||
.option(['k', 'errorLikeObjectKeys'], 'Define which keys contain error objects (`-k err,error`) (defaults to `err,error`)') | ||
@@ -38,0 +40,0 @@ .option(['m', 'messageKey'], 'Highlight the message under the specified key', CONSTANTS.MESSAGE_KEY) |
44
index.js
@@ -36,2 +36,4 @@ 'use strict' | ||
errorProps: '', | ||
customLevels: null, | ||
customColors: null, | ||
levelFirst: false, | ||
@@ -61,2 +63,38 @@ messageKey: MESSAGE_KEY, | ||
const errorProps = opts.errorProps.split(',') | ||
const customLevels = opts.customLevels | ||
? opts.customLevels | ||
.split(',') | ||
.reduce((agg, value, idx) => { | ||
const [levelName, levelIdx = idx] = value.split(':') | ||
agg[levelIdx] = levelName.toUpperCase() | ||
return agg | ||
}, { default: 'USERLVL' }) | ||
: undefined | ||
const customLevelNames = opts.customLevels | ||
? opts.customLevels | ||
.split(',') | ||
.reduce((agg, value, idx) => { | ||
const [levelName, levelIdx = idx] = value.split(':') | ||
agg[levelName] = levelIdx | ||
return agg | ||
}, {}) | ||
: undefined | ||
const customColors = opts.customColors | ||
? opts.customColors | ||
.split(',') | ||
.reduce((agg, value) => { | ||
const [level, color] = value.split(':') | ||
const levelNum = customLevelNames !== undefined ? customLevelNames[level] : LEVEL_NAMES[level] | ||
const colorIdx = levelNum !== undefined ? levelNum : level | ||
agg.push([colorIdx, color]) | ||
return agg | ||
}, []) | ||
: undefined | ||
const customPrettifiers = opts.customPrettifiers | ||
@@ -66,3 +104,3 @@ const ignoreKeys = opts.ignore ? new Set(opts.ignore.split(',')) : undefined | ||
const singleLine = opts.singleLine | ||
const colorizer = colors(opts.colorize) | ||
const colorizer = colors(opts.colorize, customColors) | ||
@@ -85,3 +123,3 @@ return pretty | ||
if (minimumLevel) { | ||
const minimum = LEVEL_NAMES[minimumLevel] || Number(minimumLevel) | ||
const minimum = (customLevelNames === undefined ? LEVEL_NAMES[minimumLevel] : customLevelNames[minimumLevel]) || Number(minimumLevel) | ||
const level = log[levelKey === undefined ? LEVEL_KEY : levelKey] | ||
@@ -97,3 +135,3 @@ if (level < minimum) return | ||
const prettifiedLevel = prettifyLevel({ log, colorizer, levelKey, prettifier: customPrettifiers.level }) | ||
const prettifiedLevel = prettifyLevel({ log, colorizer, levelKey, prettifier: customPrettifiers.level, customLevels, customLevelNames }) | ||
const prettifiedMetadata = prettifyMetadata({ log, prettifiers: customPrettifiers }) | ||
@@ -100,0 +138,0 @@ const prettifiedTime = prettifyTime({ log, translateFormat: opts.translateTime, timestampKey, prettifier: customPrettifiers.time }) |
@@ -19,3 +19,4 @@ 'use strict' | ||
const { createColors } = require('colorette') | ||
const { white, bgRed, red, yellow, green, blue, gray, cyan } = createColors({ useColor: true }) | ||
const availableColors = createColors({ useColor: true }) | ||
const { white, bgRed, red, yellow, green, blue, gray, cyan } = availableColors | ||
@@ -34,14 +35,31 @@ const colored = { | ||
function colorizeLevel (level, colorizer) { | ||
function resolveCustomColoredColorizer (customColors) { | ||
return customColors.reduce( | ||
function (agg, [level, color]) { | ||
agg[level] = typeof availableColors[color] === 'function' ? availableColors[color] : white | ||
return agg | ||
}, | ||
{ default: white, message: cyan, greyMessage: gray } | ||
) | ||
} | ||
function colorizeLevel (level, colorizer, { customLevels, customLevelNames } = {}) { | ||
const levels = customLevels || LEVELS | ||
const levelNames = customLevelNames || LEVEL_NAMES | ||
let levelNum = 'default' | ||
if (Number.isInteger(+level)) { | ||
return Object.prototype.hasOwnProperty.call(LEVELS, level) | ||
? colorizer[level](LEVELS[level]) | ||
: colorizer.default(LEVELS.default) | ||
levelNum = Object.prototype.hasOwnProperty.call(levels, level) ? level : levelNum | ||
} else { | ||
levelNum = Object.prototype.hasOwnProperty.call(levelNames, level.toLowerCase()) ? levelNames[level.toLowerCase()] : levelNum | ||
} | ||
const levelNum = LEVEL_NAMES[level.toLowerCase()] || 'default' | ||
return colorizer[levelNum](LEVELS[levelNum]) | ||
const levelStr = levels[levelNum] | ||
return Object.prototype.hasOwnProperty.call(colorizer, levelNum) ? colorizer[levelNum](levelStr) : colorizer.default(levelStr) | ||
} | ||
function plainColorizer (level) { | ||
return colorizeLevel(level, plain) | ||
function plainColorizer (level, opts) { | ||
return colorizeLevel(level, plain, opts) | ||
} | ||
@@ -51,4 +69,4 @@ plainColorizer.message = plain.message | ||
function coloredColorizer (level) { | ||
return colorizeLevel(level, colored) | ||
function coloredColorizer (level, opts) { | ||
return colorizeLevel(level, colored, opts) | ||
} | ||
@@ -58,2 +76,14 @@ coloredColorizer.message = colored.message | ||
function customColoredColorizerFactory (customColors) { | ||
const customColored = resolveCustomColoredColorizer(customColors) | ||
const customColoredColorizer = function (level, opts) { | ||
return colorizeLevel(level, customColored, opts) | ||
} | ||
customColoredColorizer.message = customColoredColorizer.message || customColored.message | ||
customColoredColorizer.greyMessage = customColoredColorizer.greyMessage || customColored.greyMessage | ||
return customColoredColorizer | ||
} | ||
/** | ||
@@ -65,2 +95,3 @@ * Factory function get a function to colorized levels. The returned function | ||
* terminal colors is returned. | ||
* @param {array[]} [customColors] Touple where first item of each array is the level index and the second item is the color | ||
* | ||
@@ -74,4 +105,10 @@ * @returns {function} `function (level) {}` has a `.message(str)` method to | ||
*/ | ||
module.exports = function getColorizer (useColors = false) { | ||
return useColors ? coloredColorizer : plainColorizer | ||
module.exports = function getColorizer (useColors = false, customColors) { | ||
if (useColors && customColors !== undefined) { | ||
return customColoredColorizerFactory(customColors) | ||
} else if (useColors) { | ||
return coloredColorizer | ||
} | ||
return plainColorizer | ||
} |
@@ -220,4 +220,6 @@ 'use strict' | ||
* value and returns a colorized string. Default: a no-op colorizer. | ||
* @param {string} [levelKey='level'] The key to find the level under. | ||
* @param {string} [input.levelKey='level'] The key to find the level under. | ||
* @param {function} [input.prettifier] A user-supplied formatter to be called instead of colorizer. | ||
* @param {object} [input.customLevels] The custom levels where key as the level index and value as the level name. | ||
* @param {object} [input.customLevelNames] The custom level names where key is the level name and value is the level index. | ||
* | ||
@@ -228,6 +230,6 @@ * @returns {undefined|string} If `log` does not have a `level` property then | ||
*/ | ||
function prettifyLevel ({ log, colorizer = defaultColorizer, levelKey = LEVEL_KEY, prettifier }) { | ||
function prettifyLevel ({ log, colorizer = defaultColorizer, levelKey = LEVEL_KEY, prettifier, customLevels, customLevelNames }) { | ||
if (levelKey in log === false) return undefined | ||
const output = log[levelKey] | ||
return prettifier ? prettifier(output) : colorizer(output) | ||
return prettifier ? prettifier(output) : colorizer(output, { customLevels, customLevelNames }) | ||
} | ||
@@ -247,2 +249,5 @@ | ||
* string which will be the "prettified" message. Default: a no-op colorizer. | ||
* @param {string} [input.levelLabel='levelLabel'] The label used to output the log level | ||
* @param {string} [input.levelKey='level'] The key to find the level under. | ||
* @param {object} [input.customLevels] The custom levels where key as the level index and value as the level name. | ||
* | ||
@@ -253,8 +258,8 @@ * @returns {undefined|string} If the message key is not found, or the message | ||
*/ | ||
function prettifyMessage ({ log, messageFormat, messageKey = MESSAGE_KEY, colorizer = defaultColorizer, levelLabel = LEVEL_LABEL }) { | ||
function prettifyMessage ({ log, messageFormat, messageKey = MESSAGE_KEY, colorizer = defaultColorizer, levelLabel = LEVEL_LABEL, levelKey = LEVEL_KEY, customLevels }) { | ||
if (messageFormat && typeof messageFormat === 'string') { | ||
const message = String(messageFormat).replace(/{([^{}]+)}/g, function (match, p1) { | ||
// return log level as string instead of int | ||
if (p1 === levelLabel && log[LEVEL_KEY]) { | ||
return LEVELS[log[LEVEL_KEY]] | ||
if (p1 === levelLabel && log[levelKey]) { | ||
return customLevels === undefined ? LEVELS[log[levelKey]] : customLevels[log[levelKey]] | ||
} | ||
@@ -261,0 +266,0 @@ // Parse nested key access, e.g. `{keyA.subKeyB}`. |
{ | ||
"name": "pino-pretty", | ||
"version": "7.4.0", | ||
"version": "7.5.0", | ||
"description": "Prettifier for Pino log lines", | ||
@@ -5,0 +5,0 @@ "type": "commonjs", |
@@ -63,2 +63,65 @@ 'use strict' | ||
;['--customLevels', '-x'].forEach((optionName) => { | ||
t.test(`customize levels via ${optionName}`, (t) => { | ||
t.plan(1) | ||
const logLine = '{"level":1,"time":1522431328992,"msg":"hello world","pid":42,"hostname":"foo"}\n' | ||
const child = spawn(process.argv[0], [bin, optionName, 'err:99,info:1'], { env }) | ||
child.on('error', t.threw) | ||
child.stdout.on('data', (data) => { | ||
t.equal(data.toString(), `[${epoch}] INFO (42 on foo): hello world\n`) | ||
}) | ||
child.stdin.write(logLine) | ||
t.teardown(() => child.kill()) | ||
}) | ||
t.test(`customize levels via ${optionName} without index`, (t) => { | ||
t.plan(1) | ||
const logLine = '{"level":1,"time":1522431328992,"msg":"hello world","pid":42,"hostname":"foo"}\n' | ||
const child = spawn(process.argv[0], [bin, optionName, 'err:99,info'], { env }) | ||
child.on('error', t.threw) | ||
child.stdout.on('data', (data) => { | ||
t.equal(data.toString(), `[${epoch}] INFO (42 on foo): hello world\n`) | ||
}) | ||
child.stdin.write(logLine) | ||
t.teardown(() => child.kill()) | ||
}) | ||
t.test(`customize levels via ${optionName} with minimumLevel`, (t) => { | ||
t.plan(1) | ||
const child = spawn(process.argv[0], [bin, '--minimumLevel', 'err', optionName, 'err:99,info:1'], { env }) | ||
child.on('error', t.threw) | ||
child.stdout.on('data', (data) => { | ||
t.equal(data.toString(), `[${epoch}] ERR (42 on foo): hello world\n`) | ||
}) | ||
child.stdin.write('{"level":1,"time":1522431328992,"msg":"hello world","pid":42,"hostname":"foo"}\n') | ||
child.stdin.write('{"level":99,"time":1522431328992,"msg":"hello world","pid":42,"hostname":"foo"}\n') | ||
t.teardown(() => child.kill()) | ||
}) | ||
}) | ||
;['--customColors', '-X'].forEach((optionName) => { | ||
t.test(`customize levels via ${optionName}`, (t) => { | ||
t.plan(1) | ||
const child = spawn(process.argv[0], [bin, optionName, 'info:blue,message:red'], { env }) | ||
child.on('error', t.threw) | ||
child.stdout.on('data', (data) => { | ||
t.equal(data.toString(), `[${epoch}] INFO (42 on foo): hello world\n`) | ||
}) | ||
child.stdin.write(logLine) | ||
t.teardown(() => child.kill()) | ||
}) | ||
t.test(`customize levels via ${optionName} with customLevels`, (t) => { | ||
t.plan(1) | ||
const logLine = '{"level":1,"time":1522431328992,"msg":"hello world","pid":42,"hostname":"foo"}\n' | ||
const child = spawn(process.argv[0], [bin, '--customLevels', 'err:99,info', optionName, 'info:blue,message:red'], { env }) | ||
child.on('error', t.threw) | ||
child.stdout.on('data', (data) => { | ||
t.equal(data.toString(), `[${epoch}] INFO (42 on foo): hello world\n`) | ||
}) | ||
child.stdin.write(logLine) | ||
t.teardown(() => child.kill()) | ||
}) | ||
}) | ||
t.test('does ignore escaped keys', (t) => { | ||
@@ -65,0 +128,0 @@ t.plan(1) |
@@ -79,2 +79,41 @@ 'use strict' | ||
const testCustomColoringColorizer = getColorizer => async t => { | ||
const customLevels = { | ||
0: 'INFO', | ||
1: 'ERR', | ||
default: 'USERLVL' | ||
} | ||
const customLevelNames = { | ||
info: 0, | ||
err: 1 | ||
} | ||
const customColors = [ | ||
[0, 'not-a-color'], | ||
[1, 'red'] | ||
] | ||
const opts = { | ||
customLevels, | ||
customLevelNames | ||
} | ||
const colorizer = getColorizer(true, customColors) | ||
let colorized = colorizer(1, opts) | ||
t.equal(colorized, '\u001B[31mERR\u001B[39m') | ||
colorized = colorizer(0, opts) | ||
t.equal(colorized, '\u001B[37mINFO\u001B[39m') | ||
colorized = colorizer(900) | ||
t.equal(colorized, '\u001B[37mUSERLVL\u001B[39m') | ||
colorized = colorizer('err', opts) | ||
t.equal(colorized, '\u001B[31mERR\u001B[39m') | ||
colorized = colorizer('info', opts) | ||
t.equal(colorized, '\u001B[37mINFO\u001B[39m') | ||
colorized = colorizer('use-default') | ||
t.equal(colorized, '\u001B[37mUSERLVL\u001B[39m') | ||
} | ||
test('returns default colorizer - private export', testDefaultColorizer(getColorizerPrivate)) | ||
@@ -84,1 +123,3 @@ test('returns default colorizer - public export', testDefaultColorizer(getColorizerPublic)) | ||
test('returns colorizing colorizer - public export', testColoringColorizer(getColorizerPublic)) | ||
test('returns custom colorizing colorizer - private export', testCustomColoringColorizer(getColorizerPrivate)) | ||
test('returns custom colorizing colorizer - public export', testCustomColoringColorizer(getColorizerPublic)) |
@@ -109,2 +109,7 @@ 'use strict' | ||
t.test('returns message formatted by `messageFormat` option - levelLabel & customLevels', async t => { | ||
const str = prettifyMessage({ log: { msg: 'foo', context: 'appModule', level: 123 }, messageFormat: '[{level}] {levelLabel} {context} - {msg}', customLevels: { 123: 'CUSTOM' } }) | ||
t.equal(str, '[123] CUSTOM appModule - foo') | ||
}) | ||
t.test('`messageFormat` supports nested curly brackets', async t => { | ||
@@ -111,0 +116,0 @@ const str = prettifyMessage({ log: { level: 30 }, messageFormat: '{{level}}-{level}-{{level}-{level}}' }) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
325509
3541