diff --git a/Readme.md b/Readme.md index df8f0617..6892ad01 100644 --- a/Readme.md +++ b/Readme.md @@ -207,6 +207,13 @@ The options accepted have keys corresponding to the options described in [CLI Ar ignore: 'pid,hostname', // --ignore hideObject: false, // --hideObject singleLine: false, // --singleLine + + // The file or file descriptor (1 is stdout) to write to + destination: 1, + + // Alternatively, pass a `sonic-boom` instance (allowing more flexibility): + // destination: new SonicBoom({ dest: 'a/file', mkdir: true }) + customPrettifiers: {} } ``` diff --git a/index.js b/index.js index fa950aad..93e3bb09 100644 --- a/index.js +++ b/index.js @@ -183,7 +183,18 @@ function build (opts = {}) { } }) - const destination = sonic({ dest: opts.destination || 1, sync: false }) + let destination + + if (typeof opts.destination === 'object' && typeof opts.destination.write === 'function') { + destination = opts.destination + } else { + destination = sonic({ + dest: opts.destination || 1, + append: opts.append, + mkdir: opts.mkdir, + sync: false + }) + } /* istanbul ignore else */ if (destination.fd === 1) { // We cannot close the output diff --git a/test/basic.test.js b/test/basic.test.js index 30898d75..a0a421c0 100644 --- a/test/basic.test.js +++ b/test/basic.test.js @@ -5,9 +5,17 @@ const os = require('os') const test = require('tap').test const pino = require('pino') const dateformat = require('dateformat') +const path = require('path') +const rimraf = require('rimraf') +const { join } = require('path') +const fs = require('fs') const pinoPretty = require('..') +const SonicBoom = require('sonic-boom') const _prettyFactory = pinoPretty.prettyFactory +// Disable pino warnings +process.removeAllListeners('warning') + function prettyFactory (opts) { if (!opts) { opts = { colorize: false } @@ -748,5 +756,56 @@ test('basic prettifier tests', (t) => { t.doesNotThrow(pinoPretty) }) + t.test('stream usage', async (t) => { + t.plan(1) + const tmpDir = path.join(__dirname, '.tmp_' + Date.now()) + t.teardown(() => rimraf(tmpDir, noop)) + + const destination = join(tmpDir, 'output') + + const pretty = pinoPretty({ + singleLine: true, + colorize: false, + mkdir: true, + append: false, + destination: new SonicBoom({ dest: destination, async: false, mkdir: true, append: true }), + customPrettifiers: { + upper: val => val.toUpperCase(), + undef: () => undefined + } + }) + const log = pino(pretty) + log.info({ msg: 'message', extra: { foo: 'bar', number: 42 }, upper: 'foobar', undef: 'this will not show up' }) + + await watchFileCreated(destination) + + const formatted = fs.readFileSync(destination, 'utf8') + + t.equal(formatted, `[${epoch}] INFO (${pid} on ${hostname}): message {"extra":{"foo":"bar","number":42},"upper":"FOOBAR"}\n`) + }) + t.end() }) + +function watchFileCreated (filename) { + return new Promise((resolve, reject) => { + const TIMEOUT = 2000 + const INTERVAL = 100 + const threshold = TIMEOUT / INTERVAL + let counter = 0 + const interval = setInterval(() => { + // On some CI runs file is created but not filled + if (fs.existsSync(filename) && fs.statSync(filename).size !== 0) { + clearInterval(interval) + resolve() + } else if (counter <= threshold) { + counter++ + } else { + clearInterval(interval) + reject(new Error(`${filename} was not created.`)) + } + }, INTERVAL) + }) +} + +function noop () {}