Socket
Socket
Sign inDemoInstall

pino

Package Overview
Dependencies
Maintainers
4
Versions
310
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

pino - npm Package Compare versions

Comparing version 2.15.0 to 2.16.0

docs/API.md

54

package.json
{
"name": "pino",
"version": "2.15.0",
"version": "2.16.0",
"description": "super fast, all natural json logger",

@@ -10,6 +10,24 @@ "main": "pino.js",

},
"files": [
"pino.js",
"browser.js",
"pretty.js",
"usage.txt",
"test",
"docs",
"example.js"
],
"scripts": {
"browser-test": "zuul tape test/browser.test.js --local",
"test": "standard && tap --no-cov test/*test.js",
"ci": "standard && tap --cov test/*test.js"
"ci": "standard && tap --cov test/*test.js",
"bench-all": "node benchmarks/runbench all",
"bench-basic": "node benchmarks/runbench basic",
"bench-object": "node benchmarks/runbench object",
"bench-deepobject": "node benchmarks/runbench deepobject",
"bench-multiarg": "node benchmarks/runbench multiarg",
"bench-longstring": "node benchmarks/runbench longstring",
"bench-child": "node benchmarks/runbench child",
"bench-grandchild": "node benchmarks/runbench grandchild",
"bench-conception": "node benchmarks/runbench conception"
},

@@ -28,2 +46,6 @@ "precommit": "test",

"author": "Matteo Collina <hello@matteocollina.com>",
"contributors": [
"David Mark Clements <huperekchuno@googlemail.com>",
"James Sumners <james.sumners@gmail.com>"
],
"license": "MIT",

@@ -35,16 +57,19 @@ "bugs": {

"devDependencies": {
"benchmark": "^2.1.0",
"bole": "^3.0.0",
"bunyan": "^1.6.0",
"debug": "^2.2.0",
"benchmark": "^2.1.2",
"bole": "^3.0.2",
"bunyan": "^1.8.5",
"debug": "^2.5.1",
"fastbench": "^1.0.0",
"flush-write-stream": "^1.0.0",
"flush-write-stream": "^1.0.2",
"fresh-require": "^1.0.3",
"log": "^1.4.0",
"loglevel": "^1.4.0",
"pre-commit": "^1.1.2",
"standard": "^8.0.0",
"tap": "^7.0.0",
"pre-commit": "^1.2.2",
"pump": "^1.0.1",
"standard": "^8.6.0",
"steed": "^1.1.3",
"tap": "^8.0.0",
"tape": "^4.6.2",
"winston": "^2.1.1",
"through2": "^2.0.1",
"winston": "^2.3.0",
"zuul": "^3.11.1"

@@ -54,11 +79,10 @@ },

"chalk": "^1.1.1",
"core-util-is": "^1.0.2",
"fast-json-parse": "^1.0.0",
"fast-safe-stringify": "^1.1.0",
"flatstr": "^1.0.0",
"fast-safe-stringify": "^1.1.3",
"flatstr": "^1.0.4",
"object.assign": "^4.0.4",
"once": "^1.3.3",
"quick-format": "^2.0.4",
"quick-format-unescaped": "^1.0.0",
"split2": "^2.0.1"
}
}
'use strict'
var stringifySafe = require('fast-safe-stringify')
var format = require('quick-format')
var format = require('quick-format-unescaped')
var EventEmitter = require('events').EventEmitter
var os = require('os')
var fs = require('fs')
var flatstr = require('flatstr')
var once = require('once')
var util = require('util')
var pid = process.pid

@@ -16,2 +18,13 @@ var hostname = os.hostname()

var defaultOptions = {
safe: true,
name: undefined,
serializers: {},
timestamp: true,
slowtime: false,
extreme: false,
level: 'info',
enabled: true
}
var levels = {

@@ -26,8 +39,2 @@ fatal: 60,

// private property
Object.defineProperty(levels, 'silent', {
value: 100,
enumerable: false
})
var nums = Object.keys(levels).reduce(function (o, k) {

@@ -44,8 +51,2 @@ o[levels[k]] = k

// private property
Object.defineProperty(nums, '100', {
value: 'silent',
enumerable: false
})
function streamIsBlockable (s) {

@@ -58,28 +59,27 @@ if (s.hasOwnProperty('_handle') && s._handle.hasOwnProperty('fd') && s._handle.fd) return true

function pino (opts, stream) {
if (opts && (opts.writable || opts._writableState)) {
stream = opts
opts = null
var iopts = opts
var istream = stream
if (iopts && (iopts.writable || iopts._writableState)) {
istream = iopts
iopts = defaultOptions
}
stream = stream || process.stdout
opts = opts || {}
var timestamp = (opts.hasOwnProperty('timestamp')) ? opts.timestamp : true
var slowtime = opts.slowtime
var safe = opts.safe !== false
var stringify = safe ? stringifySafe : JSON.stringify
var formatOpts = safe ? null : {lowres: true}
var name = opts.name
var level = opts.level || 'info'
var serializers = opts.serializers || {}
var end = ',"v":' + LOG_VERSION + '}\n'
var cache = !opts.extreme ? null : {
istream = istream || process.stdout
iopts = extend({}, defaultOptions, iopts)
// internal options
iopts.stringify = iopts.safe ? stringifySafe : JSON.stringify
iopts.formatOpts = {lowres: true}
iopts.end = ',"v":' + LOG_VERSION + '}\n'
iopts.cache = !iopts.extreme ? null : {
size: 4096,
buf: ''
}
iopts.chindings = ''
if (opts.enabled === false) {
level = 'silent'
if (iopts.enabled === false) {
iopts.level = 'silent'
}
var logger = new Pino(level, stream, serializers, stringify, end, name, timestamp, slowtime, '', cache, formatOpts)
if (cache) {
var logger = new Pino(iopts, istream)
if (iopts.cache) {
// setImmediate is causing a very weird crash:

@@ -89,3 +89,3 @@ // Assertion failed: (cb_v->IsFunction()), function MakeCallback...

setTimeout(function () {
if (!streamIsBlockable(stream)) {
if (!streamIsBlockable(istream)) {
logger.emit('error', new Error('stream must have a file descriptor in extreme mode'))

@@ -96,8 +96,9 @@ }

onExit(function (code, evt) {
if (cache.buf) {
var buf = iopts.cache.buf
if (buf) {
// We need to block the process exit long enough to flush the buffer
// to the destination stream. We do that by forcing a synchronous
// write directly to the stream's file descriptor.
var fd = (stream.fd) ? stream.fd : stream._handle.fd
require('fs').writeSync(fd, cache.buf)
var fd = (istream.fd) ? istream.fd : istream._handle.fd
fs.writeSync(fd, buf)
}

@@ -124,22 +125,33 @@ if (!process._events[evt] || process._events[evt].length < 2 || !process._events[evt].filter(function (f) {

})
Object.defineProperty(pino.levels.values, 'silent', {value: 100})
Object.defineProperty(pino.levels.labels, '100', {value: 'silent'})
function Pino (level, stream, serializers, stringify, end, name, timestamp, slowtime, chindings, cache, formatOpts) {
pino.addLevel = function addLevel (name, lvl) {
if (pino.levels.values.hasOwnProperty(name)) return false
if (pino.levels.labels.hasOwnProperty(lvl)) return false
pino.levels.values[name] = lvl
pino.levels.labels[lvl] = name
lscache[lvl] = flatstr('"level":' + Number(lvl))
Pino.prototype[name] = genLog(lvl)
return true
}
function Pino (opts, stream) {
this.stream = stream
this.serializers = serializers
this.stringify = stringify
this.end = end
this.name = name
this.timestamp = timestamp
this.slowtime = slowtime
this.chindings = chindings
this.cache = cache
this.formatOpts = formatOpts
this._setLevel(level)
this.serializers = opts.serializers
this.stringify = opts.stringify
this.end = opts.end
this.name = opts.name
this.timestamp = opts.timestamp
this.slowtime = opts.slowtime
this.chindings = opts.chindings
this.cache = opts.cache
this.formatOpts = opts.formatOpts
this._setLevel(opts.level)
this._baseLog = flatstr(baseLog +
(this.name === undefined ? '' : '"name":' + stringify(this.name) + ','))
(this.name === undefined ? '' : '"name":' + this.stringify(this.name) + ','))
if (timestamp === false) {
if (opts.timestamp === false) {
this.time = getNoTime
} else if (slowtime) {
} else if (opts.slowtime) {
this.time = getSlowTime

@@ -170,3 +182,3 @@ } else {

if (this.emit) {
this.emit('level-change', nums[num], num, nums[this._levelVal], this._levelVal)
this.emit('level-change', pino.levels.labels[num], num, pino.levels.labels[this._levelVal], this._levelVal)
}

@@ -176,4 +188,4 @@

for (var key in levels) {
if (num > levels[key]) {
for (var key in pino.levels.values) {
if (num > pino.levels.values[key]) {
this[key] = noop

@@ -188,12 +200,12 @@ continue

Pino.prototype._setLevel = function _setLevel (level) {
if (typeof level === 'number') { level = nums[level] }
if (typeof level === 'number') { level = pino.levels.labels[level] }
if (!levels[level]) {
if (!pino.levels.values[level]) {
throw new Error('unknown level ' + level)
}
this.levelVal = levels[level]
this.levelVal = pino.levels.values[level]
}
Pino.prototype._getLevel = function _getLevel (level) {
return nums[this.levelVal]
return pino.levels.labels[this.levelVal]
}

@@ -212,28 +224,2 @@

// magically escape strings for json
// relying on their charCodeAt
// everything below 32 needs JSON.stringify()
// 34 and 92 happens all the time, so we
// have a fast case for them
function escape (s) {
var str = s.toString()
var result = ''
var last = 0
var l = str.length
var point = 255
for (var i = 0; i < l && point >= 32; i++) {
point = str.charCodeAt(i)
if (point === 34 || point === 92) {
result += str.slice(last, i) + '\\' + str[i]
last = i + 1
}
}
if (last === 0) {
result = str
} else {
result += str.slice(last)
}
return point < 32 ? JSON.stringify(str) : '"' + result + '"'
}
Pino.prototype.asJson = function asJson (obj, msg, num) {

@@ -247,3 +233,3 @@ if (!msg && obj instanceof Error) {

if (msg != undefined) {
data += ',"msg":' + escape(msg)
data += ',"msg":' + JSON.stringify(msg)
}

@@ -254,10 +240,9 @@ var value

data += ',"type":"Error","stack":' + this.stringify(obj.stack)
} else {
for (var key in obj) {
value = obj[key]
if (obj.hasOwnProperty(key) && value !== undefined) {
value = this.stringify(this.serializers[key] ? this.serializers[key](value) : value)
if (value !== undefined) {
data += ',"' + key + '":' + value
}
}
for (var key in obj) {
value = obj[key]
if (obj.hasOwnProperty(key) && value !== undefined) {
value = this.stringify(this.serializers[key] ? this.serializers[key](value) : value)
if (value !== undefined) {
data += ',"' + key + '":' + value
}

@@ -299,14 +284,16 @@ }

return new Pino(
bindings.level || this.level,
this.stream,
bindings.hasOwnProperty('serializers') ? extend(this.serializers, bindings.serializers) : this.serializers,
this.stringify,
this.end,
this.name,
this.timestamp,
this.slowtime,
data,
this.cache,
this.formatOpts)
var opts = {
level: bindings.level || this.level,
serializers: bindings.hasOwnProperty('serializers') ? extend(this.serializers, bindings.serializers) : this.serializers,
stringify: this.stringify,
end: this.end,
name: this.name,
timestamp: this.timestamp,
slowtime: this.slowtime,
chindings: data,
cache: this.cache,
formatOpts: this.formatOpts
}
return new Pino(opts, this.stream)
}

@@ -367,3 +354,3 @@

function asErrValue (err) {
return {
var obj = {
type: err.constructor.name,

@@ -373,4 +360,23 @@ message: err.message,

}
for (var key in err) {
if (obj[key] === undefined) {
obj[key] = err[key]
}
}
return obj
}
function countInterp (s, i) {
var n = 0
var pos = 0
while (true) {
pos = s.indexOf(i, pos)
if (pos >= 0) {
++n
pos += 2
} else break
}
return n
}
function genLog (z) {

@@ -398,3 +404,9 @@ return function LOG (a, b, c, d, e, f, g, h, i, j, k) {

if (p > 1) {
o = format(n, this.formatOpts)
l = typeof a === 'string' ? countInterp(a, '%j') : 0
if (l) {
n.length = l + countInterp(a, '%d') + countInterp(a, '%s') + 1
o = String(util.format.apply(null, n))
} else {
o = format(n, this.formatOpts)
}
} else if (p) {

@@ -401,0 +413,0 @@ o = n[0]

@@ -50,3 +50,6 @@ #! /usr/bin/env node

function isPinoLine (line) {
return line.hasOwnProperty('hostname') && line.hasOwnProperty('pid') && (line.hasOwnProperty('v') && line.v === 1)
return line &&
line.hasOwnProperty('hostname') &&
line.hasOwnProperty('pid') &&
(line.hasOwnProperty('v') && line.v === 1)
}

@@ -53,0 +56,0 @@

@@ -13,14 +13,10 @@ ![banner](pino-banner.png)

* [Benchmarks](#benchmarks)
* [API](#api)
* [Extreme mode explained](#extreme)
* [How to use Pino with Express](#express)
* [How to use Pino with Hapi](#hapi)
* [How to use Pino with Restify](#restify)
* [How to use Pino with Koa](#koa)
* [How do I rotate log files?](#rotate)
* [How do I redact sensitive information?](#redact)
* [How to use Transports with Pino](#transports)
* [API](docs/API.md)
* [Extreme mode explained](docs/extreme.md)
* [Pino Howtos](docs/howtos.md)
* [Transports with Pino](docs/transports.md)
* [Pino in the browser](#browser)
* [Caveats](#caveats)
* [Team](#team)
* [Contributing](#contributing)
* [Acknowledgements](#acknowledgements)

@@ -79,3 +75,2 @@ * [License](#license)

## Benchmarks
As far as we know, it is one of the fastest loggers in town:

@@ -141,814 +136,9 @@

<a name="cli"></a>
## CLI
To use the command line tool, we can install `pino` globally:
```sh
npm install -g pino
```
Then we simply pipe a log file through `pino`:
```sh
cat log | pino
```
There are also two transformer flags..
`-t` that converts Epoch timestamps to ISO timestamps.
```sh
cat log | pino -t
```
and `-l` that flips the time and level on the standard output.
```sh
cat log | pino -l
```
`pino -t` will transform this:
```js
{"pid":14139,"hostname":"MacBook-Pro-3.home","level":30,"msg":"hello world","time":1457537229339,"v":0}
```
Into this:
```js
{"pid":14139,"hostname":"MacBook-Pro-3.home","level":30,"msg":"hello world","time":"2016-03-09T15:27:09.339Z","v":0}
```
`pino -l` will transform this:
```sh
[2016-03-09T15:27:09.339Z] INFO (14139 on MacBook-Pro-3.home): hello world
```
Into this:
```sh
INFO [2016-03-09T15:27:09.339Z] (14139 on MacBook-Pro-3.home): hello world
```
<a name="api"></a>
## API
* <a href="#constructor"><code><b>pino()</b></code></a>
* <a href="#child"><code>logger.<b>child()</b></code></a>
* <a href="#level"><code>logger.<b>level</b></code></a>
* <a href="#fatal"><code>logger.<b>fatal()</b></code></a>
* <a href="#error"><code>logger.<b>error()</b></code></a>
* <a href="#warn"><code>logger.<b>warn()</b></code></a>
* <a href="#info"><code>logger.<b>info()</b></code></a>
* <a href="#debug"><code>logger.<b>debug()</b></code></a>
* <a href="#trace"><code>logger.<b>trace()</b></code></a>
* <a href="#flush"><code>logger.<b>flush()</b></code></a>
* <a href="#levelVal"><code>logger.<b>levelVal</b></code></a>
* <a href="#level-change"><code>logger.on(<b>'level-change'</b>, fn)</code></a>
* <a href="#levelValues"><code>logger.levels.<b>values</b></code> & <code>pino.levels.<b>values</b></code></a>
* <a href="#levelLabels"><code>logger.levels.<b>labels</b></code> & <code>pino.levels.<b>labels</b></code></a>
* <a href="#log_version"><code>pino.<b>LOG_VERSION</b></code> & <code>logger.<b>LOG_VERSION</b></code></a>
* <a href="#reqSerializer"><code>pino.stdSerializers.<b>req</b></code></a>
* <a href="#resSerializer"><code>pino.stdSerializers.<b>res</b></code></a>
* <a href="#errSerializer"><code>pino.stdSerializers.<b>err</b></code></a>
* <a href="#pretty"><code>pino.<b>pretty()</b></code></a>
<a name="constructor"></a>
### 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 throw
* `timestamp`: Enables or disables the inclusion of a timestamp in the log message. `slowtime` has no effect if this option is set to `false`. Defaults to `true`.
* `slowtime`: 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](#cli)). default `false`.
* `extreme`: Enables extreme mode, yields an additional 60% performance (from 250ms down to 100ms per 10000 ops). There are trade-off's should be understood before usage. See [Extreme mode explained](#extreme). default `false`
* `level`: one of `'fatal'`, `'error'`, `'warn'`, `'info`', `'debug'`, `'trace'`; also `'silent'` is supported to disable logging.
* `enabled`: enables logging, defaults to `true`.
`stream` is a Writable stream, defaults to `process.stdout`.
Example:
```js
'use strict'
var pino = require('pino')
var logger = pino({
name: 'myapp',
safe: true,
serializers: {
req: pino.stdSerializers.req,
res: pino.stdSerializers.res
}
})
```
<a name="child"></a>
### logger.child(bindings)
Creates a child logger, setting all key-value pairs in `bindings` as
properties in the log lines. All serializers will be applied to the
given pair.
Example:
```js
logger.child({ a: 'property' }).info('hello child!')
// generates
// {"pid":46497,"hostname":"MacBook-Pro-di-Matteo.local","level":30,"msg":"hello child!","time":1458124707120,"v":0,"a":"property"}
```
Child loggers use the same output stream as the parent and inherit
the current log level of the parent at the time they are spawned.
From v2.x.x the log level of a child is mutable (whereas in
v1.x.x it was immutable), and can be set independently of the parent.
If a `level` property is present in the object passed to `child` it will
override the child logger level.
For example
```
var logger = pino()
logger.level = 'error'
logger.info('nope') //does not log
var child = logger.child({foo: 'bar'})
child.info('nope again') //does not log
child.level = 'info'
child.info('hooray') //will log
logger.info('nope nope nope') //will not log, level is still set to error
logger.child({ foo: 'bar', level: 'debug' }).debug('debug!')
```
Child loggers inherit the serializers from the parent logger but it is
possible to override them.
For example
```
var pino = require('./pino')
var customSerializers = {
test: function () {
return 'this is my serializer'
}
}
var child = pino().child({serializers: customSerializers})
child.info({test: 'should not show up'})
```
Will produce the following output:
```
{"pid":7971,"hostname":"mycomputer.local","level":30,"time":1469488147985,"test":"this is my serializer","v":1}
```
Also from version 2.x.x we can spawn child loggers from child loggers, for instance
```
var logger = pino()
var child = logger.child({father: true})
var childChild = child.child({baby: true})
```
Child logger creation is fast:
```
benchBunyanCreation*10000: 1291.332ms
benchBoleCreation*10000: 1630.542ms
benchPinoCreation*10000: 352.330ms
benchPinoExtremeCreation*10000: 102.282ms
```
Logging through a child logger has little performance penalty:
```
benchBunyanChild*10000: 1343.933ms
benchBoleChild*10000: 1605.969ms
benchPinoChild*10000: 334.573ms
benchPinoExtremeChild*10000: 152.792ms
```
Spawning children from children has negligible overhead:
```
benchBunyanChildChild*10000: 1397.202ms
benchPinoChildChild*10000: 338.930ms
benchPinoExtremeChildChild*10000: 150.143ms
```
<a name="level"></a>
### logger.level
Set this property to the desired logging level.
In order of priority, available levels are:
1. <a href="#fatal">`'fatal'`</a>
2. <a href="#error">`'error'`</a>
3. <a href="#warn">`'warn'`</a>
4. <a href="#info">`'info'`</a>
5. <a href="#debug">`'debug'`</a>
6. <a href="#trace">`'trace'`</a>
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.
You can pass `'silent'` to disable logging.
<a name="fatal"></a>
### 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`](https://nodejs.org/api/util.html#util_util_format_format)
<a name="error"></a>
### 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`](https://nodejs.org/api/util.html#util_util_format_format)
<a name="warn"></a>
### 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`](https://nodejs.org/api/util.html#util_util_format_format)
<a name="info"></a>
### 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`](https://nodejs.org/api/util.html#util_util_format_format)
<a name="debug"></a>
### 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`](https://nodejs.org/api/util.html#util_util_format_format)
<a name="trace"></a>
### 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`](https://nodejs.org/api/util.html#util_util_format_format)
<a name="flush"></a>
### logger.flush()
Flushes the content of the buffer in [extreme mode](#extreme). It has no effect if
extreme mode is not enabled.
<a name="levelVal"></a>
### logger.levelVal
Returns the integer value for the logger instance's logging level.
<a name="level-change"></a>
### logger.on('level-change', fn)
Registers a listener function that is triggered when the level is changed.
The listener is passed four arguments: `levelLabel`, `levelValue`, `previousLevelLabel`, `previousLevelValue`.
**Note:** When browserified, this functionality will only be available if the `events` module has been required else where (e.g. if you're using streams in the browser). This allows for a trade-off between bundle size and functionality.
```js
var listener = function (lvl, val, prevLvl, prevVal) {
console.log(lvl, val, prevLvl, prevVal)
}
logger.on('level-change', listener)
logger.level = 'trace' // trigger console message
logger.removeListener('level-change', listener)
logger.level = 'info' // no message, since listener was removed
```
<a name="levelValues"></a>
### logger.levels.values & pino.levels.values
Returns the mappings of level names to their respective internal number
representation. For example:
```js
pino.levels.values.error === 50 // true
```
<a name="levelLabels"></a>
### logger.levels.labels & pino.levels.labels
Returns the mappings of level internal level numbers to their string
representations. For example:
```js
pino.levels.labels[50] === 'error' // true
```
<a name="log_version"></a>
### logger.LOG_VERSION & pino.LOG_VERSION
Read only. Holds the current log format version (as output in the `v` property of each log record).
<a name="reqSerializer"></a>
### pino.stdSerializers.req
Generates a JSONifiable object from the HTTP `request` object passed to
the `createServer` callback of Node's HTTP server.
It returns an object in the form:
```js
{
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
}
}
```
<a name="resSerializer"></a>
### pino.stdSerializers.res
Generates a JSONifiable object from the HTTP `response` object passed to
the `createServer` callback of Node's HTTP server.
It returns an object in the form:
```js
{
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'
}
}
```
<a name="errSerializer"></a>
### pino.stdSerializers.err
Serializes an `Error` object if passed in as an property.
```js
{
"pid": 40510,
"hostname": "MBP-di-Matteo",
"level": 50,
"msg": "an error",
"time": 1459433282301,
"v": 1,
"type": "Error",
"stack": "Error: an error\n at Object.<anonymous> (/Users/matteo/Repositories/pino/example.js:16:7)\n at Module._compile (module.js:435:26)\n at Object.Module._extensions..js (module.js:442:10)\n at Module.load (module.js:356:32)\n at Function.Module._load (module.js:313:12)\n at Function.Module.runMain (module.js:467:10)\n at startup (node.js:136:18)\n at node.js:963:3"
}
```
<a name="pretty"></a>
### pino.pretty([opts])
Returns a transform stream that formats JSON output into pretty print
output as per the [cli](#cli) tool.
Options:
* `timeTransOnly`, if set to `true`, it will only covert the unix timestamp to
ISO 8601 date format, and reserialize the JSON (equivalent to `pino -t`).
* `formatter`, a custom function to format the line, is passed the JSON
object as an argument and should return a string value
You can use the pretty transformer internally, like so:
```js
'use strict'
var pino = require('pino')
var pretty = pino.pretty()
pretty.pipe(process.stdout)
var log = pino({
name: 'app',
safe: true
}, pretty)
log.child({ widget: 'foo' }).info('hello')
log.child({ widget: 'bar' }).warn('hello 2')
```
<a name="extreme"></a>
## Extreme mode explained
In essence, Extreme mode enables extreme performance by buffering log messages and writing them in larger chunks.
This has a couple of important caveats:
* 4KB of spare RAM will be needed for logging
* As opposed to the default mode, there is not a one-to-one relationship between calls to logging methods (e.g. `logger.info`) and writes to a log file (or log stream)
* There is a possibility of the most recently buffered log messages being lost (up to 4KB of logs)
* For instance, a powercut will mean up to 4KB of buffered logs will be lost
* A sigkill (or other untrappable signal) will probably result in the same
* If writing to a stream other than `process.stdout` or `process.stderr`, there is a slight possibility of lost logs or even partially written logs if the OS buffers don't have enough space, or something else is being written to the stream (or maybe some other reason we've not thought of)
* If you supply an alternate stream to the constructor, then that stream must support synchronous writes so that it can be properly flushed on exit. This means the stream must expose its file descriptor via `stream.fd` or `stream._handle.fd`. Usually they have to be native (from core) stream, meaning a TCP/unix socket, a file, or stdout/sderr. If your stream is invalid an `error` event will be emitted on the returned logger, e.g.:
```js
var stream = require('stream')
var pino = require('pino')
var logger = pino({extreme: true}, new stream.Writable({write: function (chunk) {
// do something with chunk
}}))
logger.on('error', function (err) {
console.error('pino logger cannot flush on exit due to provided output stream')
process.exit(1)
})
```
So in summary, only use extreme mode if you're doing an extreme amount of logging, and you're happy in some scenarios to lose the most recent logs.
<a name="express"></a>
## How to use Pino with Express
We've got you covered:
```sh
npm install --save express-pino-logger
```
```js
var app = require('express')()
var pino = require('express-pino-logger')()
app.use(pino)
app.get('/', function (req, res) {
req.log.info('something')
res.send('hello world')
})
app.listen(3000)
```
See the [express-pino-logger readme](http://npm.im/express-pino-logger) for more info.
<a name="hapi"></a>
## How to use Pino with Hapi
We've got you covered:
```sh
npm install --save hapi-pino
```
```js
'use strict'
const Hapi = require('hapi')
const server = new Hapi.Server()
server.connection({ port: 3000 })
server.route({
method: 'GET',
path: '/',
handler: function (request, reply) {
request.logger.info('In handler %s', request.path)
return reply('hello world')
}
})
server.register(require('hapi-pino'), (err) => {
if (err) {
console.error(err)
process.exit(1)
}
server.logger().info('another way for accessing it')
// Start the server
server.start((err) => {
if (err) {
console.error(err)
process.exit(1)
}
})
})
```
See the [hapi-pino readme](http://npm.im/hapi-pino) for more info.
<a name="restify"></a>
## How to use Pino with Restify
We've got you covered:
```sh
npm install --save restify-pino-logger
```
```js
var server = require('restify').createServer({name: 'server'})
var pino = require('restify-pino-logger')()
server.use(pino)
server.get('/', function (req, res) {
req.log.info('something')
res.send('hello world')
})
server.listen(3000)
```
See the [restify-pino-logger readme](http://npm.im/restify-pino-logger) for more info.
<a name="koa"></a>
## How to use Pino with koa
We've got you covered:
### Koa v1
```sh
npm install --save koa-pino-logger@1
```
```js
var app = require('koa')()
var pino = require('koa-pino-logger')()
app.use(pino)
app.use(function * () {
this.log.info('something else')
this.body = 'hello world'
})
app.listen(3000)
```
See the [koa-pino-logger v1 readme](https://github.com/pinojs/koa-pino-logger/tree/v1) for more info.
### Koa v2
```sh
npm install --save koa-pino-logger@2
```
```js
var Koa = require('koa')
var app = new Koa()
var pino = require('koa-pino-logger')()
app.use(pino)
app.use((ctx) => {
ctx.log.info('something else')
ctx.body = 'hello world'
})
app.listen(3000)
```
See the [koa-pino-logger v2 readme](https://github.com/pinojs/koa-pino-logger/tree/v2) for more info.
<a name="rotate"></a>
## How do I rotate log files?
Use a separate tool for log rotation.
We recommend [logrotate](https://github.com/logrotate/logrotate)
Consider we output our logs to `/var/log/myapp.log` like so:
```
> node server.js > /var/log/myapp.log
```
We would rotate our log files with logrotate, by adding the following to `/etc/logrotate.d/myapp`:
```
/var/log/myapp.log {
su root
daily
rotate 7
delaycompress
compress
notifempty
missingok
copytruncate
}
```
<a name="redact"></a>
## How do I redact sensitive information??
Use [pino-noir](http://npm.im/pino-noir), initialize with the key paths you wish to redact and pass the resulting instance in through the `serializers` option
```js
var noir = require('pino-noir')
var pino = require('pino')({
serializers: noir(['key', 'path.to.key'])
})
pino.info({
key: 'will be redacted',
path: {
to: {key: 'sensitive', another: 'thing'}
},
more: 'stuff'
})
// {"pid":7306,"hostname":"x","level":30,"time":1475519922198,"key":"[Redacted]","path":{"to":{"key":"[Redacted]","another":"thing"}},"more":"stuff","v":1}
```
If you have other serializers simply extend:
```js
var noir = require('pino-noir')
var pino = require('pino')({
serializers: Object.assign(
noir(['key', 'path.to.key']),
{myCustomSerializer: () => {}}
})
```
<a name="transports"></a>
## How to use Transports with Pino
Create a separate process and pipe to it.
For example:
```js
var split = require('split2')
var pump = require('pump')
var through = require('through2')
var myTransport = through.obj(function (chunk, enc, cb) {
// do whatever you want here!
console.log(chunk)
cb()
})
pump(process.stdin, split(JSON.parse), myTransport)
```
```sh
node my-app-which-logs-stuff-to-stdout.js | node my-transport-process.js
```
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!
<a name="pino-elasticsearch"></a>
### pino-elasticsearch
[pino-elasticsearch][pino-elasticsearch] uploads the log lines in bulk
to [Elasticsearch][elasticsearch], to be displayed in [Kibana][kibana].
It is extremely simple to use and setup
```sh
$ node yourapp.js | pino-elasticsearch
```
Assuming Elasticsearch is running on localhost.
If you wish to connect to an external elasticsearch instance (recommended for production):
* Check that you defined `network.host` in your `elasticsearch.yml` configuration file. See [elasticsearch Network Settings documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-network.html#common-network-settings) for more details.
* Launch:
```sh
$ node yourapp.js | pino-elasticsearch --host 192.168.1.42
```
Assuming Elasticsearch is running on `192.168.1.42`.
Then, head to your
Kibana instance, and [create an index pattern](https://www.elastic.co/guide/en/kibana/current/setup.html) on `'pino'`,
the default for `pino-elasticsearch`.
[pino-elasticsearch]: https://github.com/pinojs/pino-elasticsearch
<a name="pino-socket"></a>
### pino-socket
[pino-socket][pino-socket] is a transport that will forward logs to a IPv4
UDP or TCP socket. As an example, use `socat` to fake a listener:
```sh
$ socat -v udp4-recvfrom:6000,fork exec:'/bin/cat'
```
And then run an application that uses `pino` for logging:
```sh
$ node yourapp.js | pino-socket -p 6000
```
You should see the logs from your application on both consoles.
<a name="pino-syslog"></a>
### pino-syslog
[pino-syslog][pino-syslog] is a transport, really a "transform," that converts
*pino's* logs to [RFC3164][rfc3164] compatible log messages. *pino-syslog* does not
forward the logs anywhere, it merely re-writes the messages to `stdout`. But
in combination with *pino-socket*, you can relay logs to a syslog server:
```sh
$ node yourapp.js | pino-syslog | pino-socket -a syslog.example.com
```
Example output for the "hello world" log:
```
<134>Apr 1 16:44:58 MacBook-Pro-3 none[94473]: {"pid":94473,"hostname":"MacBook-Pro-3","level":30,"msg":"hello world","time":1459529098958,"v":1}
```
[pino-syslog]: https://www.npmjs.com/package/pino-syslog
[rfc3164]: https://tools.ietf.org/html/rfc3164
#### Logstash
You can also use [pino-socket][pino-socket] to upload logs to
[Logstash][logstash] via:
```
$ node yourapp.js | pino-socket -a 127.0.0.1 -p 5000 -m tcp
```
Assuming your logstash is running on the same host and configured as
follows:
```
input {
tcp {
port => 5000
}
}
filter {
json {
source => "message"
}
}
output {
elasticsearch {
hosts => "127.0.0.1:9200"
}
}
```
See https://www.elastic.co/guide/en/kibana/current/setup.html to learn
how to setup [Kibana][kibana].
If you are a Docker fan, you can use
https://github.com/deviantony/docker-elk to setup an ELK stack.
[pino-socket]: https://www.npmjs.com/package/pino-socket
<a name="browser"></a>
## Pino in the browser
Pino is compatible with [`browserify`](http://npm.im) for browser side usage. This can be useful with isomorphic/universal JavaScript code.
Pino is compatible with [`browserify`](http://npm.im) for browser side usage:
This can be useful with isomorphic/universal JavaScript code.
In the browser, `pino` uses corresponding [Log4j](https://en.wikipedia.org/wiki/Log4j) `console` methods (`console.error`, `console.warn`, `console.info`, `console.debug`, `console.trace`) and uses `console.error` for any `fatal` level logs.

@@ -1016,3 +206,2 @@

### David Mark Clements

@@ -1038,2 +227,10 @@

## Contributing
Pino is an **OPEN Open Source Project**. This means that:
> Individuals making significant and valuable contributions are given commit-access to the project to contribute as they see fit. This project is more like an open wiki than a standard guarded open source project.
See the [CONTRIBUTING.md](https://github.com/pinojs/pino/blob/master/CONTRIBUTING.md) file for more details.
<a name="acknowledgements"></a>

@@ -1040,0 +237,0 @@ ## Acknowledgements

@@ -70,24 +70,2 @@ 'use strict'

test('passing error at level ' + name, function (t) {
t.plan(2)
var err = new Error('myerror')
var instance = pino(sink(function (chunk, enc, cb) {
t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
delete chunk.time
t.deepEqual(chunk, {
pid: pid,
hostname: hostname,
level: level,
type: 'Error',
msg: err.message,
stack: err.stack,
v: 1
})
cb()
}))
instance.level = name
instance[name](err)
})
test('passing error with a serializer at level ' + name, function (t) {

@@ -296,2 +274,38 @@ t.plan(2)

// https://github.com/pinojs/pino/issues/139
test('object and format string', function (t) {
var instance = pino(sink(function (chunk, enc, cb) {
delete chunk.time
t.deepEqual(chunk, {
pid: pid,
hostname: hostname,
level: 30,
msg: 'foo bar',
v: 1
})
t.end()
cb()
}))
instance.info({}, 'foo %s', 'bar')
})
test('object and format string property', function (t) {
var instance = pino(sink(function (chunk, enc, cb) {
delete chunk.time
t.deepEqual(chunk, {
pid: pid,
hostname: hostname,
level: 30,
msg: 'foo bar',
answer: 42,
v: 1
})
t.end()
cb()
}))
instance.info({ answer: 42 }, 'foo %s', 'bar')
})
test('correctly strip undefined when returned from toJSON', function (t) {

@@ -298,0 +312,0 @@ t.plan(1)

@@ -243,3 +243,3 @@ 'use strict'

function fnName (fn) {
var rx = /^\s*function\s*([^\(]*)/i
var rx = /^\s*function\s*([^(]*)/i
var match = rx.exec(fn)

@@ -246,0 +246,0 @@ return match && match[1]

@@ -140,1 +140,7 @@ 'use strict'

})
test('flush does nothing without stream mode', function (t) {
var instance = require('..')()
instance.flush()
t.end()
})

@@ -29,2 +29,10 @@ 'use strict'

test('the wrong level throws', function (t) {
t.plan(1)
var instance = pino()
t.throws(function () {
instance.level = 'kaboom'
})
})
test('set the level by number', function (t) {

@@ -31,0 +39,0 @@ t.plan(4)

@@ -113,1 +113,63 @@ 'use strict'

})
test('pino transform prettifies properties', function (t) {
t.plan(1)
var pretty = pino.pretty()
var first = true
pretty.pipe(split(function (line) {
if (first) {
first = false
} else {
t.equal(line, ' a: "b"', 'prettifies the line')
}
return line
}))
var instance = pino(pretty)
instance.info({ a: 'b' }, 'hello world')
})
test('pino transform treats the name with care', function (t) {
t.plan(1)
var pretty = pino.pretty()
pretty.pipe(split(function (line) {
t.ok(line.match(/\(matteo\/.*$/), 'includes the name')
return line
}))
var instance = pino({ name: 'matteo' }, pretty)
instance.info('hello world')
})
test('handles `null` input', function (t) {
t.plan(1)
var pretty = pino.pretty()
pretty.pipe(split(function (line) {
t.is(line, 'null')
return line
}))
pretty.write('null')
pretty.end()
})
test('handles `undefined` input', function (t) {
t.plan(1)
var pretty = pino.pretty()
pretty.pipe(split(function (line) {
t.is(line, 'undefined')
return line
}))
pretty.write('undefined')
pretty.end()
})
test('handles `true` input', function (t) {
t.plan(1)
var pretty = pino.pretty()
pretty.pipe(split(function (line) {
t.is(line, 'true')
return line
}))
pretty.write('true')
pretty.end()
})

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc