Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to override custom levels comparison #1883

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions lib/levels.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ const {
useOnlyCustomLevelsSym,
streamSym,
formattersSym,
hooksSym
hooksSym,
levelCompSym
} = require('./symbols')
const { noop, genLog } = require('./tools')

Expand Down Expand Up @@ -119,7 +120,19 @@ function getLevel (level) {
function isLevelEnabled (logLevel) {
const { values } = this.levels
const logLevelVal = values[logLevel]
return logLevelVal !== undefined && (logLevelVal >= this[levelValSym])
return logLevelVal !== undefined && this[levelCompSym](logLevelVal, this[levelValSym])
}

function genLevelComparison (levelComparison) {
if (levelComparison === 'ASC') {
return (current, expected) => current >= expected
}

if (levelComparison === 'DESC') {
return (current, expected) => current <= expected
}
obrus-corcentric marked this conversation as resolved.
Show resolved Hide resolved

return levelComparison
}

function mappings (customLevels = null, useOnlyCustomLevels = false) {
Expand Down Expand Up @@ -180,6 +193,14 @@ function assertNoLevelCollisions (levels, customLevels) {
}
}

function assertLevelComparison (levelComparison) {
obrus-corcentric marked this conversation as resolved.
Show resolved Hide resolved
if (['ASC', 'DESC'].includes(levelComparison) || typeof levelComparison === 'function') {
return
}

throw new Error('Levels comparison should be one of "ASC", "DESC" or "function" type')
jsumners marked this conversation as resolved.
Show resolved Hide resolved
}

module.exports = {
initialLsCache,
genLsCache,
Expand All @@ -190,5 +211,7 @@ module.exports = {
mappings,
jsumners marked this conversation as resolved.
Show resolved Hide resolved
levels,
assertNoLevelCollisions,
assertDefaultLevelFound
assertDefaultLevelFound,
genLevelComparison,
assertLevelComparison
}
2 changes: 2 additions & 0 deletions lib/symbols.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const setLevelSym = Symbol('pino.setLevel')
const getLevelSym = Symbol('pino.getLevel')
const levelValSym = Symbol('pino.levelVal')
const levelCompSym = Symbol('pino.levelComp')
const useLevelLabelsSym = Symbol('pino.useLevelLabels')
const useOnlyCustomLevelsSym = Symbol('pino.useOnlyCustomLevels')
const mixinSym = Symbol('pino.mixin')
Expand Down Expand Up @@ -42,6 +43,7 @@ module.exports = {
setLevelSym,
getLevelSym,
levelValSym,
levelCompSym,
useLevelLabelsSym,
mixinSym,
lsCacheSym,
Expand Down
9 changes: 8 additions & 1 deletion pino.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,12 @@ declare namespace pino {
* The keys of the object correspond the namespace of the log level, and the values should be the numerical value of the level.
*/
customLevels?: { [level in CustomLevels]: number };
/**
* Use this option to define custom comparison of log levels.
* Usefull to compare custom log levels or non-standard level values.
* Default: "ASC"
*/
levelComparison?: "ASC" | "DESC" | ((current: number, expected: number) => boolean);
/**
* Use this option to only use defined `customLevels` and omit Pino's levels.
* Logger's default `level` must be changed to a value in `customLevels` in order to use `useOnlyCustomLevels`
Expand Down Expand Up @@ -853,4 +859,5 @@ export { pino as default, pino };
// Export just the type side of the namespace as "P", allows
// `import {P} from "pino"; const log: P.Logger;`.
// (Legacy support for early 7.x releases, remove in 8.x.)
export type { pino as P };
export type { pino as P };

9 changes: 8 additions & 1 deletion pino.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const time = require('./lib/time')
const proto = require('./lib/proto')
const symbols = require('./lib/symbols')
const { configure } = require('safe-stable-stringify')
const { assertDefaultLevelFound, mappings, genLsCache, levels } = require('./lib/levels')
const { assertDefaultLevelFound, mappings, genLsCache, levels, genLevelComparison, assertLevelComparison } = require('./lib/levels')
const {
createArgsNormalizer,
asChindings,
Expand Down Expand Up @@ -36,6 +36,7 @@ const {
errorKeySym,
nestedKeySym,
mixinSym,
levelCompSym,
useOnlyCustomLevelsSym,
formattersSym,
hooksSym,
Expand All @@ -49,6 +50,7 @@ const hostname = os.hostname()
const defaultErrorSerializer = stdSerializers.err
const defaultOptions = {
level: 'info',
levelComparison: 'ASC',
levels,
messageKey: 'msg',
errorKey: 'err',
Expand Down Expand Up @@ -97,6 +99,7 @@ function pino (...args) {
name,
level,
customLevels,
levelComparison,
mixin,
mixinMergeStrategy,
useOnlyCustomLevels,
Expand Down Expand Up @@ -157,8 +160,12 @@ function pino (...args) {
assertDefaultLevelFound(level, customLevels, useOnlyCustomLevels)
const levels = mappings(customLevels, useOnlyCustomLevels)

assertLevelComparison(levelComparison)
const levelCompFunc = genLevelComparison(levelComparison)

Object.assign(instance, {
levels,
[levelCompSym]: levelCompFunc,
[useOnlyCustomLevelsSym]: useOnlyCustomLevels,
[streamSym]: stream,
[timeSym]: time,
Expand Down
198 changes: 170 additions & 28 deletions test/is-level-enabled.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,183 @@
const { test } = require('tap')
const pino = require('../')

test('can check if current level enabled', async ({ equal }) => {
const log = pino({ level: 'debug' })
equal(true, log.isLevelEnabled('debug'))
})
const descLevels = {
trace: 60,
debug: 50,
info: 40,
warn: 30,
error: 20,
fatal: 10
}

test('can check if level enabled after level set', async ({ equal }) => {
const log = pino()
equal(false, log.isLevelEnabled('debug'))
log.level = 'debug'
equal(true, log.isLevelEnabled('debug'))
})
const ascLevels = {
trace: 10,
debug: 20,
info: 30,
warn: 40,
error: 50,
fatal: 60
}

test('Default levels suite', ({ test, end }) => {
test('can check if current level enabled', async ({ equal }) => {
const log = pino({ level: 'debug' })
equal(true, log.isLevelEnabled('debug'))
})

test('can check if level enabled after level set', async ({ equal }) => {
const log = pino()
equal(false, log.isLevelEnabled('debug'))
log.level = 'debug'
equal(true, log.isLevelEnabled('debug'))
})

test('can check if higher level enabled', async ({ equal }) => {
const log = pino({ level: 'debug' })
equal(true, log.isLevelEnabled('error'))
})

test('can check if lower level is disabled', async ({ equal }) => {
const log = pino({ level: 'error' })
equal(false, log.isLevelEnabled('trace'))
})

test('ASC: can check if child has current level enabled', async ({ equal }) => {
const log = pino().child({}, { level: 'debug' })
equal(true, log.isLevelEnabled('debug'))
equal(true, log.isLevelEnabled('error'))
equal(false, log.isLevelEnabled('trace'))
})

test('can check if higher level enabled', async ({ equal }) => {
const log = pino({ level: 'debug' })
equal(true, log.isLevelEnabled('error'))
test('can check if custom level is enabled', async ({ equal }) => {
const log = pino({
customLevels: { foo: 35 },
level: 'debug'
})
equal(true, log.isLevelEnabled('foo'))
equal(true, log.isLevelEnabled('error'))
equal(false, log.isLevelEnabled('trace'))
})

end()
})

test('can check if lower level is disabled', async ({ equal }) => {
const log = pino({ level: 'error' })
equal(false, log.isLevelEnabled('trace'))
test('Ascending levels suite', ({ test, end }) => {
const customLevels = ascLevels
const levelComparison = 'ASC'

test('can check if current level enabled', async ({ equal }) => {
const log = pino({ level: 'debug', levelComparison, customLevels, useOnlyCustomLevels: true })
equal(true, log.isLevelEnabled('debug'))
})

test('can check if level enabled after level set', async ({ equal }) => {
const log = pino({ levelComparison, customLevels, useOnlyCustomLevels: true })
equal(false, log.isLevelEnabled('debug'))
log.level = 'debug'
equal(true, log.isLevelEnabled('debug'))
})

test('can check if higher level enabled', async ({ equal }) => {
const log = pino({ level: 'debug', levelComparison, customLevels, useOnlyCustomLevels: true })
equal(true, log.isLevelEnabled('error'))
})

test('can check if lower level is disabled', async ({ equal }) => {
const log = pino({ level: 'error', customLevels, useOnlyCustomLevels: true })
equal(false, log.isLevelEnabled('trace'))
})

test('can check if child has current level enabled', async ({ equal }) => {
const log = pino().child({ levelComparison, customLevels, useOnlyCustomLevels: true }, { level: 'debug' })
equal(true, log.isLevelEnabled('debug'))
equal(true, log.isLevelEnabled('error'))
equal(false, log.isLevelEnabled('trace'))
})

test('can check if custom level is enabled', async ({ equal }) => {
const log = pino({
levelComparison,
useOnlyCustomLevels: true,
customLevels: { foo: 35, ...customLevels },
level: 'debug'
})
equal(true, log.isLevelEnabled('foo'))
equal(true, log.isLevelEnabled('error'))
equal(false, log.isLevelEnabled('trace'))
})

end()
})

test('can check if child has current level enabled', async ({ equal }) => {
const log = pino().child({}, { level: 'debug' })
equal(true, log.isLevelEnabled('debug'))
equal(true, log.isLevelEnabled('error'))
equal(false, log.isLevelEnabled('trace'))
test('Descending levels suite', ({ test, end }) => {
const customLevels = descLevels
const levelComparison = 'DESC'

test('can check if current level enabled', async ({ equal }) => {
const log = pino({ level: 'debug', levelComparison, customLevels, useOnlyCustomLevels: true })
equal(true, log.isLevelEnabled('debug'))
})

test('can check if level enabled after level set', async ({ equal }) => {
const log = pino({ levelComparison, customLevels, useOnlyCustomLevels: true })
equal(false, log.isLevelEnabled('debug'))
log.level = 'debug'
equal(true, log.isLevelEnabled('debug'))
})

test('can check if higher level enabled', async ({ equal }) => {
const log = pino({ level: 'debug', levelComparison, customLevels, useOnlyCustomLevels: true })
equal(true, log.isLevelEnabled('error'))
})

test('can check if lower level is disabled', async ({ equal }) => {
const log = pino({ level: 'error', levelComparison, customLevels, useOnlyCustomLevels: true })
equal(false, log.isLevelEnabled('trace'))
})

test('can check if child has current level enabled', async ({ equal }) => {
const log = pino({ levelComparison, customLevels, useOnlyCustomLevels: true }).child({}, { level: 'debug' })
equal(true, log.isLevelEnabled('debug'))
equal(true, log.isLevelEnabled('error'))
equal(false, log.isLevelEnabled('trace'))
})

test('can check if custom level is enabled', async ({ equal }) => {
const log = pino({
levelComparison,
customLevels: { foo: 35, ...customLevels },
useOnlyCustomLevels: true,
level: 'debug'
})
equal(true, log.isLevelEnabled('foo'))
equal(true, log.isLevelEnabled('error'))
equal(false, log.isLevelEnabled('trace'))
})

end()
})

test('can check if custom level is enabled', async ({ equal }) => {
const log = pino({
customLevels: { foo: 35 },
level: 'debug'
test('Custom levels comparison', async ({ test, end }) => {
test('Custom comparison returns true cause level is enabled', async ({ equal }) => {
const log = pino({ level: 'error', levelComparison: () => true })
equal(true, log.isLevelEnabled('debug'))
})

test('Custom comparison returns false cause level is disabled', async ({ equal }) => {
const log = pino({ level: 'error', levelComparison: () => false })
equal(false, log.isLevelEnabled('debug'))
})
equal(true, log.isLevelEnabled('foo'))
equal(true, log.isLevelEnabled('error'))
equal(false, log.isLevelEnabled('trace'))

test('Custom comparison returns true cause child level is enabled', async ({ equal }) => {
const log = pino({ levelComparison: () => true }).child({ level: 'error' })
equal(true, log.isLevelEnabled('debug'))
})

test('Custom comparison returns false cause child level is disabled', async ({ equal }) => {
const log = pino({ levelComparison: () => false }).child({ level: 'error' })
equal(false, log.isLevelEnabled('debug'))
})

end()
})
Loading