Added the missing syntax highlighting
Added syntax highlighting everywhere and minor formatting.
This commit is contained in:
parent
4f071a0a37
commit
9cd70479cb
1 changed files with 384 additions and 303 deletions
687
README.md
687
README.md
|
@ -1,8 +1,10 @@
|
|||
Bunyan is **a simple and fast JSON logging library** for node.js services:
|
||||
|
||||
var bunyan = require('bunyan');
|
||||
var log = bunyan.createLogger({name: "myapp"});
|
||||
log.info("hi");
|
||||
```js
|
||||
var bunyan = require('bunyan');
|
||||
var log = bunyan.createLogger({name: "myapp"});
|
||||
log.info("hi");
|
||||
```
|
||||
|
||||
and **a `bunyan` CLI tool** for nicely viewing those logs:
|
||||
|
||||
|
@ -31,7 +33,9 @@ browser](https://groups.google.com/forum/?fromgroups#!forum/bunyan-logging).
|
|||
|
||||
# Installation
|
||||
|
||||
npm install bunyan
|
||||
```sh
|
||||
npm install bunyan
|
||||
```
|
||||
|
||||
**Tip**: The `bunyan` CLI tool is written to be compatible (within reason) with
|
||||
all versions of Bunyan logs. Therefore you might want to `npm install -g bunyan`
|
||||
|
@ -60,11 +64,13 @@ node.js library usage of bunyan in your apps.
|
|||
Like most logging libraries you create a Logger instance and call methods
|
||||
named after the logging levels:
|
||||
|
||||
$ cat hi.js
|
||||
var bunyan = require('bunyan');
|
||||
var log = bunyan.createLogger({name: 'myapp'});
|
||||
log.info('hi');
|
||||
log.warn({lang: 'fr'}, 'au revoir');
|
||||
```sh
|
||||
$ cat hi.js
|
||||
var bunyan = require('bunyan');
|
||||
var log = bunyan.createLogger({name: 'myapp'});
|
||||
log.info('hi');
|
||||
log.warn({lang: 'fr'}, 'au revoir');
|
||||
```
|
||||
|
||||
All loggers must provide a "name". This is somewhat akin to the log4j logger
|
||||
"name", but Bunyan doesn't do hierarchical logger names.
|
||||
|
@ -72,33 +78,36 @@ All loggers must provide a "name". This is somewhat akin to the log4j logger
|
|||
**Bunyan log records are JSON.** A few fields are added automatically:
|
||||
"pid", "hostname", "time" and "v".
|
||||
|
||||
$ node hi.js
|
||||
{"name":"myapp","hostname":"banana.local","pid":40161,"level":30,"msg":"hi","time":"2013-01-04T18:46:23.851Z","v":0}
|
||||
{"name":"myapp","hostname":"banana.local","pid":40161,"level":40,"lang":"fr","msg":"au revoir","time":"2013-01-04T18:46:23.853Z","v":0}
|
||||
|
||||
```sh
|
||||
$ node hi.js
|
||||
{"name":"myapp","hostname":"banana.local","pid":40161,"level":30,"msg":"hi","time":"2013-01-04T18:46:23.851Z","v":0}
|
||||
{"name":"myapp","hostname":"banana.local","pid":40161,"level":40,"lang":"fr","msg":"au revoir","time":"2013-01-04T18:46:23.853Z","v":0}
|
||||
```
|
||||
|
||||
## Log Method API
|
||||
|
||||
The example above shows two different ways to call `log.info(...)`. The
|
||||
full API is:
|
||||
|
||||
log.info(); // Returns a boolean: is the "info" level enabled?
|
||||
// This is equivalent to `log.isInfoEnabled()` or
|
||||
// `log.isEnabledFor(INFO)` in log4j.
|
||||
```js
|
||||
log.info(); // Returns a boolean: is the "info" level enabled?
|
||||
// This is equivalent to `log.isInfoEnabled()` or
|
||||
// `log.isEnabledFor(INFO)` in log4j.
|
||||
|
||||
log.info('hi'); // Log a simple string message (or number).
|
||||
log.info('hi %s', bob, anotherVar); // Uses `util.format` for msg formatting.
|
||||
log.info('hi'); // Log a simple string message (or number).
|
||||
log.info('hi %s', bob, anotherVar); // Uses `util.format` for msg formatting.
|
||||
|
||||
log.info({foo: 'bar'}, 'hi');
|
||||
// Adds "foo" field to log record. You can add any number
|
||||
// of additional fields here.
|
||||
log.info({foo: 'bar'}, 'hi');
|
||||
// Adds "foo" field to log record. You can add any number
|
||||
// of additional fields here.
|
||||
|
||||
log.info(err); // Special case to log an `Error` instance to the record.
|
||||
// This adds an "err" field with exception details
|
||||
// (including the stack) and sets "msg" to the exception
|
||||
// message.
|
||||
log.info(err, 'more on this: %s', more);
|
||||
// ... or you can specify the "msg".
|
||||
log.info(err); // Special case to log an `Error` instance to the record.
|
||||
// This adds an "err" field with exception details
|
||||
// (including the stack) and sets "msg" to the exception
|
||||
// message.
|
||||
log.info(err, 'more on this: %s', more);
|
||||
// ... or you can specify the "msg".
|
||||
```
|
||||
|
||||
Note that this implies **you cannot pass any object as the first argument
|
||||
to log it**. IOW, `log.info(mywidget)` may not be what you expect. Instead
|
||||
|
@ -106,7 +115,9 @@ of a string representation of `mywidget` that other logging libraries may
|
|||
give you, Bunyan will try to JSON-ify your object. It is a Bunyan best
|
||||
practice to always give a field name to included objects, e.g.:
|
||||
|
||||
log.info({widget: mywidget}, ...)
|
||||
```js
|
||||
log.info({widget: mywidget}, ...)
|
||||
```
|
||||
|
||||
This will dove-tail with [Bunyan serializer support](#serializers), discussed
|
||||
later.
|
||||
|
@ -123,9 +134,11 @@ but not for reading directly. A **`bunyan` tool** is provided **for
|
|||
pretty-printing bunyan logs** and for **filtering** (e.g.
|
||||
`| bunyan -c 'this.foo == "bar"'`). Using our example above:
|
||||
|
||||
$ node hi.js | ./bin/bunyan
|
||||
[2013-01-04T19:01:18.241Z] INFO: myapp/40208 on banana.local: hi
|
||||
[2013-01-04T19:01:18.242Z] WARN: myapp/40208 on banana.local: au revoir (lang=fr)
|
||||
```sh
|
||||
$ node hi.js | ./bin/bunyan
|
||||
[2013-01-04T19:01:18.241Z] INFO: myapp/40208 on banana.local: hi
|
||||
[2013-01-04T19:01:18.242Z] WARN: myapp/40208 on banana.local: au revoir (lang=fr)
|
||||
```
|
||||
|
||||
See the screenshot above for an example of the default coloring of rendered
|
||||
log output. That example also shows the nice formatting automatically done for
|
||||
|
@ -136,14 +149,18 @@ One interesting feature is **filtering** of log content, which can be useful
|
|||
for digging through large log files or for analysis. We can filter only
|
||||
records above a certain level:
|
||||
|
||||
$ node hi.js | bunyan -l warn
|
||||
[2013-01-04T19:08:37.182Z] WARN: myapp/40353 on banana.local: au revoir (lang=fr)
|
||||
```sh
|
||||
$ node hi.js | bunyan -l warn
|
||||
[2013-01-04T19:08:37.182Z] WARN: myapp/40353 on banana.local: au revoir (lang=fr)
|
||||
```
|
||||
|
||||
Or filter on the JSON fields in the records (e.g. only showing the French
|
||||
records in our contrived example):
|
||||
|
||||
$ node hi.js | bunyan -c 'this.lang == "fr"'
|
||||
[2013-01-04T19:08:26.411Z] WARN: myapp/40342 on banana.local: au revoir (lang=fr)
|
||||
```sh
|
||||
$ node hi.js | bunyan -c 'this.lang == "fr"'
|
||||
[2013-01-04T19:08:26.411Z] WARN: myapp/40342 on banana.local: au revoir (lang=fr)
|
||||
```
|
||||
|
||||
See `bunyan --help` for other facilities.
|
||||
|
||||
|
@ -153,32 +170,35 @@ See `bunyan --help` for other facilities.
|
|||
By default, log output is to stdout and at the "info" level. Explicitly that
|
||||
looks like:
|
||||
|
||||
var log = bunyan.createLogger({
|
||||
name: 'myapp',
|
||||
stream: process.stdout,
|
||||
level: 'info'
|
||||
});
|
||||
```js
|
||||
var log = bunyan.createLogger({
|
||||
name: 'myapp',
|
||||
stream: process.stdout,
|
||||
level: 'info'
|
||||
});
|
||||
```
|
||||
|
||||
That is an abbreviated form for a single stream. **You can define multiple
|
||||
streams at different levels**.
|
||||
|
||||
var log = bunyan.createLogger({
|
||||
name: 'myapp',
|
||||
streams: [
|
||||
{
|
||||
level: 'info',
|
||||
stream: process.stdout // log INFO and above to stdout
|
||||
},
|
||||
{
|
||||
level: 'error',
|
||||
path: '/var/tmp/myapp-error.log' // log ERROR and above to a file
|
||||
}
|
||||
]
|
||||
});
|
||||
```js
|
||||
var log = bunyan.createLogger({
|
||||
name: 'myapp',
|
||||
streams: [
|
||||
{
|
||||
level: 'info',
|
||||
stream: process.stdout // log INFO and above to stdout
|
||||
},
|
||||
{
|
||||
level: 'error',
|
||||
path: '/var/tmp/myapp-error.log' // log ERROR and above to a file
|
||||
}
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
More on streams in the [Streams section](#streams) below.
|
||||
|
||||
|
||||
## log.child
|
||||
|
||||
Bunyan has a concept of a child logger to **specialize a logger for a
|
||||
|
@ -190,38 +210,43 @@ In the following example, logging on a "Wuzzle" instance's `this.log` will
|
|||
be exactly as on the parent logger with the addition of the `widget_type`
|
||||
field:
|
||||
|
||||
var bunyan = require('bunyan');
|
||||
var log = bunyan.createLogger({name: 'myapp'});
|
||||
```js
|
||||
var bunyan = require('bunyan');
|
||||
var log = bunyan.createLogger({name: 'myapp'});
|
||||
|
||||
function Wuzzle(options) {
|
||||
this.log = options.log.child({widget_type: 'wuzzle'});
|
||||
this.log.info('creating a wuzzle')
|
||||
}
|
||||
Wuzzle.prototype.woos = function () {
|
||||
this.log.warn('This wuzzle is woosey.')
|
||||
}
|
||||
function Wuzzle(options) {
|
||||
this.log = options.log.child({widget_type: 'wuzzle'});
|
||||
this.log.info('creating a wuzzle')
|
||||
}
|
||||
Wuzzle.prototype.woos = function () {
|
||||
this.log.warn('This wuzzle is woosey.')
|
||||
}
|
||||
|
||||
log.info('start');
|
||||
var wuzzle = new Wuzzle({log: log});
|
||||
wuzzle.woos();
|
||||
log.info('done');
|
||||
log.info('start');
|
||||
var wuzzle = new Wuzzle({log: log});
|
||||
wuzzle.woos();
|
||||
log.info('done');
|
||||
```
|
||||
|
||||
Running that looks like (raw):
|
||||
|
||||
$ node myapp.js
|
||||
{"name":"myapp","hostname":"myhost","pid":34572,"level":30,"msg":"start","time":"2013-01-04T07:47:25.814Z","v":0}
|
||||
{"name":"myapp","hostname":"myhost","pid":34572,"widget_type":"wuzzle","level":30,"msg":"creating a wuzzle","time":"2013-01-04T07:47:25.815Z","v":0}
|
||||
{"name":"myapp","hostname":"myhost","pid":34572,"widget_type":"wuzzle","level":40,"msg":"This wuzzle is woosey.","time":"2013-01-04T07:47:25.815Z","v":0}
|
||||
{"name":"myapp","hostname":"myhost","pid":34572,"level":30,"msg":"done","time":"2013-01-04T07:47:25.816Z","v":0}
|
||||
```sh
|
||||
$ node myapp.js
|
||||
{"name":"myapp","hostname":"myhost","pid":34572,"level":30,"msg":"start","time":"2013-01-04T07:47:25.814Z","v":0}
|
||||
{"name":"myapp","hostname":"myhost","pid":34572,"widget_type":"wuzzle","level":30,"msg":"creating a wuzzle","time":"2013-01-04T07:47:25.815Z","v":0}
|
||||
{"name":"myapp","hostname":"myhost","pid":34572,"widget_type":"wuzzle","level":40,"msg":"This wuzzle is woosey.","time":"2013-01-04T07:47:25.815Z","v":0}
|
||||
{"name":"myapp","hostname":"myhost","pid":34572,"level":30,"msg":"done","time":"2013-01-04T07:47:25.816Z","v":0}
|
||||
```
|
||||
|
||||
And with the `bunyan` CLI (using the "short" output mode):
|
||||
|
||||
$ node myapp.js | bunyan -o short
|
||||
07:46:42.707Z INFO myapp: start
|
||||
07:46:42.709Z INFO myapp: creating a wuzzle (widget_type=wuzzle)
|
||||
07:46:42.709Z WARN myapp: This wuzzle is woosey. (widget_type=wuzzle)
|
||||
07:46:42.709Z INFO myapp: done
|
||||
|
||||
```sh
|
||||
$ node myapp.js | bunyan -o short
|
||||
07:46:42.707Z INFO myapp: start
|
||||
07:46:42.709Z INFO myapp: creating a wuzzle (widget_type=wuzzle)
|
||||
07:46:42.709Z WARN myapp: This wuzzle is woosey. (widget_type=wuzzle)
|
||||
07:46:42.709Z INFO myapp: done
|
||||
```
|
||||
|
||||
A more practical example is in the
|
||||
[node-restify](https://github.com/mcavage/node-restify) web framework.
|
||||
|
@ -229,7 +254,9 @@ Restify uses Bunyan for its logging. One feature of its integration, is that
|
|||
if `server.use(restify.requestLogger())` is used, each restify request handler
|
||||
includes a `req.log` logger that is:
|
||||
|
||||
log.child({req_id: <unique request id>}, true)
|
||||
```js
|
||||
log.child({req_id: <unique request id>}, true)
|
||||
```
|
||||
|
||||
Apps using restify can then use `req.log` and have all such log records
|
||||
include the unique request id (as "req\_id"). Handy.
|
||||
|
@ -240,39 +267,47 @@ include the unique request id (as "req\_id"). Handy.
|
|||
Bunyan has a concept of **"serializers" to produce a JSON-able object from a
|
||||
JavaScript object**, so you can easily do the following:
|
||||
|
||||
log.info({req: <request object>}, 'something about handling this request');
|
||||
```js
|
||||
log.info({req: <request object>}, 'something about handling this request');
|
||||
```
|
||||
|
||||
Serializers is a mapping of log record field name, "req" in this example, to
|
||||
a serializer function. That looks like this:
|
||||
|
||||
function reqSerializer(req) {
|
||||
return {
|
||||
method: req.method,
|
||||
url: req.url,
|
||||
headers: req.headers
|
||||
}
|
||||
```js
|
||||
function reqSerializer(req) {
|
||||
return {
|
||||
method: req.method,
|
||||
url: req.url,
|
||||
headers: req.headers
|
||||
}
|
||||
var log = bunyan.createLogger({
|
||||
name: 'myapp',
|
||||
serializers: {
|
||||
req: reqSerializer
|
||||
}
|
||||
});
|
||||
}
|
||||
var log = bunyan.createLogger({
|
||||
name: 'myapp',
|
||||
serializers: {
|
||||
req: reqSerializer
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
Or this:
|
||||
|
||||
var log = bunyan.createLogger({
|
||||
name: 'myapp',
|
||||
serializers: {req: bunyan.stdSerializers.req}
|
||||
});
|
||||
```js
|
||||
var log = bunyan.createLogger({
|
||||
name: 'myapp',
|
||||
serializers: {req: bunyan.stdSerializers.req}
|
||||
});
|
||||
```
|
||||
|
||||
because Bunyan includes a small set of standard serializers. To use all the
|
||||
standard serializers you can use:
|
||||
|
||||
var log = bunyan.createLogger({
|
||||
...
|
||||
serializers: bunyan.stdSerializers
|
||||
});
|
||||
```js
|
||||
var log = bunyan.createLogger({
|
||||
...
|
||||
serializers: bunyan.stdSerializers
|
||||
});
|
||||
```
|
||||
|
||||
**Note**: Your own serializers should never throw, otherwise you'll get an
|
||||
ugly message on stderr from Bunyan (along with the traceback) and the field
|
||||
|
@ -284,25 +319,29 @@ in your log record will be replaced with a short error message.
|
|||
The **source file, line and function of the log call site** can be added to
|
||||
log records by using the `src: true` config option:
|
||||
|
||||
var log = bunyan.createLogger({src: true, ...});
|
||||
```js
|
||||
var log = bunyan.createLogger({src: true, ...});
|
||||
```
|
||||
|
||||
This adds the call source info with the 'src' field, like this:
|
||||
|
||||
{
|
||||
"name": "src-example",
|
||||
"hostname": "banana.local",
|
||||
"pid": 123,
|
||||
"component": "wuzzle",
|
||||
"level": 4,
|
||||
"msg": "This wuzzle is woosey.",
|
||||
"time": "2012-02-06T04:19:35.605Z",
|
||||
"src": {
|
||||
"file": "/Users/trentm/tm/node-bunyan/examples/src.js",
|
||||
"line": 20,
|
||||
"func": "Wuzzle.woos"
|
||||
},
|
||||
"v": 0
|
||||
}
|
||||
```js
|
||||
{
|
||||
"name": "src-example",
|
||||
"hostname": "banana.local",
|
||||
"pid": 123,
|
||||
"component": "wuzzle",
|
||||
"level": 4,
|
||||
"msg": "This wuzzle is woosey.",
|
||||
"time": "2012-02-06T04:19:35.605Z",
|
||||
"src": {
|
||||
"file": "/Users/trentm/tm/node-bunyan/examples/src.js",
|
||||
"line": 20,
|
||||
"func": "Wuzzle.woos"
|
||||
},
|
||||
"v": 0
|
||||
}
|
||||
```
|
||||
|
||||
**WARNING: Determining the call source info is slow. Never use this option
|
||||
in production.**
|
||||
|
@ -336,20 +375,20 @@ The lowercase level names are aliases supported in the API.
|
|||
|
||||
Here is the API for changing levels in an existing logger:
|
||||
|
||||
log.level() -> INFO // gets current level (lowest level of all streams)
|
||||
```js
|
||||
log.level() -> INFO // gets current level (lowest level of all streams)
|
||||
|
||||
log.level(INFO) // set all streams to level INFO
|
||||
log.level("info") // set all streams to level INFO
|
||||
|
||||
log.levels() -> [DEBUG, INFO] // get array of levels of all streams
|
||||
log.levels(0) -> DEBUG // get level of stream at index 0
|
||||
log.levels("foo") // get level of stream with name "foo"
|
||||
|
||||
log.levels(0, INFO) // set level of stream 0 to INFO
|
||||
log.levels(0, "info") // can use "info" et al aliases
|
||||
log.levels("foo", WARN) // set stream named "foo" to WARN
|
||||
log.level(INFO) // set all streams to level INFO
|
||||
log.level("info") // set all streams to level INFO
|
||||
|
||||
log.levels() -> [DEBUG, INFO] // get array of levels of all streams
|
||||
log.levels(0) -> DEBUG // get level of stream at index 0
|
||||
log.levels("foo") // get level of stream with name "foo"
|
||||
|
||||
log.levels(0, INFO) // set level of stream 0 to INFO
|
||||
log.levels(0, "info") // can use "info" et al aliases
|
||||
log.levels("foo", WARN) // set stream named "foo" to WARN
|
||||
```
|
||||
|
||||
# Log Record Fields
|
||||
|
||||
|
@ -368,30 +407,33 @@ incorrect signature) is always a bug in Bunyan.**
|
|||
|
||||
A typical Bunyan log record looks like this:
|
||||
|
||||
{"name":"myserver","hostname":"banana.local","pid":123,"req":{"method":"GET","url":"/path?q=1#anchor","headers":{"x-hi":"Mom","connection":"close"}},"level":3,"msg":"start request","time":"2012-02-03T19:02:46.178Z","v":0}
|
||||
```js
|
||||
{"name":"myserver","hostname":"banana.local","pid":123,"req":{"method":"GET","url":"/path?q=1#anchor","headers":{"x-hi":"Mom","connection":"close"}},"level":3,"msg":"start request","time":"2012-02-03T19:02:46.178Z","v":0}
|
||||
```
|
||||
|
||||
Pretty-printed:
|
||||
|
||||
{
|
||||
"name": "myserver",
|
||||
"hostname": "banana.local",
|
||||
"pid": 123,
|
||||
"req": {
|
||||
"method": "GET",
|
||||
"url": "/path?q=1#anchor",
|
||||
"headers": {
|
||||
"x-hi": "Mom",
|
||||
"connection": "close"
|
||||
},
|
||||
"remoteAddress": "120.0.0.1",
|
||||
"remotePort": 51244
|
||||
},
|
||||
"level": 3,
|
||||
"msg": "start request",
|
||||
"time": "2012-02-03T19:02:57.534Z",
|
||||
"v": 0
|
||||
}
|
||||
|
||||
```js
|
||||
{
|
||||
"name": "myserver",
|
||||
"hostname": "banana.local",
|
||||
"pid": 123,
|
||||
"req": {
|
||||
"method": "GET",
|
||||
"url": "/path?q=1#anchor",
|
||||
"headers": {
|
||||
"x-hi": "Mom",
|
||||
"connection": "close"
|
||||
},
|
||||
"remoteAddress": "120.0.0.1",
|
||||
"remotePort": 51244
|
||||
},
|
||||
"level": 3,
|
||||
"msg": "start request",
|
||||
"time": "2012-02-03T19:02:57.534Z",
|
||||
"v": 0
|
||||
}
|
||||
```
|
||||
|
||||
Core fields:
|
||||
|
||||
|
@ -432,6 +474,7 @@ Recommended/Best Practice Fields:
|
|||
- `err`: Object. A caught JS exception. Log that thing with `log.info(err)`
|
||||
to get:
|
||||
|
||||
```js
|
||||
...
|
||||
"err": {
|
||||
"message": "boom",
|
||||
|
@ -440,6 +483,7 @@ Recommended/Best Practice Fields:
|
|||
},
|
||||
"msg": "boom",
|
||||
...
|
||||
```
|
||||
|
||||
Or use the `bunyan.stdSerializers.err` serializer in your Logger and
|
||||
do this `log.error({err: err}, "oops")`. See "examples/err.js".
|
||||
|
@ -455,6 +499,7 @@ Recommended/Best Practice Fields:
|
|||
- `req`: An HTTP server request. Bunyan provides `bunyan.stdSerializers.req`
|
||||
to serialize a request with a suggested set of keys. Example:
|
||||
|
||||
```js
|
||||
{
|
||||
"method": "GET",
|
||||
"url": "/path?q=1#anchor",
|
||||
|
@ -465,15 +510,17 @@ Recommended/Best Practice Fields:
|
|||
"remoteAddress": "120.0.0.1",
|
||||
"remotePort": 51244
|
||||
}
|
||||
```
|
||||
|
||||
- `res`: An HTTP server response. Bunyan provides `bunyan.stdSerializers.res`
|
||||
to serialize a response with a suggested set of keys. Example:
|
||||
|
||||
```js
|
||||
{
|
||||
"statusCode": 200,
|
||||
"header": "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nConnection: keep-alive\r\nTransfer-Encoding: chunked\r\n\r\n"
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Other fields to consider:
|
||||
|
||||
|
@ -494,26 +541,30 @@ interface, but there are some additional attributes used to create and
|
|||
manage the stream. A Bunyan Logger instance has one or more streams.
|
||||
In general streams are specified with the "streams" option:
|
||||
|
||||
var bunyan = require('bunyan');
|
||||
var log = bunyan.createLogger({
|
||||
name: "foo",
|
||||
streams: [
|
||||
{
|
||||
stream: process.stderr,
|
||||
level: "debug"
|
||||
},
|
||||
...
|
||||
]
|
||||
});
|
||||
```js
|
||||
var bunyan = require('bunyan');
|
||||
var log = bunyan.createLogger({
|
||||
name: "foo",
|
||||
streams: [
|
||||
{
|
||||
stream: process.stderr,
|
||||
level: "debug"
|
||||
},
|
||||
...
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
For convenience, if there is only one stream, it can specified with the
|
||||
"stream" and "level" options (internally converted to a `Logger.streams`).
|
||||
|
||||
var log = bunyan.createLogger({
|
||||
name: "foo",
|
||||
stream: process.stderr,
|
||||
level: "debug"
|
||||
});
|
||||
```js
|
||||
var log = bunyan.createLogger({
|
||||
name: "foo",
|
||||
stream: process.stderr,
|
||||
level: "debug"
|
||||
});
|
||||
```
|
||||
|
||||
Note that "file" streams do not support this shortcut (partly for historical
|
||||
reasons and partly to not make it difficult to add a literal "path" field
|
||||
|
@ -528,10 +579,12 @@ type "stream" emitting to `process.stdout` at the "info" level.
|
|||
Bunyan re-emits error events from the created `WriteStream`. So you can
|
||||
do this:
|
||||
|
||||
var log = bunyan.createLogger({name: 'mylog', streams: [{path: LOG_PATH}]});
|
||||
log.on('error', function (err, stream) {
|
||||
// Handle stream write or create error here.
|
||||
});
|
||||
```js
|
||||
var log = bunyan.createLogger({name: 'mylog', streams: [{path: LOG_PATH}]});
|
||||
log.on('error', function (err, stream) {
|
||||
// Handle stream write or create error here.
|
||||
});
|
||||
```
|
||||
|
||||
Note: This is **not** that same as a log record at the "error" level as
|
||||
produced by `log.error(...)`.
|
||||
|
@ -544,13 +597,15 @@ Stream](http://nodejs.org/docs/latest/api/all.html#writable_Stream). A
|
|||
"stream" (the writable stream) field is required. E.g.: `process.stdout`,
|
||||
`process.stderr`.
|
||||
|
||||
var log = bunyan.createLogger({
|
||||
name: 'foo',
|
||||
streams: [{
|
||||
stream: process.stderr
|
||||
// `type: 'stream'` is implied
|
||||
}]
|
||||
});
|
||||
```js
|
||||
var log = bunyan.createLogger({
|
||||
name: 'foo',
|
||||
streams: [{
|
||||
stream: process.stderr
|
||||
// `type: 'stream'` is implied
|
||||
}]
|
||||
});
|
||||
```
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
|
@ -596,13 +651,15 @@ used for anything else.</td>
|
|||
A `type === 'file'` stream requires a "path" field. Bunyan will open this
|
||||
file for appending. E.g.:
|
||||
|
||||
var log = bunyan.createLogger({
|
||||
name: 'foo',
|
||||
streams: [{
|
||||
path: '/var/log/foo.log',
|
||||
// `type: 'file'` is implied
|
||||
}]
|
||||
});
|
||||
```js
|
||||
var log = bunyan.createLogger({
|
||||
name: 'foo',
|
||||
streams: [{
|
||||
path: '/var/log/foo.log',
|
||||
// `type: 'file'` is implied
|
||||
}]
|
||||
});
|
||||
```
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
|
@ -665,21 +722,25 @@ for details.
|
|||
A `type === 'rotating-file'` is a file stream that handles file automatic
|
||||
rotation.
|
||||
|
||||
var log = bunyan.createLogger({
|
||||
name: 'foo',
|
||||
streams: [{
|
||||
type: 'rotating-file',
|
||||
path: '/var/log/foo.log',
|
||||
period: '1d', // daily rotation
|
||||
count: 3 // keep 3 back copies
|
||||
}]
|
||||
});
|
||||
```js
|
||||
var log = bunyan.createLogger({
|
||||
name: 'foo',
|
||||
streams: [{
|
||||
type: 'rotating-file',
|
||||
path: '/var/log/foo.log',
|
||||
period: '1d', // daily rotation
|
||||
count: 3 // keep 3 back copies
|
||||
}]
|
||||
});
|
||||
```
|
||||
|
||||
This will rotate '/var/log/foo.log' every day (at midnight) to:
|
||||
|
||||
/var/log/foo.log.0 # yesterday
|
||||
/var/log/foo.log.1 # 1 day ago
|
||||
/var/log/foo.log.2 # 2 days ago
|
||||
```sh
|
||||
/var/log/foo.log.0 # yesterday
|
||||
/var/log/foo.log.1 # 1 day ago
|
||||
/var/log/foo.log.2 # 2 days ago
|
||||
```
|
||||
|
||||
*Currently*, there is no support for providing a template for the rotated
|
||||
files, or for rotating when the log reaches a threshold size.
|
||||
|
@ -749,11 +810,13 @@ logrotate or `-c` with logadm) then the fd for your 'file' stream will change.
|
|||
You can tell bunyan to reopen the file stream with code like this in your
|
||||
app:
|
||||
|
||||
var log = bunyan.createLogger(...);
|
||||
...
|
||||
process.on('SIGUSR2', function () {
|
||||
log.reopenFileStreams();
|
||||
});
|
||||
```js
|
||||
var log = bunyan.createLogger(...);
|
||||
...
|
||||
process.on('SIGUSR2', function () {
|
||||
log.reopenFileStreams();
|
||||
});
|
||||
```
|
||||
|
||||
where you'd configure your log rotation to send SIGUSR2 (or some other signal)
|
||||
to your process. Any other mechanism to signal your app to run
|
||||
|
@ -779,37 +842,40 @@ own HTTP interface, or a post-mortem facility like MDB or node-panic.
|
|||
|
||||
To use a RingBuffer:
|
||||
|
||||
/* Create a ring buffer that stores the last 100 records. */
|
||||
var bunyan = require('bunyan');
|
||||
var ringbuffer = new bunyan.RingBuffer({ limit: 100 });
|
||||
var log = bunyan.createLogger({
|
||||
name: 'foo',
|
||||
streams: [
|
||||
{
|
||||
level: 'info',
|
||||
stream: process.stdout
|
||||
},
|
||||
{
|
||||
level: 'trace',
|
||||
type: 'raw', // use 'raw' to get raw log record objects
|
||||
stream: ringbuffer
|
||||
}
|
||||
]
|
||||
});
|
||||
```js
|
||||
/* Create a ring buffer that stores the last 100 records. */
|
||||
var bunyan = require('bunyan');
|
||||
var ringbuffer = new bunyan.RingBuffer({ limit: 100 });
|
||||
var log = bunyan.createLogger({
|
||||
name: 'foo',
|
||||
streams: [
|
||||
{
|
||||
level: 'info',
|
||||
stream: process.stdout
|
||||
},
|
||||
{
|
||||
level: 'trace',
|
||||
type: 'raw', // use 'raw' to get raw log record objects
|
||||
stream: ringbuffer
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
log.info('hello world');
|
||||
console.log(ringbuffer.records);
|
||||
log.info('hello world');
|
||||
console.log(ringbuffer.records);
|
||||
```
|
||||
|
||||
This example emits:
|
||||
|
||||
[ { name: 'foo',
|
||||
hostname: '912d2b29',
|
||||
pid: 50346,
|
||||
level: 30,
|
||||
msg: 'hello world',
|
||||
time: '2012-06-19T21:34:19.906Z',
|
||||
v: 0 } ]
|
||||
|
||||
```js
|
||||
[ { name: 'foo',
|
||||
hostname: '912d2b29',
|
||||
pid: 50346,
|
||||
level: 30,
|
||||
msg: 'hello world',
|
||||
time: '2012-06-19T21:34:19.906Z',
|
||||
v: 0 } ]
|
||||
```
|
||||
|
||||
## third-party streams
|
||||
|
||||
|
@ -842,12 +908,14 @@ On systems that support DTrace (e.g., MacOS, FreeBSD, illumos derivatives
|
|||
like SmartOS and OmniOS), Bunyan will create a DTrace provider (`bunyan`)
|
||||
that makes available the following probes:
|
||||
|
||||
log-trace
|
||||
log-debug
|
||||
log-info
|
||||
log-warn
|
||||
log-error
|
||||
log-fatal
|
||||
```sh
|
||||
log-trace
|
||||
log-debug
|
||||
log-info
|
||||
log-warn
|
||||
log-error
|
||||
log-fatal
|
||||
```
|
||||
|
||||
Each of these probes has a single argument: the string that would be
|
||||
written to the log. Note that when a probe is enabled, it will
|
||||
|
@ -861,86 +929,98 @@ Trace all log messages coming from any Bunyan module on the system.
|
|||
(The `-x strsize=4k` is to raise dtrace's default 256 byte buffer size
|
||||
because log messages are longer than typical dtrace probes.)
|
||||
|
||||
dtrace -x strsize=4k -qn 'bunyan*:::log-*{printf("%d: %s: %s", pid, probefunc, copyinstr(arg0))}'
|
||||
```sh
|
||||
dtrace -x strsize=4k -qn 'bunyan*:::log-*{printf("%d: %s: %s", pid, probefunc, copyinstr(arg0))}'
|
||||
```
|
||||
|
||||
Trace all log messages coming from the "wuzzle" component:
|
||||
|
||||
dtrace -x strsize=4k -qn 'bunyan*:::log-*/strstr(this->str = copyinstr(arg0), "\"component\":\"wuzzle\"") != NULL/{printf("%s", this->str)}'
|
||||
```sh
|
||||
dtrace -x strsize=4k -qn 'bunyan*:::log-*/strstr(this->str = copyinstr(arg0), "\"component\":\"wuzzle\"") != NULL/{printf("%s", this->str)}'
|
||||
```
|
||||
|
||||
Aggregate debug messages from process 1234, by message:
|
||||
|
||||
dtrace -x strsize=4k -n 'bunyan1234:::log-debug{@[copyinstr(arg0)] = count()}'
|
||||
```sh
|
||||
dtrace -x strsize=4k -n 'bunyan1234:::log-debug{@[copyinstr(arg0)] = count()}'
|
||||
```
|
||||
|
||||
Have the bunyan CLI pretty-print the traced logs:
|
||||
|
||||
dtrace -x strsize=4k -qn 'bunyan1234:::log-*{printf("%s", copyinstr(arg0))}' | bunyan
|
||||
```sh
|
||||
dtrace -x strsize=4k -qn 'bunyan1234:::log-*{printf("%s", copyinstr(arg0))}' | bunyan
|
||||
```
|
||||
|
||||
A convenience handle has been made for this:
|
||||
|
||||
bunyan -p 1234
|
||||
|
||||
```sh
|
||||
bunyan -p 1234
|
||||
```
|
||||
|
||||
On systems that support the
|
||||
[`jstack`](http://dtrace.org/blogs/dap/2012/04/25/profiling-node-js/) action
|
||||
via a node.js helper, get a stack backtrace for any debug message that
|
||||
includes the string "danger!":
|
||||
|
||||
dtrace -x strsize=4k -qn 'log-debug/strstr(copyinstr(arg0), "danger!") != NULL/{printf("\n%s", copyinstr(arg0)); jstack()}'
|
||||
```sh
|
||||
dtrace -x strsize=4k -qn 'log-debug/strstr(copyinstr(arg0), "danger!") != NULL/{printf("\n%s", copyinstr(arg0)); jstack()}'
|
||||
```
|
||||
|
||||
Output of the above might be:
|
||||
|
||||
{"name":"foo","hostname":"763bf293-d65c-42d5-872b-4abe25d5c4c7.local","pid":12747,"level":20,"msg":"danger!","time":"2012-10-30T18:28:57.115Z","v":0}
|
||||
```
|
||||
{"name":"foo","hostname":"763bf293-d65c-42d5-872b-4abe25d5c4c7.local","pid":12747,"level":20,"msg":"danger!","time":"2012-10-30T18:28:57.115Z","v":0}
|
||||
|
||||
node`0x87e2010
|
||||
DTraceProviderBindings.node`usdt_fire_probe+0x32
|
||||
DTraceProviderBindings.node`_ZN4node11DTraceProbe5_fireEN2v85LocalINS1_5ValueEEE+0x32d
|
||||
DTraceProviderBindings.node`_ZN4node11DTraceProbe4FireERKN2v89ArgumentsE+0x77
|
||||
<< internal code >>
|
||||
(anon) as (anon) at /root/node-bunyan/lib/bunyan.js position 40484
|
||||
<< adaptor >>
|
||||
(anon) as doit at /root/my-prog.js position 360
|
||||
(anon) as list.ontimeout at timers.js position 4960
|
||||
<< adaptor >>
|
||||
<< internal >>
|
||||
<< entry >>
|
||||
node`_ZN2v88internalL6InvokeEbNS0_6HandleINS0_10JSFunctionEEENS1_INS0_6ObjectEEEiPS5_Pb+0x101
|
||||
node`_ZN2v88internal9Execution4CallENS0_6HandleINS0_6ObjectEEES4_iPS4_Pbb+0xcb
|
||||
node`_ZN2v88Function4CallENS_6HandleINS_6ObjectEEEiPNS1_INS_5ValueEEE+0xf0
|
||||
node`_ZN4node12MakeCallbackEN2v86HandleINS0_6ObjectEEENS1_INS0_8FunctionEEEiPNS1_INS0_5ValueEEE+0x11f
|
||||
node`_ZN4node12MakeCallbackEN2v86HandleINS0_6ObjectEEENS1_INS0_6StringEEEiPNS1_INS0_5ValueEEE+0x66
|
||||
node`_ZN4node9TimerWrap9OnTimeoutEP10uv_timer_si+0x63
|
||||
node`uv__run_timers+0x66
|
||||
node`uv__run+0x1b
|
||||
node`uv_run+0x17
|
||||
node`_ZN4node5StartEiPPc+0x1d0
|
||||
node`main+0x1b
|
||||
node`_start+0x83
|
||||
|
||||
node`0x87e2010
|
||||
DTraceProviderBindings.node`usdt_fire_probe+0x32
|
||||
DTraceProviderBindings.node`_ZN4node11DTraceProbe5_fireEN2v85LocalINS1_5ValueEEE+0x32d
|
||||
DTraceProviderBindings.node`_ZN4node11DTraceProbe4FireERKN2v89ArgumentsE+0x77
|
||||
<< internal code >>
|
||||
(anon) as (anon) at /root/node-bunyan/lib/bunyan.js position 40484
|
||||
<< adaptor >>
|
||||
(anon) as doit at /root/my-prog.js position 360
|
||||
(anon) as list.ontimeout at timers.js position 4960
|
||||
<< adaptor >>
|
||||
<< internal >>
|
||||
<< entry >>
|
||||
node`_ZN2v88internalL6InvokeEbNS0_6HandleINS0_10JSFunctionEEENS1_INS0_6ObjectEEEiPS5_Pb+0x101
|
||||
node`_ZN2v88internal9Execution4CallENS0_6HandleINS0_6ObjectEEES4_iPS4_Pbb+0xcb
|
||||
node`_ZN2v88Function4CallENS_6HandleINS_6ObjectEEEiPNS1_INS_5ValueEEE+0xf0
|
||||
node`_ZN4node12MakeCallbackEN2v86HandleINS0_6ObjectEEENS1_INS0_8FunctionEEEiPNS1_INS0_5ValueEEE+0x11f
|
||||
node`_ZN4node12MakeCallbackEN2v86HandleINS0_6ObjectEEENS1_INS0_6StringEEEiPNS1_INS0_5ValueEEE+0x66
|
||||
node`_ZN4node9TimerWrap9OnTimeoutEP10uv_timer_si+0x63
|
||||
node`uv__run_timers+0x66
|
||||
node`uv__run+0x1b
|
||||
node`uv_run+0x17
|
||||
node`_ZN4node5StartEiPPc+0x1d0
|
||||
node`main+0x1b
|
||||
node`_start+0x83
|
||||
node`0x87e2010
|
||||
DTraceProviderBindings.node`usdt_fire_probe+0x32
|
||||
DTraceProviderBindings.node`_ZN4node11DTraceProbe5_fireEN2v85LocalINS1_5ValueEEE+0x32d
|
||||
DTraceProviderBindings.node`_ZN4node11DTraceProbe4FireERKN2v89ArgumentsE+0x77
|
||||
<< internal code >>
|
||||
(anon) as (anon) at /root/node-bunyan/lib/bunyan.js position 40484
|
||||
<< adaptor >>
|
||||
(anon) as doit at /root/my-prog.js position 360
|
||||
(anon) as list.ontimeout at timers.js position 4960
|
||||
<< adaptor >>
|
||||
<< internal >>
|
||||
<< entry >>
|
||||
node`_ZN2v88internalL6InvokeEbNS0_6HandleINS0_10JSFunctionEEENS1_INS0_6ObjectEEEiPS5_Pb+0x101
|
||||
node`_ZN2v88internal9Execution4CallENS0_6HandleINS0_6ObjectEEES4_iPS4_Pbb+0xcb
|
||||
node`_ZN2v88Function4CallENS_6HandleINS_6ObjectEEEiPNS1_INS_5ValueEEE+0xf0
|
||||
node`_ZN4node12MakeCallbackEN2v86HandleINS0_6ObjectEEENS1_INS0_8FunctionEEEiPNS1_INS0_5ValueEEE+0x11f
|
||||
node`_ZN4node12MakeCallbackEN2v86HandleINS0_6ObjectEEENS1_INS0_6StringEEEiPNS1_INS0_5ValueEEE+0x66
|
||||
node`_ZN4node9TimerWrap9OnTimeoutEP10uv_timer_si+0x63
|
||||
node`uv__run_timers+0x66
|
||||
node`uv__run+0x1b
|
||||
node`uv_run+0x17
|
||||
node`_ZN4node5StartEiPPc+0x1d0
|
||||
node`main+0x1b
|
||||
node`_start+0x83
|
||||
|
||||
node`0x87e2010
|
||||
DTraceProviderBindings.node`usdt_fire_probe+0x32
|
||||
DTraceProviderBindings.node`_ZN4node11DTraceProbe5_fireEN2v85LocalINS1_5ValueEEE+0x32d
|
||||
DTraceProviderBindings.node`_ZN4node11DTraceProbe4FireERKN2v89ArgumentsE+0x77
|
||||
<< internal code >>
|
||||
(anon) as (anon) at /root/node-bunyan/lib/bunyan.js position 40484
|
||||
<< adaptor >>
|
||||
(anon) as doit at /root/my-prog.js position 360
|
||||
(anon) as list.ontimeout at timers.js position 4960
|
||||
<< adaptor >>
|
||||
<< internal >>
|
||||
<< entry >>
|
||||
node`_ZN2v88internalL6InvokeEbNS0_6HandleINS0_10JSFunctionEEENS1_INS0_6ObjectEEEiPS5_Pb+0x101
|
||||
node`_ZN2v88internal9Execution4CallENS0_6HandleINS0_6ObjectEEES4_iPS4_Pbb+0xcb
|
||||
node`_ZN2v88Function4CallENS_6HandleINS_6ObjectEEEiPNS1_INS_5ValueEEE+0xf0
|
||||
node`_ZN4node12MakeCallbackEN2v86HandleINS0_6ObjectEEENS1_INS0_8FunctionEEEiPNS1_INS0_5ValueEEE+0x11f
|
||||
node`_ZN4node12MakeCallbackEN2v86HandleINS0_6ObjectEEENS1_INS0_6StringEEEiPNS1_INS0_5ValueEEE+0x66
|
||||
node`_ZN4node9TimerWrap9OnTimeoutEP10uv_timer_si+0x63
|
||||
node`uv__run_timers+0x66
|
||||
node`uv__run+0x1b
|
||||
node`uv_run+0x17
|
||||
node`_ZN4node5StartEiPPc+0x1d0
|
||||
node`main+0x1b
|
||||
node`_start+0x83
|
||||
```
|
||||
|
||||
# Browserify
|
||||
|
||||
|
@ -950,7 +1030,9 @@ It is a build tool to run on your node.js script to bundle up your script and
|
|||
all its node.js dependencies into a single file that is runnable in the
|
||||
browser via:
|
||||
|
||||
<script src="play.browser.js"></script>
|
||||
```html
|
||||
<script src="play.browser.js"></script>
|
||||
```
|
||||
|
||||
As of version 1.1.0, node-bunyan supports being run via Browserify. The
|
||||
default [stream](#streams) when running in the browser is one that emits
|
||||
|
@ -961,12 +1043,13 @@ script.
|
|||
|
||||
1. Get browserify and bunyan installed in your module:
|
||||
|
||||
|
||||
$ npm install browserify bunyan
|
||||
```sh
|
||||
$ npm install browserify bunyan
|
||||
```
|
||||
|
||||
2. An example script using Bunyan, "play.js":
|
||||
|
||||
```javascript
|
||||
```js
|
||||
var bunyan = require('bunyan');
|
||||
var log = bunyan.createLogger({name: 'play', level: 'debug'});
|
||||
log.trace('this one does not emit');
|
||||
|
@ -978,7 +1061,9 @@ script.
|
|||
|
||||
3. Build this into a bundle to run in the browser, "play.browser.js":
|
||||
|
||||
$ ./node_modules/.bin/browserify play.js -o play.browser.js
|
||||
```sh
|
||||
$ ./node_modules/.bin/browserify play.js -o play.browser.js
|
||||
```
|
||||
|
||||
4. Put that into an HTML file, "play.html":
|
||||
|
||||
|
@ -997,8 +1082,9 @@ script.
|
|||
|
||||
5. Open that in your browser and open your browser console:
|
||||
|
||||
$ open play.html
|
||||
|
||||
```sh
|
||||
$ open play.html
|
||||
```
|
||||
|
||||
Here is what it looks like in Firefox's console: ![Bunyan + Browserify in the
|
||||
Firefox console](./docs/img/bunyan.browserify.png)
|
||||
|
@ -1006,7 +1092,7 @@ Firefox console](./docs/img/bunyan.browserify.png)
|
|||
For some, the raw log records might not be desired. To have a rendered log line
|
||||
you'll want to add your own stream, starting with something like this:
|
||||
|
||||
```javascript
|
||||
```js
|
||||
var bunyan = require('./lib/bunyan');
|
||||
|
||||
function MyRawStream() {}
|
||||
|
@ -1031,9 +1117,6 @@ var log = bunyan.createLogger({
|
|||
log.info('hi on info');
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
# Versioning
|
||||
|
||||
The scheme I follow is most succinctly described by the bootstrap guys
|
||||
|
@ -1043,12 +1126,10 @@ tl;dr: All versions are `<major>.<minor>.<patch>` which will be incremented for
|
|||
breaking backward compat and major reworks, new features without breaking
|
||||
change, and bug fixes, respectively.
|
||||
|
||||
|
||||
# License
|
||||
|
||||
MIT. See "LICENSE.txt".
|
||||
|
||||
|
||||
# See Also
|
||||
|
||||
- Bunyan syslog support: <https://github.com/mcavage/node-bunyan-syslog>.
|
||||
|
|
Loading…
Reference in a new issue