Skip to content

Commit

Permalink
Merge branch 'master' into stringify-opt
Browse files Browse the repository at this point in the history
mcollina committed Mar 7, 2016
2 parents c897432 + 6b96119 commit e3b0fc4
Showing 3 changed files with 281 additions and 2 deletions.
80 changes: 80 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ It also includes a shell utility to pretty-print its log files.
* [API](#api)
* [Benchmarks](#benchmarks)
* [How do I rotate log files?](#rotate)
* [Acknowledgements](#acknowledgements)
* [License](#license)

## Install
@@ -62,6 +63,8 @@ This produces:
* <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="#reqSerializer"><code>pino.stdSerializers.<b>req</b></code></a>
* <a href="#resSerializer"><code>pino.stdSerializers.<b>res</b></code></a>

<a name="constructor"></a>
### pino([opts], [stream])
@@ -71,9 +74,28 @@ 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 jsonificable object and
they should never throw.

`stream` is a Writable stream, defaults to `process.stdout`.

Example:

```js
'use strict'

var pino = require('pino')
var instance = pino({
name: 'myapp',
safe: true,
serializers: {
req: pino.stdSerializers.req
res: pino.stdSerializers.res
}
}
```
<a name="level"></a>
### logger.level
@@ -139,6 +161,59 @@ 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="reqSerializer"></a>
### pino.stdSerializers.req
Function to generate a jsonificable object out of an HTTP request from
node 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
Function to generate a jsonificable object out of an HTTP
response from
node 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="benchmarks"></a>
## Benchmarks
@@ -190,6 +265,11 @@ In order to rotate your log files, add in `/etc/logrotate.d/myapp`:
}
```
<a name="acknowledgements"></a>
## Acknowledgements
This project was kindly sponsored by [nearForm](http://nearform.com).
## License
MIT
48 changes: 46 additions & 2 deletions pino.js
Original file line number Diff line number Diff line change
@@ -35,6 +35,7 @@ function pino (opts, stream) {
debug: null,
trace: null
}
var serializers = opts.serializers || {}

for (var key in levels) {
funcs[key] = genLogFunction(key)
@@ -76,6 +77,12 @@ function pino (opts, stream) {
obj = a
params = [b, c, d, e, f, g, h, i, j, k]
base = 1

if (obj.method && obj.headers && obj.socket) {
obj = mapHttpRequest(obj)
} else if (obj.statusCode) {
obj = mapHttpResponse(obj)
}
} else {
params = [a, b, c, d, e, f, g, h, i, j, k]
}
@@ -92,15 +99,18 @@ function pino (opts, stream) {
msg = obj.message
}
var data = message(num, msg)
var value
if (obj) {
data = data.slice(0, data.length - 1)

if (obj instanceof Error) {
data += ',"type":"Error","stack":' + stringify(obj.stack) + '}'
} else {
for (var key in obj) {
if (obj.hasOwnProperty(key) && obj[key] !== undefined) {
data += ',"' + key + '":' + stringify(obj[key])
value = obj[key]
if (obj.hasOwnProperty(key) && value !== undefined) {
value = serializers[key] ? serializers[key](value) : value
data += ',"' + key + '":' + stringify(value)
}
}
data += '}'
@@ -122,4 +132,38 @@ function pino (opts, stream) {

function noop () {}

function mapHttpRequest (req) {
return {
req: asReqValue(req)
}
}

function mapHttpResponse (res) {
return {
res: asResValue(res)
}
}

function asReqValue (req) {
return {
method: req.method,
url: req.url,
headers: req.headers,
remoteAddress: req.connection.remoteAddress,
remotePort: req.connection.remotePort
}
}

function asResValue (res) {
return {
statusCode: res.statusCode,
header: res._header
}
}

module.exports = pino

module.exports.stdSerializers = {
req: asReqValue,
res: asResValue
}
155 changes: 155 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ var pino = require('./')
var writeStream = require('flush-write-stream')
var os = require('os')
var split = require('split2')
var http = require('http')
var pid = process.pid
var hostname = os.hostname()

@@ -250,3 +251,157 @@ test('set properties defined in the prototype chain', function (t) {

instance.info(new MyObject())
})

test('http request support', function (t) {
t.plan(3)

var originalReq
var instance = pino(sink(function (chunk, enc, cb) {
t.ok(Date.parse(chunk.time) <= new Date(), 'time is greater than Date.now()')
delete chunk.time
t.deepEqual(chunk, {
pid: pid,
hostname: hostname,
level: 30,
msg: 'my request',
v: 0,
req: {
method: originalReq.method,
url: originalReq.url,
headers: originalReq.headers,
remoteAddress: originalReq.connection.remoteAddress,
remotePort: originalReq.connection.remotePort
}
})
cb()
}))

var server = http.createServer(function (req, res) {
originalReq = req
instance.info(req, 'my request')
res.end('hello')
}).listen(function (err) {
t.error(err)
t.teardown(server.close.bind(server))

http.get('http://localhost:' + server.address().port, function (res) {
res.resume()
})
})
})

test('http request support via serializer', function (t) {
t.plan(3)

var originalReq
var instance = pino({
serializers: {
req: pino.stdSerializers.req
}
}, sink(function (chunk, enc, cb) {
t.ok(Date.parse(chunk.time) <= new Date(), 'time is greater than Date.now()')
delete chunk.time
t.deepEqual(chunk, {
pid: pid,
hostname: hostname,
level: 30,
msg: 'my request',
v: 0,
req: {
method: originalReq.method,
url: originalReq.url,
headers: originalReq.headers,
remoteAddress: originalReq.connection.remoteAddress,
remotePort: originalReq.connection.remotePort
}
})
cb()
}))

var server = http.createServer(function (req, res) {
originalReq = req
instance.info({ req: req }, 'my request')
res.end('hello')
}).listen(function (err) {
t.error(err)
t.teardown(server.close.bind(server))

http.get('http://localhost:' + server.address().port, function (res) {
res.resume()
})
})
})

test('http response support', function (t) {
t.plan(3)

var originalRes
var instance = pino(sink(function (chunk, enc, cb) {
t.ok(Date.parse(chunk.time) <= new Date(), 'time is greater than Date.now()')
delete chunk.time
t.deepEqual(chunk, {
pid: pid,
hostname: hostname,
level: 30,
msg: 'my response',
v: 0,
res: {
statusCode: originalRes.statusCode,
header: originalRes._header
}
})
cb()
}))

var server = http.createServer(function (req, res) {
originalRes = res
res.end('hello')
instance.info(res, 'my response')
}).listen(function (err) {
t.error(err)
t.teardown(server.close.bind(server))

http.get('http://localhost:' + server.address().port, function (res) {
res.resume()
})
})
})

test('http response support via a serializer', function (t) {
t.plan(3)

var originalRes
var instance = pino({
serializers: {
res: pino.stdSerializers.res
}
}, sink(function (chunk, enc, cb) {
t.ok(Date.parse(chunk.time) <= new Date(), 'time is greater than Date.now()')
delete chunk.time
t.deepEqual(chunk, {
pid: pid,
hostname: hostname,
level: 30,
msg: 'my response',
v: 0,
res: {
statusCode: originalRes.statusCode,
header: originalRes._header
}
})
cb()
}))

var server = http.createServer(function (req, res) {
originalRes = res
res.end('hello')
instance.info({ res: res }, 'my response')
}).listen(function (err) {
t.error(err)
t.teardown(server.close.bind(server))

http.get('http://localhost:' + server.address().port, function (res) {
res.resume()
})
})
})

0 comments on commit e3b0fc4

Please sign in to comment.