-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
799 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"esnext": true, | ||
"node": true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
LINT = node_modules/.bin/jshint | ||
MOCHA = node_modules/.bin/_mocha | ||
ISTANBUL = node_modules/.bin/istanbul | ||
|
||
all: lint test-cov | ||
|
||
lint: index.js | ||
@ $(LINT) index.js | ||
|
||
test: .PHONY | ||
@ node --harmony $(MOCHA) | ||
|
||
test-cov: .PHONY | ||
@ node --harmony $(ISTANBUL) cover $(MOCHA) | ||
|
||
test-travis: lint test-cov | ||
@ node --harmony $(ISTANBUL) check-coverage | ||
|
||
.PHONY: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,232 @@ | ||
koa-bunyan-logger | ||
================= | ||
# koa-bunyan-logger | ||
|
||
Flexible log context and request logging middleware | ||
for [koa](http://koajs.com/) using [bunyan](https://github.com/trentm/node-bunyan). | ||
|
||
Inspired by [koa-bunyan](https://github.com/ivpusic/koa-bunyan), | ||
[koa-json-logger](https://github.com/rudijs/koa-json-logger), | ||
[bunyan-request](https://github.com/vvo/bunyan-request), and others. | ||
|
||
A primary goal of this module is to be as flexible as possible, while | ||
remaining relatively lightweight, leaving advanced functionality and | ||
customization the app. | ||
|
||
```js | ||
var koa = require('koa'); | ||
var koaBunyanLogger = require('koa-bunyan-logger'); | ||
|
||
var app = koa(); | ||
app.use(koaBunyanLogger()); | ||
|
||
app.use(function *() { | ||
this.log.info({'Got a request from %s for %s', this.request.ip, this.path); | ||
}); | ||
|
||
app.listen(8000); | ||
``` | ||
Server: | ||
``` | ||
node --harmony examples/simple.js | ./node_modules/.bin/bunyan -o short` | ||
``` | ||
|
||
Client: | ||
``` | ||
curl http://localhost:8000/ | ||
``` | ||
|
||
Server output: | ||
``` | ||
07:50:14.014Z INFO koa: Got a request from ::1 for / | ||
``` | ||
|
||
### Request logging | ||
|
||
```js | ||
app.use(koaBunyanLogger()); | ||
app.use(koaBunyanLogger.requestIdContext()); | ||
app.use(koaBunyanLogger.requestLogger()); | ||
``` | ||
|
||
Server: | ||
``` | ||
node --harmony examples/requests.js | ./node_modules/.bin/bunyan -o short | ||
``` | ||
|
||
Client: | ||
``` | ||
curl -H "X-Request-Id: 1234" http://localhost:8000/ | ||
``` | ||
|
||
Server output: | ||
``` | ||
20:19:24.526Z INFO koa: --> GET / (req_id=1234) | ||
GET / HTTP/1.1 | ||
-- | ||
req.header: { | ||
"user-agent": "curl/7.30.0", | ||
"host": "localhost:8000", | ||
"accept": "*/*", | ||
"x-request-id": "1234" | ||
} | ||
20:19:24.527Z INFO koa: <-- GET / 1ms (req_id=1234, duration=1, res.status=200, res.message=OK) | ||
GET / HTTP/1.1 | ||
-- | ||
x-powered-by: koa | ||
content-type: text/plain; charset=utf-8 | ||
content-length: 11 | ||
-- | ||
req.header: { | ||
"user-agent": "curl/7.30.0", | ||
"host": "localhost:8000", | ||
"accept": "*/*", | ||
"x-request-id": "1234" | ||
} | ||
``` | ||
|
||
### Suppressing default error stack traces | ||
|
||
To ensure that stack traces from request handling don't get logged in their | ||
raw non-JSON forms, you can disable the app's default error handler: | ||
|
||
```js | ||
app.on('error', function () {}); | ||
``` | ||
|
||
## API Reference | ||
|
||
### koaBunyanLogger(logger) | ||
|
||
Parameters: | ||
- logger: bunyan logger instance or an object to pass to bunyan.createLogger() | ||
|
||
#### Examples | ||
|
||
Use an existing logger: | ||
|
||
```js | ||
var bunyan = require('bunyan'); | ||
var koaBunyanLogger = require('koa-bunyan-logger'); | ||
var appLogger = bunyan.createLogger({name: 'myapp', level: 'debug'}); | ||
app.use(koaBunyanLogger(appLogger)); | ||
``` | ||
|
||
Shortcut to create a new logger: | ||
|
||
```js | ||
var koaBunyanLogger = require('koa-bunyan-logger'); | ||
app.use(koaBunyanLogger({ | ||
name: 'myapp', | ||
level: 'debug' | ||
})); | ||
``` | ||
|
||
### koaBunyanLogger.requestLogger(opts) | ||
|
||
Options: | ||
- durationField: Name of field to store request duration in ms | ||
|
||
- levelFn: Function which will be called with (status, err) and should | ||
return the name of a log level to be used for the response log entry. | ||
The default function will log status 400-499 as warn, 500+ as error, | ||
and all other responses as info. | ||
|
||
- updateLogFields: Function which will be called with a single argument, | ||
an object containing the fields (req, res, err) to be logged with the | ||
request and response message. | ||
|
||
The function has the opportunity to add or remove fields from the object, | ||
or return a different object to replace the default set of fields. | ||
The function will be called using the koa 'this' context, once for the | ||
request and again for the response. | ||
|
||
- updateRequestLogFields: Function which will be called with a request | ||
fields object when logging a request, after processing updateLogFields. | ||
|
||
- updateResponseLogFields: Function which will be called with a response | ||
fields object when logging a response, after processing updateLogFields. | ||
It also receives a second argument, err, if an error was thrown. | ||
|
||
- formatRequestLog: Function which will be called to generate a log message | ||
for logging requests. The function will be called in the context of the | ||
koa 'this' context and passed the request fields object. It should return | ||
a string. | ||
|
||
- formatResponseLog: Same as formatRequestLog, but for responses. | ||
|
||
#### Examples | ||
|
||
Basic usage: | ||
|
||
```js | ||
app.use(koaBunyanLogger()); | ||
app.use(koaBunyanLogger.requestLogger()); | ||
``` | ||
|
||
Add custom fields to include in request and response logs: | ||
|
||
```js | ||
app.use(koaBunyanLogger.requestLogger({ | ||
// Custom fields for both request and response | ||
updateLogFields: function (fields) { | ||
fields.authorized_user = this.user.id; | ||
fields.client_version = this.request.get('X-Client-Version'); | ||
}, | ||
|
||
// Custom fields for response only | ||
updateResponseLogFields: function (fields, err) { | ||
if (err) { | ||
fields.last_db_query = this.db.lastDbQuery(); | ||
} | ||
} | ||
})); | ||
``` | ||
### koaBunyanLogger.requestIdContext(opts) | ||
Get X-Request-Id header, or if the header does not exist, generates a random | ||
unique id for each request. | ||
Options: | ||
- header: name of header to get request id from | ||
- prop: property to store on context; defaults to 'reqId' e.g. this.reqId | ||
- requestProp: property to store on request; defaults to 'reqId' e.g. this.request.reqId | ||
- field: field to add to log messages in downstream middleware and handlers; | ||
defaults to 'req_id' | ||
#### Examples | ||
```js | ||
var koaBunyanLogger = require('koa-bunyan-logger'); | ||
|
||
app.use(koaBunyanLogger()); | ||
app.use(koaBunyanLogger.requestIdContext()); | ||
``` | ||
Or use a different header: | ||
```js | ||
var koaBunyanLogger = require('koa-bunyan-logger'); | ||
|
||
app.use(koaBunyanLogger()); | ||
app.use(koaBunyanLogger.requestIdContext({ | ||
header: 'Request-Id' | ||
})); | ||
``` | ||
By default, the request id will be accessible as this.reqId and this.request.reqId: | ||
```js | ||
var koaBunyanLogger = require('koa-bunyan-logger'); | ||
|
||
app.use(koaBunyanLogger()); | ||
app.use(koaBunyanLogger.requestIdContext()); | ||
|
||
app.use(function * () { | ||
this.response.set('X-Server-Request-Id', this.reqId); | ||
this.body = "Hello world"; | ||
}); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
var koa = require('koa'); | ||
var koaBunyanLogger = require('../'); | ||
|
||
var app = koa(); | ||
|
||
app.use(koaBunyanLogger()); | ||
app.use(koaBunyanLogger.requestLogger()); | ||
|
||
var userByToken = { | ||
'token123': {id: 1, name: 'alice'}, | ||
'token345': {id: 2, name: 'bob'} | ||
}; | ||
|
||
app.use(function *(next) { | ||
var token = this.query.token; | ||
|
||
if (!token) { | ||
this.throw(403, 'expected token\r\n'); | ||
} | ||
|
||
this.log.trace('looking up user with token "%s"', token); | ||
this.user = userByToken[token]; | ||
|
||
if (!this.user) { | ||
this.throw(403, 'invalid user token\r\n'); | ||
} | ||
|
||
yield next; | ||
}); | ||
|
||
// All log messages from downstream middleware | ||
// will now have 'authorized_user' added to the log fields | ||
app.use(function *(next) { | ||
this.log = this.log.child({ | ||
authorized_user: this.user.id | ||
}); | ||
|
||
yield next; | ||
}); | ||
|
||
app.use(function *() { | ||
this.log.info('doing stuff'); | ||
|
||
this.body = "OK\r\n"; | ||
}); | ||
|
||
app.listen(8000); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
var koa = require('koa'); | ||
var koaBunyanLogger = require('../'); | ||
|
||
var app = koa(); | ||
|
||
app.use(koaBunyanLogger()); | ||
app.use(koaBunyanLogger.requestIdContext()); | ||
app.use(koaBunyanLogger.requestLogger()); | ||
|
||
app.use(function *() { | ||
this.body = 'Hello world\r\n'; | ||
}); | ||
|
||
app.listen(8000); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
var koa = require('koa'); | ||
var koaBunyanLogger = require('../'); | ||
|
||
var app = koa(); | ||
|
||
app.use(koaBunyanLogger()); | ||
|
||
app.use(function *() { | ||
this.log.info('Got a request from %s for %s', this.request.ip, this.path); | ||
this.body = 'Hello world\r\n'; | ||
}); | ||
|
||
app.listen(8000); |
Oops, something went wrong.