Bunyan: Fast Structured JSON Logging for Node.js

repository·master·Indexed Apr 14, 2026

https://github.com/trentm/node-bunyan

Bunyan is a fast, structured JSON logging library for Node.js services. It supports multiple streams, child loggers, custom serializers, and a CLI tool for filtering and pretty-printing logs. Features include DTrace support, source location tracking, rotating file streams, and robust error handling. The CLI handles termination signals gracefully, supports automatic paging, and allows local time formatting via the moment library. Version 1.7.0 introduced configurable error re-emission, while version 1.8.0 fixed rotating file stream initialization. The library excludes sensitive domain keys from error serialization by default to prevent OOM errors.

Tokens
34.7K
Snippets
95
Records
129
Agent score
93%

What's inside bunyan

  1. Disable Logging by Setting Level to 0

    master

    In version 1.6.0, you can disable all logging by setting the level option to 0 in createLogger.

    Usage:

    var log = bunyan.createLogger({
        name: 'foo',
        level: 0 // Disables all logging
    });

    Previously, only named levels (TRACE=10 to FATAL=60) were supported. Setting level: 0 is now the explicit way to turn logging off.

    var log = bunyan.createLogger({
        name: 'foo',
        level: 0
    });

    Sources: CHANGES.md

  2. Avoid Bad Releases: 1.1.1, 0.22.2, 0.21.2, 0.18.3

    master

    Several Bunyan releases contained critical bugs. Avoid these versions:

    • 1.1.1: Breaks log.info(err) on loggers with no serializers. Use 1.1.2+.
    • 0.22.2: Corrupted package on npm. Use 0.22.3+.
    • 0.21.2: Broke bunyan -p '*' usage. Use 0.21.3+.
    • 0.18.3: Applied serializers to all records even if the key was undefined, causing errors and junk in logs. Use 0.20.0+.

    Recommendation: Always check your Bunyan version against this list. If you are using any of these versions, upgrade immediately to the fixed version.

    Sources: CHANGES.md

  3. Change Logger Name Field

    master

    In version 0.5.0, the service field was renamed to name in Logger creation options. This change aligns with log4j Logger naming conventions and removes the tie to service-specific usage.

    Use name instead of service:

    var log = new bunyan.Logger({
        name: 'myapp',
        level: 'info'
    });
    var log = new bunyan.Logger({
        name: 'myapp',
        level: 'info'
    });

    Sources: CHANGES.md

  4. Measure Performance Overhead of Source Location Tracking

    master

    Use the tools/timesrc.js script to benchmark the performance cost of enabling source location tracking (src: true) in Bunyan loggers. This script compares the execution time of log.info() calls with and without the src option enabled.

    Prerequisites:

    • Install the ben benchmarking library: npm install ben

    Usage: Run the script from the repository root:

    node tools/timesrc.js

    Output: The script prints the milliseconds per iteration for:

    • log.info with src: true
    • log.info without src

    This helps you decide if the overhead of capturing call source info (file, line, function) is acceptable for your application's logging performance requirements.

    #!/usr/bin/env node
    /*
     * Time 'src' fields (getting log call source info). This is expensive.
     */
    
    console.log('Time adding "src" field with call source info:');
    
    var ben = require('ben');  // npm install ben
    var Logger = require('../lib/bunyan');
    
    var records = [];
    function Collector() {
    }
    Collector.prototype.write = function (s) {
        //records.push(s);
    }
    var collector = new Collector();
    
    var logwith = new Logger({
        name: 'with-src',
        src: true,
        stream: collector
    });
    
    var ms = ben(1e5, function () {
        logwith.info('hi');
    });
    console.log(' - log.info with    src:  %dms per iteration', ms);
    
    var logwithout = new Logger({
        name: 'without-src',
        stream: collector
    });
    var ms = ben(1e5, function () {
        logwithout.info('hi');
    });
    console.log(' - log.info without src:  %dms per iteration', ms);

    Sources: tools/timesrc.js

  5. Use `bunyan -0` Shortcut for JSON Output

    master

    Bunyan 1.0.0 added a shortcut for the JSON output format. Instead of typing bunyan -o bunyan, you can use bunyan -0.

    Usage:

    bunyan -0 foo.log

    This is equivalent to:

    bunyan -o bunyan foo.log

    The bunyan output format is the same as json-0 but with a more convenient name.

    bunyan -0 foo.log

    Sources: CHANGES.md

  6. Create a Custom Stream to Mute Logs via Environment Variables

    master

    You can create a custom Bunyan stream to filter out log records based on environment variables. This allows you to mute specific log entries without modifying the core library.

    How it works:

    1. Define a custom stream class (e.g., MuteByEnvVars) that implements a write method.
    2. The stream scans process.env for keys starting with BUNYAN_MUTE_.
    3. When a log record is written, the stream checks if any field in the record matches the corresponding environment variable value.
    4. If a match is found, the record is suppressed (muted). Otherwise, it is written to the underlying stream.

    Usage Pattern:

    • Set environment variables in the format BUNYAN_MUTE_<field_path>=<value> before running your script.
    • Use dot notation for nested fields (e.g., BUNYAN_MUTE_user.id=123).
    • Attach the custom stream to your logger with type: 'raw'.

    Example:

    var bunyan = require('bunyan');
    
    function MuteByEnvVars(opts) {
        opts = opts || {};
        this.stream = opts.stream || process.stdout;
        var PREFIX = 'BUNYAN_MUTE_';
        this.mutes = {};
        for (var k in process.env) {
            if (k.indexOf(PREFIX) === 0) {
                this.mutes[k.slice(PREFIX.length)] = process.env[k];
            }
        }
    }
    
    MuteByEnvVars.prototype._objectFromDotNotation = function (o, s) {
        s = s.replace(/\[(\w+)\]/g, '.$1');
        s = s.replace(/^\./, '');
        var a = s.split('.');
        while (a.length) {
            var n = a.shift();
            if (n in o) {
                o = o[n];
            } else {
                return;
            }
        }
        return o;
    }
    
    MuteByEnvVars.prototype.write = function (rec) {
        if (typeof (rec) !== 'object') {
            console.error('error: MuteByEnvVars raw stream got a non-object record: %j', rec);
            return;
        }
        var muteRec = false;
        var keys = Object.keys(this.mutes);
        for (var i = 0; i < keys.length; i++) {
            var k = keys[i];
            var match = this._objectFromDotNotation(rec, k);
            if (match === this.mutes[k]) {
                muteRec = true;
                break;
            }
        }
        if (!muteRec) {
            this.stream.write(JSON.stringify(rec) + '\n');
        }
    }
    
    var log = bunyan.createLogger({
        name: 'mute-by-envvars-stream',
        streams: [
            {
                level: 'info',
                stream: new MuteByEnvVars(),
                type: 'raw'
            }
        ]
    });
    
    log.info('hi raw stream');
    log.info({foo: 'bar'}, 'added "foo" key');

    Running with Mute Rules: To mute logs containing {foo: 'bar'}:

    BUNYAN_MUTE_foo=bar node mute-by-envvars-stream.js

    Notes:

    • This is a custom implementation and may not be optimized for performance or edge cases.
    • Nested fields must be accessed using dot notation in the environment variable key (e.g., BUNYAN_MUTE_user.name=John).
    • The stream treats all environment variable values as strings.
    var bunyan = require('bunyan');
    
    function MuteByEnvVars(opts) {
        opts = opts || {};
        this.stream = opts.stream || process.stdout;
        var PREFIX = 'BUNYAN_MUTE_';
        this.mutes = {};
        for (var k in process.env) {
            if (k.indexOf(PREFIX) === 0) {
                this.mutes[k.slice(PREFIX.length)] = process.env[k];
            }
        }
    }
    
    MuteByEnvVars.prototype._objectFromDotNotation = function (o, s) {
        s = s.replace(/\[(\w+)\]/g, '.$1');
        s = s.replace(/^\./, '');
        var a = s.split('.');
        while (a.length) {
            var n = a.shift();
            if (n in o) {
                o = o[n];
            } else {
                return;
            }
        }
        return o;
    }
    
    MuteByEnvVars.prototype.write = function (rec) {
        if (typeof (rec) !== 'object') {
            console.error('error: MuteByEnvVars raw stream got a non-object record: %j', rec);
            return;
        }
        var muteRec = false;
        var keys = Object.keys(this.mutes);
        for (var i = 0; i < keys.length; i++) {
            var k = keys[i];
            var match = this._objectFromDotNotation(rec, k);
            if (match === this.mutes[k]) {
                muteRec = true;
                break;
            }
        }
        if (!muteRec) {
            this.stream.write(JSON.stringify(rec) + '\n');
        }
    }
    
    var log = bunyan.createLogger({
        name: 'mute-by-envvars-stream',
        streams: [
            {
                level: 'info',
                stream: new MuteByEnvVars(),
                type: 'raw'
            }
        ]
    });
    
    log.info('hi raw stream');
    log.info({foo: 'bar'}, 'added "foo" key');

    Sources: examples/mute-by-envvars-stream.js

  7. Enable Source Location

    master

    Include the source location (file, line, function) in log records by setting src: true in the logger configuration.

    var log = bunyan.createLogger({
        name: 'myapp',
        src: true
    });

    This adds source information to each log record, which is useful for debugging.

    var log = bunyan.createLogger({
        name: 'myapp',
        src: true
    });

    Sources: README.md

  8. Configure Bunyan for Webpack

    master

    To use Bunyan with Webpack, you must exclude optional dependencies that are unavailable in browser environments. Configure Webpack to mark these dependencies as externals in your webpack.config.js:

    module.exports = {
      // ... other config
      externals: {
        'dtrace-provider': 'commonjs dtrace-provider',
        'mkdirp': 'commonjs mkdirp',
        'rimraf': 'commonjs rimraf',
        'semver': 'commonjs semver',
        'streamroller': 'commonjs streamroller'
      }
    };

    This prevents Webpack from bundling these Node.js-specific modules, allowing Bunyan to function correctly in the browser environment.

    module.exports = {
      externals: {
        'dtrace-provider': 'commonjs dtrace-provider',
        'mkdirp': 'commonjs mkdirp',
        'rimraf': 'commonjs rimraf',
        'semver': 'commonjs semver',
        'streamroller': 'commonjs streamroller'
      }
    };

    Sources: README.md

  9. Use Fast Child Logger Creation

    master

    The log.child(options, true) method provides a 'fast child' path that asserts the options only add fields (no configuration changes). This results in a 10x speed increase in child creation compared to the regular log.child.

    Use this when creating child loggers frequently (e.g., per request) to minimize overhead:

    var child = log.child({ userId: 123 }, true);
    var child = log.child({ userId: 123 }, true);

    Sources: CHANGES.md

  10. Fix for Child Logger Hostname Override

    master

    In version 1.6.0, log.child() was fixed to not override the hostname field of the parent logger. This is useful if you manually set a custom hostname in your parent logger configuration.

    Before 1.6.0: Calling log.child() might have reset the hostname to os.hostname(). After 1.6.0: The child logger inherits the parent's hostname unless explicitly overridden in the child's options.

    Sources: CHANGES.md

  11. Export RotatingFileStream for Customization

    master

    In version 1.3.1, bunyan.RotatingFileStream was exported. This allows you to customize the rotating file stream behavior if needed.

    Usage:

    var bunyan = require('bunyan');
    var RotatingFileStream = bunyan.RotatingFileStream;
    
    // Use RotatingFileStream for custom configuration
    var log = bunyan.createLogger({
        name: 'my-app',
        streams: [{
            type: 'rotating-file',
            path: '/var/log/my-app.log',
            // Custom options passed to RotatingFileStream
        }]
    });

    Refer to issue #194 for examples of customization.

    Sources: CHANGES.md

  12. Create a Logger

    master

    Create a logger instance by requiring bunyan and calling createLogger with a configuration object. The name field is required.

    var bunyan = require('bunyan');
    var log = bunyan.createLogger({
        name: 'myapp',
        level: 'info',
        stream: process.stdout
    });

    Configuration Options:

    • name (string, required): The logger name.
    • level (string or number, optional): The minimum log level (see Levels).
    • stream (node.js stream, optional): A single output stream (e.g., process.stdout).
    • streams (array, optional): Multiple streams with different levels.
    • serializers (object, optional): Custom serializers for objects.
    • src (boolean, optional): Include source location (file, line, function).
    • Any other fields are added to all log records.

    Example with multiple streams:

    var log = bunyan.createLogger({
      name: 'myapp',
      streams: [
        {
          level: 'info',
          stream: process.stdout
        },
        {
          level: 'error',
          path: '/var/tmp/myapp-error.log'
        }
      ]
    });
    var bunyan = require('bunyan');
    var log = bunyan.createLogger({name: 'myapp'});

    Sources: README.md