From 5d8eb719761003bce52d12ccc9e0a5b69ef9e185 Mon Sep 17 00:00:00 2001 From: Daniele Bacarella Date: Thu, 17 Feb 2022 18:11:39 +0100 Subject: [PATCH] Added documentation for MultiStreamRes, StreamEntry, DestinationStream and Level (#1342) * Added documentation about MultiStreamRes, StreamEntry, DestinationStream and Level * fix branching in multistream#add --- docs/api.md | 64 ++++++++++++++++++++++++++- lib/multistream.js | 42 +++++++++++++----- pino.d.ts | 4 +- test/multistream.test.js | 39 +++++++++++++++- test/types/pino-multistream.test-d.ts | 1 + 5 files changed, 133 insertions(+), 17 deletions(-) diff --git a/docs/api.md b/docs/api.md index 3efe63782..15570949a 100644 --- a/docs/api.md +++ b/docs/api.md @@ -30,6 +30,12 @@ * [pino.stdTimeFunctions](#pino-stdtimefunctions) * [pino.symbols](#pino-symbols) * [pino.version](#pino-version) +* [Interfaces](#interfaces) + * [MultiStreamRes](#multistreamres) + * [StreamEntry](#streamentry) + * [DestinationStream](#destinationstream) +* [Types](#types) + * [Level](#level-1) ## `pino([options], [destination]) => logger` @@ -1164,9 +1170,10 @@ finalLogger.info('exiting...') -### `pino.multistream(options) => Stream` +### `pino.multistream(streamsArray, opts) => MultiStreamRes` -Create a stream composed by multiple destination streams: +Create a stream composed by multiple destination streams and returns an +object implementing the [MultiStreamRes](#multistreamres) interface. ```js var fs = require('fs') @@ -1272,3 +1279,56 @@ for general use. Exposes the Pino package version. Also available on the logger instance. * See [`logger.version`](#version) + +## Interfaces + + +### `MultiStreamRes` + Properties: + + * `write(data)` + - `data` Object | string + - Returns: void + + Write `data` onto the streams held by the current instance. + * `add(dest)` + - `dest` [StreamEntry](#streamentry) | [DestinationStream](#destinationstream) + - Returns: [MultiStreamRes](#multistreamres) + + Add `dest` stream to the array of streams of the current instance. + * `flushSync()` + - Returns: `undefined` + + Call `flushSync` on each stream held by the current instance. + * `minLevel` + - number + + The minimum level amongst all the streams held by the current instance. + * `streams` + - Returns: [StreamEntry[]](#streamentry) + + The array of streams currently held by the current instance. + * `clone(level)` + - `level` [Level](#level-1) + - Returns: [MultiStreamRes](#multistreamres) + + Returns a cloned object of the current instance but with the the provided `level`. + +### `StreamEntry` + Properties: + + * `stream` + - DestinationStream + * `level` + - Optional: [Level](#level-1) + +### `DestinationStream` + Properties: + + * `write(msg)` + - `msg` string + +## Types +### `Level` + + * Values: `"fatal"` | `"error"` | `"warn"` | `"info"` | `"debug"` | `"trace"` diff --git a/lib/multistream.js b/lib/multistream.js index 96527986b..45213edd2 100644 --- a/lib/multistream.js +++ b/lib/multistream.js @@ -6,9 +6,10 @@ const { levels } = require('./levels') const defaultLevels = Object.create(levels) defaultLevels.silent = Infinity +const DEFAULT_INFO_LEVEL = levels.info + function multistream (streamsArray, opts) { let counter = 0 - streamsArray = streamsArray || [] opts = opts || { dedupe: false } @@ -77,22 +78,39 @@ function multistream (streamsArray, opts) { } function add (dest) { + if (!dest) { + return res + } + + // Check that dest implements either StreamEntry or DestinationStream + const isStream = typeof dest.write === 'function' || dest.stream + const stream_ = dest.write ? dest : dest.stream + // This is necessary to provide a meaningful error message, otherwise it throws somewhere inside write() + if (!isStream) { + throw Error('stream object needs to implement either StreamEntry or DestinationStream interface') + } + const { streams } = this - if (typeof dest.write === 'function') { - return add.call(this, { stream: dest }) - } else if (typeof dest.levelVal === 'number') { - return add.call(this, Object.assign({}, dest, { level: dest.levelVal, levelVal: undefined })) + + let level + if (typeof dest.levelVal === 'number') { + level = dest.levelVal } else if (typeof dest.level === 'string') { - return add.call(this, Object.assign({}, dest, { level: levels[dest.level] })) - } else if (typeof dest.level !== 'number') { - // we default level to 'info' - dest = Object.assign({}, dest, { level: 30 }) + level = levels[dest.level] + } else if (typeof dest.level === 'number') { + level = dest.level } else { - dest = Object.assign({}, dest) + level = DEFAULT_INFO_LEVEL + } + + const dest_ = { + stream: stream_, + level, + levelVal: undefined, + id: counter++ } - dest.id = counter++ - streams.unshift(dest) + streams.unshift(dest_) streams.sort(compareByLevel) this.minLevel = streams[0].level diff --git a/pino.d.ts b/pino.d.ts index 31efc4f7b..b1be3867f 100644 --- a/pino.d.ts +++ b/pino.d.ts @@ -261,10 +261,10 @@ declare namespace pino { interface MultiStreamRes { write: (data: any) => void, - add: (dest: Record) => MultiStreamRes, + add: (dest: StreamEntry | DestinationStream) => MultiStreamRes, flushSync: () => void, minLevel: number, - streams: ({ stream: DestinationStream, level: number, id: number })[], + streams: StreamEntry[], clone(level: Level): MultiStreamRes, } diff --git a/test/multistream.test.js b/test/multistream.test.js index 94ae848bf..7073148a2 100644 --- a/test/multistream.test.js +++ b/test/multistream.test.js @@ -481,7 +481,7 @@ test('no stream', function (t) { t.end() }) -test('add a stream', function (t) { +test('one stream', function (t) { let messageCount = 0 const stream = writeStream(function (data, enc, cb) { messageCount += 1 @@ -497,6 +497,43 @@ test('add a stream', function (t) { t.end() }) +test('add a stream', function (t) { + let messageCount = 0 + const stream = writeStream(function (data, enc, cb) { + messageCount += 1 + cb() + }) + + const log = pino({ + level: 'trace' + }, multistream().add(stream)) + log.info('info stream') + log.debug('debug stream') + log.fatal('fatal stream') + t.equal(messageCount, 2) + t.end() +}) + +test('multistream.add throws if not a stream', function (t) { + try { + pino({ + level: 'trace' + }, multistream().add({})) + } catch (_) { + t.end() + } +}) + +test('multistream throws if not a stream', function (t) { + try { + pino({ + level: 'trace' + }, multistream({})) + } catch (_) { + t.end() + } +}) + test('flushSync', function (t) { const tmp = join( os.tmpdir(), diff --git a/test/types/pino-multistream.test-d.ts b/test/types/pino-multistream.test-d.ts index cc2f6863c..6006f9c53 100644 --- a/test/types/pino-multistream.test-d.ts +++ b/test/types/pino-multistream.test-d.ts @@ -21,5 +21,6 @@ expectType(pino.multistream(streams)) expectType(pino.multistream(streams, {})) expectType(pino.multistream(streams, { levels: { 'info': 30 } })) expectType(pino.multistream(streams, { dedupe: true })) +expectType(pino.multistream(streams[0]).add(streams[1])) expectType(multistream(process.stdout));