npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

good-enough

v5.0.0

Published

A good logger with useful output

Readme

good-enough

Build Status Coverage Status Dependency Status

A multiple transport logging plugin that lets you apply arbitrary transforms to incoming log events.

Supports classic DEBUG, INFO, WARN and ERROR style logging.

Usage

First, register the logger:

const Hapi = require('hapi')

const server = new Hapi.Server()
// ...
server.register({
  register: Good,
  options: {
    reporters: {
      enough: {
        module: 'good-enough',
        args: [{
          events: {
            error: '*',
            log: '*',
            request: '*',
            response: '*',
            wreck: '*',
            ops: '*'
          }
        }]
      }
    }]
  }
})

Then do some logging:

const DEBUG = require('good-enough').DEBUG
const INFO = require('good-enough').INFO
const WARN = require('good-enough').WARN
const ERROR = require('good-enough').ERROR

// give some context to the logs
const CONTEXT = 'my:request-handler'

const requestHandler = (request, reply) => {
  request.log([INFO, CONTEXT], 'Hello world')

  request.log([WARN, CONTEXT], `I can be template string: ${request.payload}`)
}

Context

You should pass two tags with your log message - a level and some context. If you don't pass these good-enough will assume that the log even is intended for a different reporter and ignore it.

request.log([INFO, CONTEXT], 'Will be logged')
request.log(['some-other-tag'], 'Will not be logged')

Setting the log level

good-enough supports the standard DEBUG < INFO < WARN < ERROR hierarchy.

It's possible to dynamically alter the log level:

const logger = require('good-enough')
const DEBUG = require('good-enough').DEBUG
const INFO = require('good-enough').INFO

// show debug logs
logger.LEVEL = DEBUG

// now debug logs will be ignored
logger.LEVEL = INFO

Log levels

It's possible to create the log level constants from strings:

const logger = require('good-enough')
const INFO = require('good-enough').INFO

console.info(INFO === logger.logLevelFromString('INFO')) // true

console.info(INFO === logger.logLevelFromString('info')) // true (not case sensitive)

Specifying message output

By default all messages are printed to process.stdout. To override this, pass one or more functions as a hash to config.transports:

const through = require('through2')

server.register({
  register: Good,
  options: {
    reporters: {
      enough: {
        module: 'good-enough',
        args: [{
          transports: {
            stdout: process.stdout.write.bind(process.stdout),
            custom: (chunk, encoding, callback) => {
              // do something with chunk/encoding and then call the callback
            }
          }
        }]
      }
    }]
  }
})

Transforming messages

Be default events are formatted and turned into strings. This has the side effect of losing information (log levels, timestamps, etc).

To define your own transforms, pass a transforms hash as an option:

const through = require('through2')

server.register({
  register: Good,
  options: {
    reporters: {
      enough: {
        module: 'good-enough',
        args: [{
          events: {
            // ...
          },
          transforms: {
            toString: function (event, callback) {
              callback(null, JSON.stringify(event))
            }
          },
          transports: {
            // ...
          }
        }]
      }
    }]
  }
})

The first transform in the hash will be passed an event object which will have some or all of the following properties:

{
  host: String, // defaults to `os.hostname()`
  pid: Number, // id of the current process
  request: String, // the id of the request that was in flight when this event was logged
  tags: Array,
  type: String, // 'wreck', 'request', 'response', 'ops', 'error' or 'log'
  timestamp: Date, // when the message was logged
  level: String, // 'INFO', 'WARN', 'ERROR' or 'DEBUG'

  // optional fields
  message: String, // a message
  context: String, // if `type` is log, the context you passed to `request.log`
  statusCode: Number, // if `type` is 'wreck' this is the response from the wreck request, if it is `response` it's the response from your app
  headers: Object // if `type` is 'wreck' this will be the response headers from the request
}

Specifying which transforms to apply to transports

By default all transforms will be applied to an event in the order they are specified. To override this, pass an array as a transport with the transport function being the last item in the array.

server.register({
  register: Good,
  options: {
    reporters: {
      enough: {
        module: 'good-enough',
        args: [{
          events: {
            // ...
          },
          transforms: {
            toString: (event, callback) => {
              callback(null, JSON.stringify(event))
            },
            overrideHostName: (event, callback) => {
              event.host = 'foo'
              callback(null, event)
            }
          },
          transports: {
            // will have toString applied to all events before passing to stdout
            stdout: ['toString', process.stdout.write.bind(process.stdout)],
            // will not have the toString transform applied to any arguments
            stderr: process.stderr.write.bind(process.stdout),
            // will have overrideHostName and toString applied sequentially to all events
            stdout: ['overrideHostName', 'toString', (chunk, encoding, callback) => {
              // ... some code here
            }],
          }
        }]
      }
    }
  }
})

Handling log events

There are a default set of event handlers available but these can be overridden:

server.register({
  register: Good,
  options: {
    reporters: {
      enough: {
        module: 'good-enough',
        args: [{
          events: {
            // ...
          },
          handlers: {
            error: (stream, event) => {
              // change `event` properties here

              stream.push(event)
            }
          }
        }]
      }
    }
  }
})