diff --git a/docs/api.md b/docs/api.md index ec357fdda..634868957 100644 --- a/docs/api.md +++ b/docs/api.md @@ -369,6 +369,37 @@ documented in the [Browser API ⇗](/docs/browser.md) documentation. * See [Browser API ⇗](/docs/browser.md) +#### `transport` (Object) + +The `transport` option is a shorthand for the [pino.transport()](#pino-transport) function. +It supports the same input options: +```js +require('pino')({ + transport: { + target: '/absolute/path/to/my-transport.mjs' + } +}) + +// or multiple transports +require('pino')({ + transport: { + targets: [ + { target: '/absolute/path/to/my-transport.mjs', level: 'error' }, + { target: 'some-file-transport', options: { destination: '/dev/null' } + ] + } +}) +``` + +If the transport option is supplied to `pino`, a [`destination`](#destination) parameter may not also be passed as a separate argument to `pino`: + +```js +pino({ transport: {}}, '/path/to/somewhere') // THIS WILL NOT WORK, DO NOT DO THIS +pino({ transport: {}}, process.stderr) // THIS WILL NOT WORK, DO NOT DO THIS +when using the `transport` option. In this case an `Error` will be thrown. + +* See [pino.transport()](#pino-transport) + ### `destination` (SonicBoom | WritableStream | String | Object) diff --git a/lib/tools.js b/lib/tools.js index a238c1957..63bb7466a 100644 --- a/lib/tools.js +++ b/lib/tools.js @@ -27,6 +27,7 @@ const { nestedKeyStrSym } = require('./symbols') const { isMainThread } = require('worker_threads') +const transport = require('./transport') function noop () {} @@ -395,10 +396,16 @@ function createArgsNormalizer (defaultOptions) { stream = buildSafeSonicBoom({ dest: opts, sync: true }) opts = {} } else if (typeof stream === 'string') { + if (opts && opts.transport) { + throw Error('only one of option.transport or stream can be specified') + } stream = buildSafeSonicBoom({ dest: stream, sync: true }) } else if (opts instanceof SonicBoom || opts.writable || opts._writableState) { stream = opts opts = null + } else if (opts.transport) { + stream = transport(opts.transport) + opts = null } opts = Object.assign({}, defaultOptions, opts) opts.serializers = Object.assign({}, defaultOptions.serializers, opts.serializers) diff --git a/lib/transport.js b/lib/transport.js index 7d478e139..f43c776f5 100644 --- a/lib/transport.js +++ b/lib/transport.js @@ -64,7 +64,7 @@ function transport (fullOptions) { let target = fullOptions.target if (target && targets) { - throw new Error('Only one of target or targets can be specified') + throw new Error('only one of target or targets can be specified') } if (targets) { diff --git a/test/transport.test.js b/test/transport.test.js index d77e99843..213b4472b 100644 --- a/test/transport.test.js +++ b/test/transport.test.js @@ -299,7 +299,7 @@ test('pino.transport with target and targets', async ({ fail, equal }) => { }) fail('must throw') } catch (err) { - equal(err.message, 'Only one of target or targets can be specified') + equal(err.message, 'only one of target or targets can be specified') } }) @@ -386,3 +386,95 @@ test('stdout in worker', async ({ not }) => { await once(child, 'close') not(strip(actual).match(/Hello/), null) }) + +test('pino transport options with target', async ({ teardown, same }) => { + const destination = join( + os.tmpdir(), + '_' + Math.random().toString(36).substr(2, 9) + ) + const instance = pino({ + transport: { + target: '#pino/file', + options: { destination } + } + }) + const transportStream = instance[pino.symbols.streamSym] + teardown(transportStream.end.bind(transportStream)) + instance.info('transport option test') + await watchFileCreated(destination) + const result = JSON.parse(await readFile(destination)) + delete result.time + same(result, { + pid, + hostname, + level: 30, + msg: 'transport option test' + }) +}) + +test('pino transport options with targets', async ({ teardown, same }) => { + const dest1 = join( + os.tmpdir(), + '_' + Math.random().toString(36).substr(2, 9) + ) + const dest2 = join( + os.tmpdir(), + '_' + Math.random().toString(36).substr(2, 9) + ) + const instance = pino({ + transport: { + targets: [ + { target: '#pino/file', options: { destination: dest1 } }, + { target: '#pino/file', options: { destination: dest2 } } + ] + } + }) + const transportStream = instance[pino.symbols.streamSym] + teardown(transportStream.end.bind(transportStream)) + instance.info('transport option test') + + await Promise.all([watchFileCreated(dest1), watchFileCreated(dest2)]) + const result1 = JSON.parse(await readFile(dest1)) + delete result1.time + same(result1, { + pid, + hostname, + level: 30, + msg: 'transport option test' + }) + const result2 = JSON.parse(await readFile(dest2)) + delete result2.time + same(result2, { + pid, + hostname, + level: 30, + msg: 'transport option test' + }) +}) + +test('transport options with target and targets', async ({ fail, equal }) => { + try { + pino({ + transport: { + target: {}, + targets: {} + } + }) + fail('must throw') + } catch (err) { + equal(err.message, 'only one of target or targets can be specified') + } +}) + +test('transport options with target and stream', async ({ fail, equal }) => { + try { + pino({ + transport: { + target: {} + } + }, '/log/null') + fail('must throw') + } catch (err) { + equal(err.message, 'only one of option.transport or stream can be specified') + } +})