Skip to content

Commit

Permalink
feat: automatically consume pino config when using pino@>=8.21.0 (#508)
Browse files Browse the repository at this point in the history
  • Loading branch information
10xLaCroixDrinker committed Apr 29, 2024
1 parent 2596a6b commit 4f992c2
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 21 deletions.
11 changes: 10 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,14 @@ jobs:
contents: read
strategy:
matrix:
node-version: [14, 16, 18]
node-version: [14, 16, 18, 20]
os: [ubuntu-latest]
pino-version: [8.20.0, ^8.21.0, ^9.0.0]
exclude:
- node-version: 14
pino-version: ^9.0.0
- node-version: 16
pino-version: ^9.0.0
steps:
- name: Check out repo
uses: actions/checkout@v4
Expand All @@ -62,6 +68,9 @@ jobs:
- name: Install dependencies
run: npm i --ignore-scripts

- name: Install pino ${{ matrix.pino-version }}
run: npm i --no-save pino@${{ matrix.pino-version }}

- name: Run tests
run: npm run ci

Expand Down
6 changes: 3 additions & 3 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,10 +240,10 @@ The options accepted have keys corresponding to the options described in [CLI Ar
colorize: colorette.isColorSupported, // --colorize
colorizeObjects: true, //--colorizeObjects
crlf: false, // --crlf
errorLikeObjectKeys: ['err', 'error'], // --errorLikeObjectKeys
errorLikeObjectKeys: ['err', 'error'], // --errorLikeObjectKeys (not required to match custom errorKey with pino >=8.21.0)
errorProps: '', // --errorProps
levelFirst: false, // --levelFirst
messageKey: 'msg', // --messageKey
messageKey: 'msg', // --messageKey (not required with pino >=8.21.0)
levelKey: 'level', // --levelKey
messageFormat: false, // --messageFormat
timestampKey: 'time', // --timestampKey
Expand All @@ -253,7 +253,7 @@ The options accepted have keys corresponding to the options described in [CLI Ar
hideObject: false, // --hideObject
singleLine: false, // --singleLine
customColors: 'err:red,info:blue', // --customColors
customLevels: 'err:99,info:1', // --customLevels
customLevels: 'err:99,info:1', // --customLevels (not required with pino >=8.21.0)
levelLabel: 'levelLabel', // --levelLabel
minimumLevel: 'info', // --minimumLevel
useOnlyCustomProps: true, // --useOnlyCustomProps
Expand Down
6 changes: 6 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ interface PrettyOptions_ {
/**
* The key in the JSON object to use as the highlighted message.
* @default "msg"
*
* Not required when used with pino >= 8.21.0
*/
messageKey?: string;
/**
Expand Down Expand Up @@ -122,6 +124,8 @@ interface PrettyOptions_ {
/**
* Define the log keys that are associated with error like objects.
* @default ["err", "error"]
*
* Not required to handle custom errorKey when used with pino >= 8.21.0
*/
errorLikeObjectKeys?: string[];
/**
Expand Down Expand Up @@ -192,6 +196,8 @@ interface PrettyOptions_ {
*
* @example ( CSV ) customLevels: 'info:10,some_level:40'
* @example ( Object ) customLevels: { info: 10, some_level: 40 }
*
* Not required when used with pino >= 8.21.0
*/
customLevels?: string|object;
/**
Expand Down
12 changes: 11 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,18 @@ function prettyFactory (options) {
* @returns {Transform | (Transform & OnUnknown)}
*/
function build (opts = {}) {
const pretty = prettyFactory(opts)
let pretty = prettyFactory(opts)
return abstractTransport(function (source) {
source.on('message', function pinoConfigListener (message) {
if (!message || message.code !== 'PINO_CONFIG') return
Object.assign(opts, {
messageKey: message.config.messageKey,
errorLikeObjectKeys: Array.from(new Set([...(opts.errorLikeObjectKeys || ERROR_LIKE_KEYS), message.config.errorKey])),
customLevels: message.config.levels.values
})
pretty = prettyFactory(opts)
source.off('message', pinoConfigListener)
})
const stream = new Transform({
objectMode: true,
autoDestroy: true,
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"pino": "^9.0.0",
"pre-commit": "^1.2.2",
"rimraf": "^3.0.2",
"semver": "^7.6.0",
"snazzy": "^9.0.0",
"standard": "^17.0.0",
"tap": "^16.0.0",
Expand Down
86 changes: 71 additions & 15 deletions test/basic.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const path = require('path')
const rimraf = require('rimraf')
const { join } = require('path')
const fs = require('fs')
const semver = require('semver')
const pinoPretty = require('..')
const SonicBoom = require('sonic-boom')
const _prettyFactory = pinoPretty.prettyFactory
Expand Down Expand Up @@ -1074,7 +1075,7 @@ test('basic prettifier tests', (t) => {
t.test('stream usage', async (t) => {
t.plan(1)
const tmpDir = path.join(__dirname, '.tmp_' + Date.now())
t.teardown(() => rimraf(tmpDir, noop))
t.teardown(() => rimraf.sync(tmpDir))

const destination = join(tmpDir, 'output')

Expand Down Expand Up @@ -1102,24 +1103,28 @@ test('basic prettifier tests', (t) => {
t.test('sync option', async (t) => {
t.plan(1)
const tmpDir = path.join(__dirname, '.tmp_' + Date.now())
t.teardown(() => rimraf(tmpDir, noop))
t.teardown(() => rimraf.sync(tmpDir))

const destination = join(tmpDir, 'output')

const pretty = pinoPretty({
singleLine: true,
colorize: false,
mkdir: true,
append: false,
sync: true,
destination
})
const log = pino(pretty)
log.info({ msg: 'message', extra: { foo: 'bar', number: 42 }, upper: 'foobar' })
const log = pino(pino.transport({
target: '..',
options: {
singleLine: true,
colorize: false,
mkdir: true,
append: false,
sync: true,
destination
}
}))
log.info({ msg: 'message', extra: { foo: 'bar', number: 43 }, upper: 'foobar' })

await watchFileCreated(destination)

const formatted = fs.readFileSync(destination, 'utf8')

t.equal(formatted, `[${formattedEpoch}] INFO (${pid}): message {"extra":{"foo":"bar","number":42},"upper":"foobar"}\n`)
t.equal(formatted, `[${formattedEpoch}] INFO (${pid}): message {"extra":{"foo":"bar","number":43},"upper":"foobar"}\n`)
})

t.test('support custom colors object', async (t) => {
Expand Down Expand Up @@ -1151,6 +1156,59 @@ test('basic prettifier tests', (t) => {
t.end()
})

if (semver.gte(pino.version, '8.21.0')) {
test('using pino config', (t) => {
t.beforeEach(() => {
Date.originalNow = Date.now
Date.now = () => epoch
})
t.afterEach(() => {
Date.now = Date.originalNow
delete Date.originalNow
})

t.test('can use different message keys', (t) => {
t.plan(1)
const destination = new Writable({
write (formatted, enc, cb) {
t.equal(
formatted.toString(),
`[${formattedEpoch}] INFO (${pid}): baz\n`
)
cb()
}
})
const pretty = pinoPretty({
destination,
colorize: false
})
const log = pino({ messageKey: 'bar' }, pretty)
log.info({ bar: 'baz' })
})

t.test('handles customLogLevels', (t) => {
t.plan(1)
const destination = new Writable({
write (formatted, enc, cb) {
t.equal(
formatted.toString(),
`[${formattedEpoch}] TESTCUSTOM (${pid}): test message\n`
)
cb()
}
})
const pretty = pinoPretty({
destination,
colorize: false
})
const log = pino({ customLevels: { testCustom: 35 } }, pretty)
log.testCustom('test message')
})

t.end()
})
}

function watchFileCreated (filename) {
return new Promise((resolve, reject) => {
const TIMEOUT = 2000
Expand All @@ -1171,5 +1229,3 @@ function watchFileCreated (filename) {
}, INTERVAL)
})
}

function noop () {}
47 changes: 46 additions & 1 deletion test/error-objects.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ process.env.TZ = 'UTC'
const Writable = require('stream').Writable
const test = require('tap').test
const pino = require('pino')
const semver = require('semver')
const serializers = pino.stdSerializers
const _prettyFactory = require('../').prettyFactory
const pinoPretty = require('../')
const _prettyFactory = pinoPretty.prettyFactory

function prettyFactory (opts) {
if (!opts) {
Expand Down Expand Up @@ -452,3 +454,46 @@ test('error like objects tests', (t) => {

t.end()
})

if (semver.gte(pino.version, '8.21.0')) {
test('using pino config', (t) => {
t.beforeEach(() => {
Date.originalNow = Date.now
Date.now = () => epoch
})
t.afterEach(() => {
Date.now = Date.originalNow
delete Date.originalNow
})

t.test('prettifies Error in custom errorKey', (t) => {
t.plan(8)
const destination = new Writable({
write (chunk, enc, cb) {
const formatted = chunk.toString()
const lines = formatted.split('\n')
t.equal(lines.length, expected.length + 7)
t.equal(lines[0], `[${formattedEpoch}] INFO (${pid}): hello world`)
t.match(lines[1], /\s{4}customErrorKey: {/)
t.match(lines[2], /\s{6}"type": "Error",/)
t.match(lines[3], /\s{6}"message": "hello world",/)
t.match(lines[4], /\s{6}"stack":/)
t.match(lines[5], /\s{6}Error: hello world/)
// Node 12 labels the test `<anonymous>`
t.match(lines[6], /\s{10}(at Test.t.test|at Test.<anonymous>)/)
cb()
}
})
const pretty = pinoPretty({
destination,
colorize: false
})
const log = pino({ errorKey: 'customErrorKey' }, pretty)
const err = Error('hello world')
const expected = err.stack.split('\n')
log.info({ customErrorKey: err })
})

t.end()
})
}

0 comments on commit 4f992c2

Please sign in to comment.