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 🙏

© 2024 – Pkg Stats / Ryan Hefner

lean-logger

v4.0.0

Published

dead simple, fast, env configurable node.js json logging

Downloads

7

Readme

lean-logger

Lean-logger is a nodejs logger, doing only logging, only json to only console. It's configurable mainly with ENV variables. 0-dependency, 0-bullshit and based on The Twelve-Factor App methodology.

Also I think that the "severity levels" approach is suitable only to very simple application: it is clear for everyone that "severity" of the error message is higher than that of info or silly, so we can control them by setting that level to show only messages with "equal" or "bigger" levels. But it is not so easy to separate when for ex. one needs to show database layer messages and keep silent stripe library messages - both types are about debug/info level. What of them are "bigger"? How to hide one and show another?

That's why this logger does not contain levels at all - there are channels. The channel should be explicitly set as "active" via ENV var or config to output anything. Default channels are info, warn, error and fatal - they, on the contrary, should be explicitly silenced.

So ...

To Install

npm i -S lean-logger
# or
yarn add lean-logger

To Use

import { createLogger } from 'lean-logger'
const logger = createLogger()
...
  logger.warn('Hi there, got some issue', someIssueData)
  logger.info('It\'s ok now', someData)
  logger.debug('Debug info', process.env)
  ...

which prints

{"channel":"WARN","time":1629615224513,"messages":["Hi there, got some issue",{...someIssueData}]}
{"channel":"INFO","time":1629615224513,"messages":["It's ok now",{...someData}]}

logger.debug prints nothing as it's inactive by default

To Config

Empty configuration means these defaults:

const logger = createLogger({
  channels: {
    info: true,
    warn: true,
    error: true,
    fatal: true
  }
})

This default configuration is being merged with that provided by user, so

const logger = createLogger({
  http: true,
  request: true
})

implicitly results in

const logger = createLogger({
  channels: {
    info: true,
    warn: true,
    error: true,
    fatal: true,
    http: true,
    request: true
  }
})

If you want to silence default channel, e.g. info - you'll need to do it explicitly, like

const logger = createLogger({
  channels: {
    info: false,
    warn: false,
    stripe: true
  }
})

To print to non-existent channels

The logger can be used with any channel, including never defined:

const logger = createLogger()
// ... somewhere later
logger.noSuchChannel(req.ip, req.method, req.originalUrl, res.statusCode)
logger.confession('I like Old Grand-Dad Bourbon', url)

They output nothing and they don't throw anything like TypeError: "confession" is not a function. So one needs not to bother with including all possible channels in the configuration - they can be activated any time with environment variable or just kept them silent.

To configure with ENV

Use LOG env variable to manage logging

LOG=(+|-|)(channelName|all),(+|-|)(channelName|all|*),... node your-app

"-" sign to deactivate channel, "+" or nothing to activate "all" or "*" means all default channels, only makes sense with "-"

LOG=* node your-app
LOG=all node your-app

all default channels active(no need to do so)

LOG=*,+debug node your-app
LOG=+debug node your-app
LOG=debug node your-app

All default channels and debug active, so logger.debug(...) will work

LOG=-all,error,fatal node your-app

All default channels deactivated except error and fatal

LOG=-info,-warn,+http node your-app

Default channels without info and warn plus http channel

LOG=-all,confession node your-app

Default channels all dead but now everyone knows you like Bourbon.

To Extract channel and set active channels "wildly*"

import { createLogger } from 'lean-logger'
const logger = createLogger({ ... })
// extract channel to separate func
const logMigration = logger.getChannel('migration')
// ... somewhere
logMigration(`Migration ${name}, table ${table}, ${rNum} records`, someData, ...blah)

This is particularly useful combined with wild channel activation:

const logger = createLogger({ ... })
const logCard = logger.getChannel('square:card')
const logPayment = logger.getChannel('square:pmnt')
const logRefund = logger.getChannel('square:rfnd')
// ... somewhere
logCard(`User ${uid}, card updated ${cardId}, ...`, ...blah)
// ...
logPayment(`User ${uid}, card ${cardId}, payment successful...`, ...blah)
// ...
logRefund(`User ${uid}, card ${cardId}, payment ${pmntId} cancelled...`, ...blah)

To see only e.g. payments one has to activate

LOG=square:pmnt node your-app

Samely for only cards update:

LOG=square:card node your-app

And to see all logs for the square module it's enough to set

LOG=square:* node your-app

To Extend/Update channels' data

const logger = createLogger({
  channels: {
    // ...
  },
  mix: {
    channels: '*', // string or string[], channel name(s) or '*' or 'all'
    mixin: { service: 'AUTH-SERVICE' }
  })
// ... somewhere
logger.info(`User ${uid}, password updated`, ...blah)

now it outputs

{"channel":"INFO","service":"AUTH-SERVICE","time":1629615224513,"messages":["User XYZ, password upfated",{...blah}]}

The mix config parameter can be object or function that receives LoggerData and process it arbitrary way.

Bits and pieces

Async output

Those logger.anything... methods use process.stdout|stderr internally, so they are asynchronous.

Channel severity

Channels named error, fatal and fuckup output to stderr. (shouldn't it be configurable?)

Colored output

For debug fancy printing install jq then update your dev scripts in package.json like this

    "dev": "NODE_ENV=development ts-node-dev --no-notify src/server.ts",
    "dev:jq": "yarn dev 2>&1 | jq -c -R 'fromjson?'",

That 2>&1 part combines stdout and stderr, and the ... -R 'fromjson?' lets jq to ignore non-json output.