<commit_before>Bunyan -- a JSON Logger for node.js servers.

Server logs should be structured. JSON's a good format. Let's do that: a log
record is one line of `JSON.stringify`'d output. Let's also specify some common
names for the requisite and common fields for a log record (see below).

Also: log4j is way more than you need.


# Current Status

Just play stuff here. Don't try to use this for realz yet.


# Usage

**The usual.** All loggers must provide a "service" name. This is somewhat akin
to log4j logger "name", but Bunyan doesn't so hierarchical logger names.

    $ cat hi.js
    var Logger = require('bunyan');
    var log = new Logger({service: "myapp"});
    log.info("hi");

**Log records are JSON.** "hostname", "time" and "v" (the Bunyan log
format version) are added for you.

    $ node hi.js
    {"service":"myapp","hostname":"banana.local","level":2,"msg":"hi","time":"2012-01-31T00:07:44.216Z","v":0}

A **`bunyan` tool is provided for pretty-printing** bunyan logs and, eventually,
for filtering (e.g. `| bunyan -c 'level>3'`). This shows the default output
(which is fluid right now) and indented-JSON output. More output formats will
be added, including support for custom formats.

    $ node hi.js | ./bin/bunyan  # CLI tool to filter/pretty-print JSON logs.
    [2012-01-31T00:08:11.387Z] INFO: myapp on banana.local: hi
    
    $ node hi.js | ./bin/bunyan -o json
    {
      "service": "myapp",
      "hostname": "banana.local",
      "level": 2,
      "msg": "hi",
      "time": "2012-01-31T00:10:00.676Z",
      "v": 0
    }

By default, log output is to stdout (**stream**) and at the "info" level.
Explicitly that looks like:

    var log = new Logger({service: "myapp", stream: process.stdout, 
      level: "info"});

That is an abbreviated form for a single stream. **You can defined multiple
streams at different levels**.

    var log = new Logger({
      service: "amon",
      streams: [
        {
          level: "info",
          stream: process.stdout, // log INFO and above to stdout
        },
        {
          level: "error",
          path: "tmp/error.log"   // log ERROR and above to a file
        }
      ]
    });

A **`log.clone(...)`** is provided to specialize a logger for a sub-component.
The following will have log records from "Wuzzle" instances use exactly the
same config as its parent, plus include the "component" field.

    var log = new Logger(...);

    ...
    
    function Wuzzle(options) {
      this.log = options.log;
      this.log.info("creating a wuzzle")
    }
    Wuzzle.prototype.woos = function () {
      this.log.warn("This wuzzle is woosey.")
    }
    
    var wuzzle = new Wuzzle({log: log.clone({component: "wuzzle"})});
    wuzzle.woos();
    log.info("done with the wuzzle")


Back to the `log.{trace|debug|...|fatal}(...)` API:

    log.info();     // returns a boolean: is the "info" level enabled?
    log.info("hi"); // log a simple string message
    log.info("hi %s", bob, anotherVar); // uses `util.format` for msg formatting
    log.info({foo: "bar"}, "hi");       // adds "foo" field to log record

Bunyan has a concept of **"serializers" to produce a JSON-able object from a
JavaScript object**, so your can easily do the following:

    log.info({req: <request object>}, "something about handling this request");

Association is by log record field name, "req" in this example, so this
requires a registered serializer something like this:

    function reqSerializer(req) {
      return {
        method: req.method,
        url: req.url,
        headers: req.headers
      }
    }
    var log = new Logger({
      ...
      serializers: {
        req: reqSerializer
      }
    });

Or this:

    var log = new Logger({
      ...
      serializers: {req: Logger.stdSerializers.req}
    });

because Buyan includes a small set of standard serializers. To use all the
standard serializers you can use:

    var log = new Logger({
      ...
      serializers: Logger.stdSerializers
    });


# Future

See "TODO.md", but basically:

- "Serializer" support to handle extracting a JSON object for a log record
  for particular object types, e.g. an HTTP request. So for example we
  could do:
  
        log.info({req: req}, "something about handling this request")

  And the "req" serializer would extract a reasonable JSON object for that
  request object -- presumably a subset of all attributes on the request
  object.
  
  This will key off the field name, IOW by convention, rather than getting
  into `instanceof` grossness.

- Spec'ing and enforcing the fields (from dap's section in eng guide).

- Syslog support. Ring-buffer support for storing last N debug messages<commit_msg>update readme for serializers<commit_after>Bunyan -- a JSON Logger for node.js servers.

Server logs should be structured. JSON's a good format. Let's do that: a log
record is one line of `JSON.stringify`'d output. Let's also specify some common
names for the requisite and common fields for a log record (see below).

Also: log4j is way more than you need.


# Current Status

Just play stuff here. Don't try to use this for realz yet.


# Usage

**The usual.** All loggers must provide a "service" name. This is somewhat akin
to log4j logger "name", but Bunyan doesn't so hierarchical logger names.

    $ cat hi.js
    var Logger = require('bunyan');
    var log = new Logger({service: "myapp"});
    log.info("hi");

**Log records are JSON.** "hostname", "time" and "v" (the Bunyan log
format version) are added for you.

    $ node hi.js
    {"service":"myapp","hostname":"banana.local","level":2,"msg":"hi","time":"2012-01-31T00:07:44.216Z","v":0}

A **`bunyan` tool is provided for pretty-printing** bunyan logs and, eventually,
for filtering (e.g. `| bunyan -c 'level>3'`). This shows the default output
(which is fluid right now) and indented-JSON output. More output formats will
be added, including support for custom formats.

    $ node hi.js | ./bin/bunyan  # CLI tool to filter/pretty-print JSON logs.
    [2012-01-31T00:08:11.387Z] INFO: myapp on banana.local: hi
    
    $ node hi.js | ./bin/bunyan -o json
    {
      "service": "myapp",
      "hostname": "banana.local",
      "level": 2,
      "msg": "hi",
      "time": "2012-01-31T00:10:00.676Z",
      "v": 0
    }

By default, log output is to stdout (**stream**) and at the "info" level.
Explicitly that looks like:

    var log = new Logger({service: "myapp", stream: process.stdout, 
      level: "info"});

That is an abbreviated form for a single stream. **You can defined multiple
streams at different levels**.

    var log = new Logger({
      service: "amon",
      streams: [
        {
          level: "info",
          stream: process.stdout, // log INFO and above to stdout
        },
        {
          level: "error",
          path: "tmp/error.log"   // log ERROR and above to a file
        }
      ]
    });

A **`log.clone(...)`** is provided to specialize a logger for a sub-component.
The following will have log records from "Wuzzle" instances use exactly the
same config as its parent, plus include the "component" field.

    var log = new Logger(...);

    ...
    
    function Wuzzle(options) {
      this.log = options.log;
      this.log.info("creating a wuzzle")
    }
    Wuzzle.prototype.woos = function () {
      this.log.warn("This wuzzle is woosey.")
    }
    
    var wuzzle = new Wuzzle({log: log.clone({component: "wuzzle"})});
    wuzzle.woos();
    log.info("done with the wuzzle")


Back to the `log.{trace|debug|...|fatal}(...)` API:

    log.info();     // returns a boolean: is the "info" level enabled?
    log.info("hi"); // log a simple string message
    log.info("hi %s", bob, anotherVar); // uses `util.format` for msg formatting
    log.info({foo: "bar"}, "hi");       // adds "foo" field to log record

Bunyan has a concept of **"serializers" to produce a JSON-able object from a
JavaScript object**, so your can easily do the following:

    log.info({req: <request object>}, "something about handling this request");

Association is by log record field name, "req" in this example, so this
requires a registered serializer something like this:

    function reqSerializer(req) {
      return {
        method: req.method,
        url: req.url,
        headers: req.headers
      }
    }
    var log = new Logger({
      ...
      serializers: {
        req: reqSerializer
      }
    });

Or this:

    var log = new Logger({
      ...
      serializers: {req: Logger.stdSerializers.req}
    });

because Buyan includes a small set of standard serializers. To use all the
standard serializers you can use:

    var log = new Logger({
      ...
      serializers: Logger.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
in your log record will be replaced with a short error message.*



# Future

See "TODO.md", but basically:

- More std serializers. See TODO.md.

- Spec'ing and enforcing the fields (from dap's section in eng guide).

- Syslog support. Ring-buffer support for storing last N debug messages
{'fraction_non_alphanumeric': 0.11955453652145431, 'fraction_numerical': 0.012665138115514795, 'mean_word_length': 2.7851239669421486, 'pattern_counts': {'":': 24, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2576084', 'n_tokens_mistral': 2895, 'n_tokens_neox': 2728, 'n_words': 1100}