pino-multi-stream
pino-multi-stream is a wrapper around the pino logger. The purpose
of pino-multi-stream is to provide a stop-gap method for migrating from the
Bunyan logger. Whereas pino allows only one destination stream,
pino-multi-stream allows multiple destination streams via the same
configuration API as Bunyan.
Please see the caveats section for some important information
regarding the performance of this module.
Install
For Pino v5+
npm install -s pino-multi-stream
For Pino v4 and below:
npm install -s pino-multi-stream@legacy #v3 pino-multi-stream line
pino-multi-stream does not provide the CLI that pino provides. Therefore,
you should not install it globally.
Usage
var fs = require('fs')
var pinoms = require('pino-multi-stream')
var streams = [
{stream: fs.createWriteStream('/tmp/info.stream.out')},
{level: 'fatal', stream: fs.createWriteStream('/tmp/fatal.stream.out')}
]
var log = pinoms({streams: streams})
log.info('this will be written to /tmp/info.stream.out')
log.fatal('this will be written to /tmp/fatal.stream.out')
API
The API for pino-multi-stream is the same as that for pino. Please
read pino's documentation for full details. Highlighted here are
the specifics for pino-multi-stream:
-
The signature for constructor remains the same, pino(opts, stream)
, but
there are a few conditions under which you may get a real pino instance
or one wrapped by pino-multi-stream:
- If the
opts
parameter is a writable stream, then a real pino
instance will be returned.
- If the
opts
parameter is an object with a singular stream
property
then a real pino instance will be returned. If there is also a plural
streams
property, the singular stream
property takes precedence. - If the
opts
parameter is an object with a plural streams
property,
does not include a singluar stream
property, and is an array, then
a pino-multi-stream wrapped instance will be returned. Otherwise,
opts.streams
is treated a single stream and a real pino instance
will be returned.
-
The pino options object accepts a streams
option, as alluded to in then
previous item. This option should be an array of stream objects. A stream
object is one with at least a stream
property and, optionally, a level
property. For example:
var logger = pinoms({
streams: [
{stream: process.stdout},
{level: 'error', stream: process.stderr}
]
})
pinoms.multistream(streams, opts)
Manually create a single multistream
as used internally by the
wrapper:
var fs = require('fs')
var pino = require('pino')
var multistream = require('pino-multi-stream').multistream
var streams = [
{stream: fs.createWriteStream('/tmp/info.stream.out')},
{level: 'debug', stream: fs.createWriteStream('/tmp/debug.stream.out')},
{level: 'fatal', stream: fs.createWriteStream('/tmp/fatal.stream.out')}
]
var log = pino({
level: 'debug'
}, multistream(streams))
log.debug('this will be written to /tmp/debug.stream.out')
log.info('this will be written to /tmp/debug.stream.out and /tmp/info.stream.out')
log.fatal('this will be written to /tmp/debug.stream.out, /tmp/info.stream.out and /tmp/fatal.stream.out')
opts
multistream options object. Available options are:
levels
: Pass custom log level definitions to the instance as an object.
-
dedupe
: Set this to true
to send logs only to the stream with the higher level. Default: false
dedupe
flag can be useful for example when using pino-multi-stream to redirect error
logs to process.stderr
and others to process.stdout
:
var pino = require('pino')
var multistream = require('pino-multi-stream').multistream
var streams = [
{stream: process.stdout},
{level: 'error', stream: process.stderr},
]
var opts = {
levels: {
silent: Infinity,
fatal: 60,
error: 50,
warn: 50,
info: 30,
debug: 20,
trace: 10
},
dedupe: true,
}
var log = pino({
level: 'debug'
}, multistream(streams, opts))
log.debug('this will be written ONLY to process.stdout')
log.info('this will be written ONLY to process.stdout')
log.error('this will be written ONLY to process.stderr')
log.fatal('this will be written ONLY to process.stderr')
pinoms.level set accessor
You can set the level to all streams by changing the level property.
It accepts the same parameters as pino. If the level is changed on a
child logger, it does not alter the parent streams level. As this is
costly operation, we recommend not changing the level for each child
logger that is being created.
pinoms.level get accessor
The behavior of the get accessor changes if { bunyan: true }
is passed
to pinoms. In that case, it implements the
bunyan.level
function.
pinoms.prettyStream({ [prettyPrint], [prettifier], [dest] })
Note: after 4.1.0 this pino-multi-stream
function was changed according to that of pino
, and after 4.2.0 its API (names of parameters and their options) are in conformity with API of pino
/pino-pretty
, as it is presented here. Those changes are related to pretty-printing options only.
Manually create an output stream with a prettifier applied.
var fs = require('fs');
var pinoms = require('pino-multi-stream')
var prettyStream = pinoms.prettyStream()
var streams = [
{stream: fs.createWriteStream('my.log') },
{stream: prettyStream }
]
var logger = pinoms(pinoms.multistream(streams))
logger.info("HELLO %s!", "World")
The options object may additionally contain a prettifier
property to define which prettifier module to use. When not present, prettifier
defaults to pino-pretty
⇗ (must be installed as a separate dependency).
The method may be passed an alternative write destination, but defaults to process.stdout
.
Prettifying options (after 4.2.0) are to be set like this:
const prettyStream = pinoms.prettyStream(
{
prettyPrint:
{ colorize: true,
translateTime: "SYS:standard",
ignore: "hostname,pid"
},
prettifier: require('pino-pretty')
}
);
Caveats
Stern warning: the performance of this module being dependent on the number
of streams you supply cannot be overstated. This module is being provided so
that you can switch to pino from Bunyan and get some immediate improvement,
but it is not meant to be a long term solution. We strongly suggest that you
use this module for only as long as it will take you to overhaul the way
you handle logging in your application. pino-multi-stream
offers close
to zero overhead if there is only one destination stream.
To illustrate what we mean, here is a benchmark of pino and Bunyan using
"multiple" streams to write to a single stream:
benchBunyanOne*10000: 703.071ms
benchPinoMSOne*10000: 287.060ms
Now let's look at the same benchmark but increase the number of destination
streams to four:
benchBunyanFour*10000: 2249.955ms
benchPinoMSFour*10000: 1017.886ms
And, finally, with ten destination streams:
benchBunyanTen*10000: 4950.301ms
benchPinoMSTen*10000: 3127.361ms
License
MIT License