pino
Extremely fast node.js logger, inspired by Bunyan.
It also includes a shell utility to pretty-print its log files.
Install
npm install pino --save
Usage
'use strict'
var pino = require('./')()
var info = pino.info
var error = pino.error
info('hello world')
error('this is at error level')
info('the answer is %d', 42)
info({ obj: 42 }, 'hello world')
info({ obj: 42, b: 2 }, 'hello world')
info({ obj: { aa: 'bbb' } }, 'another')
setImmediate(info, 'after setImmediate')
error(new Error('an error'))
This produces:
{"pid":13087,"hostname":"MacBook-Pro-3.home","level":30,"msg":"hello world","time":1457531561635,"v":0}
{"pid":13087,"hostname":"MacBook-Pro-3.home","level":50,"msg":"this is at error level","time":1457531561636,"v":0}
{"pid":13087,"hostname":"MacBook-Pro-3.home","level":30,"msg":"the answer is 42","time":1457531561637,"v":0}
{"pid":13087,"hostname":"MacBook-Pro-3.home","level":30,"msg":"hello world","time":1457531561637,"v":0,"obj":42}
{"pid":13087,"hostname":"MacBook-Pro-3.home","level":30,"msg":"hello world","time":1457531561638,"v":0,"obj":42,"b":2}
{"pid":13087,"hostname":"MacBook-Pro-3.home","level":30,"msg":"another","time":1457531561638,"v":0,"obj":{"aa":"bbb"}}
{"pid":13087,"hostname":"MacBook-Pro-3.home","level":50,"msg":"an error","time":1457531561639,"v":0,"type":"Error","stack":"Error: an error\n at Object.<anonymous> (/Users/davidclements/z/nearForm/pino/example.js:14:7)\n at Module._compile (module.js:413:34)\n at Object.Module._extensions..js (module.js:422:10)\n at Module.load (module.js:357:32)\n at Function.Module._load (module.js:314:12)\n at Function.Module.runMain (module.js:447:10)\n at startup (node.js:141:18)\n at node.js:933:3"}
{"pid":13087,"hostname":"MacBook-Pro-3.home","level":30,"msg":"after setImmediate","time":1457531561641,"v":0}
Benchmarks
As far as we know, it is the fastest logger in town:
benchBunyan*10000: 1093.236ms
benchWinston*10000: 1904.147ms
benchBole*10000: 1563.632ms
benchPino*10000: 287.858ms
benchBunyanObj*10000: 1187.016ms
benchWinstonObj*10000: 1990.980ms
benchPinoObj*10000: 366.865ms
benchBoleObj*10000: 1475.934ms
benchBunyan*10000: 1043.486ms
benchWinston*10000: 1801.232ms
benchBole*10000: 1524.136ms
benchPino*10000: 280.797ms
benchBunyanObj*10000: 1188.472ms
benchWinstonObj*10000: 1868.626ms
benchPinoObj*10000: 371.082ms
benchBoleObj*10000: 1496.449ms
## CLI
To use the command line tool, we can install pino
globally:
npm install -g pino
Then we simply pipe a log file through pino
:
cat log | pino
There's also a transformer flag that converts Epoch timestamps to ISO timestamps.
cat log | pino -t
For instance, pino -t
will transform this:
{"pid":14139,"hostname":"MacBook-Pro-3.home","level":30,"msg":"hello world","time":1457537229339,"v":0}
Into this:
{"pid":14139,"hostname":"MacBook-Pro-3.home","level":30,"msg":"hello world","time":"2016-03-09T15:27:09.339Z","v":0}
## API
pino([opts], [stream])
Returns a new logger. Allowed options are:
safe
: avoid error causes by circular references in the object tree,
default true
name
: the name of the logger, default undefined
serializers
: an object containing functions for custom serialization of objects. These functions should return an JSONifiable object and they should never throwslowtime
: Outputs ISO time stamps ('2016-03-09T15:18:53.889Z'
) instead of Epoch time stamps (1457536759176
). WARNING: This option carries a 25% performance drop, we recommend using default Epoch timestamps and transforming logs after if required. The pino -t
command will do this for you (see CLI)
stream
is a Writable stream, defaults to process.stdout
.
Example:
'use strict'
var pino = require('pino')
var instance = pino({
name: 'myapp',
safe: true,
serializers: {
req: pino.stdSerializers.req
res: pino.stdSerializers.res
}
}
logger.level
Set this property to the desired logging level.
In order of priority, available levels are:
'fatal'
'error'
'warn'
'info'
'debug'
'trace'
Example: logger.level = 'info'
The logging level is a minimum level. For instance if logger.level
is 'info'
then all fatal
, error
, warn
, and info
logs will be enabled.
logger.fatal([obj], msg, [...])
Log at 'fatal'
level the given msg
. If the first argument is an
object, all its properties will be included in the JSON line.
If more args follows msg
, these will be used to format msg
using
util.format
logger.error([obj], msg, [...])
Log at 'error'
level the given msg
. If the first argument is an
object, all its properties will be included in the JSON line.
If more args follows msg
, these will be used to format msg
using
util.format
logger.warn([obj], msg, [...])
Log at 'warn'
level the given msg
. If the first argument is an
object, all its properties will be included in the JSON line.
If more args follows msg
, these will be used to format msg
using
util.format
logger.info([obj], msg, [...])
Log at 'info'
level the given msg
. If the first argument is an
object, all its properties will be included in the JSON line.
If more args follows msg
, these will be used to format msg
using
util.format
logger.debug([obj], msg, [...])
Log at 'debug'
level the given msg
. If the first argument is an
object, all its properties will be included in the JSON line.
If more args follows msg
, these will be used to format msg
using
util.format
logger.trace([obj], msg, [...])
Log at 'trace'
level the given msg
. If the first argument is an
object, all its properties will be included in the JSON line.
If more args follows msg
, these will be used to format msg
using
util.format
pino.stdSerializers.req
Function to generate a JSONifiable object out of an HTTP request from
node HTTP server.
It returns an object in the form:
{
pid: 93535,
hostname: 'your host',
level: 30,
msg: 'my request',
time: '2016-03-07T12:21:48.766Z',
v: 0,
req: {
method: 'GET',
url: '/',
headers: {
host: 'localhost:50201',
connection: 'close'
},
remoteAddress: '::ffff:127.0.0.1',
remotePort: 50202
}
}
pino.stdSerializers.res
Function to generate a JSONifiable object out of an HTTP
response from
node HTTP server.
It returns an object in the form:
{
pid: 93581,
hostname: 'myhost',
level: 30,
msg: 'my response',
time: '2016-03-07T12:23:18.041Z',
v: 0,
res: {
statusCode: 200,
header: 'HTTP/1.1 200 OK\r\nDate: Mon, 07 Mar 2016 12:23:18 GMT\r\nConnection: close\r\nContent-Length: 5\r\n\r\n'
}
}
How do I rotate log files
You should configure
logrotate to rotate your log
files, and just redirect the standard output of your application to a
file, like so:
node server.js > /var/log/myapp.log
In order to rotate your log files, add in /etc/logrotate.d/myapp
:
/var/log/myapp.log {
su root
daily
rotate 7
delaycompress
compress
notifempty
missingok
copytruncate
}
How to use Transports with Pino
Transports are not part of Pino. There will never be an API for transports,
or support for ObjectMode Writable streams.
This library is fast because it does way less than the others. We went
to great lengths to make sure this library is really fast, and transports
will slow things down.
So, how do you do a transport? With Pino, we create a separate process for our transport and pipe to it.
It's the Unix philosophy.
Something like:
var split = require('split2')
var pump = require('pump')
var through = require('through2')
var myTransport = through.obj(function (chunk, enc, cb) {
console.log(chunk)
cb()
}
pump(process.stdin, split2(JSON.parse), myTransport)
Using transports in the same process causes unnecessary load and slows down Node's single threaded event loop.
If you write a transport, let us know and we will add a link here!
Acknowledgements
This project was kindly sponsored by nearForm.
License
MIT