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

nlogs

v2.5.3

Published

Structured logger for Node.js with category-based filtering, AsyncLocalStorage trace IDs, and built-in timers and counters. Configurable through environment variables - no setup code in most cases.

Readme

nlogs

Structured logger for Node.js with category-based filtering, AsyncLocalStorage trace IDs, and built-in timers and counters. Configurable through environment variables - no setup code in most cases.

Installation

Requires Node.js 20 or newer.

npm install nlogs

Quick start

import Logger from 'nlogs'

const logger = new Logger()

logger.info('server started', { port: 3000 })
logger.error(new Error('boom'))

The dark ANSI formatter is used in development and switches to json when NODE_ENV=production.

Log levels

trace -> debug -> log -> info -> warn -> error -> fatal

warn, error, and fatal are written to stderr; the rest go to stdout. fatal is always emitted regardless of filtering.

Filter at runtime:

NLOGS_LEVEL=warn node app.js          # warn, error, fatal
NLOGS_LEVELS=info,error node app.js   # exact set
NLOGS_LEVEL=off node app.js           # silence everything except fatal

Categories

Each logger instance has a category. By default it is derived from the source file path. Pass a class, an explicit string, or module/import.meta to override:

class UserService {}
const log = new Logger(UserService)

Filter categories with NLOGS_CATEGORY (syntax mirrors debug: comma-separated entries, leading - for negation, module:category for module-scoped rules, * for everything):

NLOGS_CATEGORY="auth, payments, -auth:internal" node app.js

Trace context

Logger.run opens an AsyncLocalStorage context. Every log inside the callback - and any async work it spawns - carries the same traceId and shared details.

A string argument sets the traceId directly:

Logger.run(req.headers['x-trace-id'], () => handler(req))

An object argument generates a fresh traceId and attaches arbitrary fields to details:

Logger.run({ userId: '42' }, async () => {
  logger.info('handling request')
  await processOrder()
})

Pass traceId explicitly to combine both:

Logger.run({ traceId: 'abc-123', userId: '42' }, () => handler())

Nested calls chain: the outer traceId is preserved in _traceIds.

Timers and counters

logger.time('db')
await query()
logger.timeEnd('db')

const counter = logger.count('events')
counter.log()    // increments and logs
counter.log()
counter.end()    // closes the counter

logger.time(label) and logger.count(label) return a handle with .log() and .end() methods. Calling the handle itself (counter()) is equivalent to .end(). Without a label each call returns a fresh handle. Repeated logger.count(label) with the same label keeps incrementing the same counter until .end().

Formatters

| Value | When to use | |----------|-----------------------------------------| | dark | Terminal with dark background (default) | | light | Terminal with light background | | string | Plain text, no ANSI | | json | One JSON object per line (prod default) |

Override with NLOGS_FORMATTER.

Environment variables

Naming convention: NLOGS_* (preferred), LOGGER_* (fallback), unprefixed (compatibility with DEBUG, LEVEL, CATEGORY, ...).

| Variable | Purpose | |----------------------------|----------------------------------------| | NLOGS_PROJECT | Project name in meta | | NLOGS_SERVICE | Service name in meta | | NLOGS_CATEGORY | Category allow/deny list | | NLOGS_DEBUG | Same syntax for debug/trace levels | | NLOGS_LEVEL | Minimum level (or exact level) | | NLOGS_LEVELS | Exact set of allowed levels | | NLOGS_FORMATTER | json/string/light/dark | | NLOGS_STRICT_LEVEL_RULES | Pre-filter by level (bool) |

DEBUG=* and NODE_DEBUG=* are honoured as aliases for NLOGS_DEBUG.

NestJS adapter

import { NestjsLogger } from 'nlogs'

const app = await NestFactory.create(AppModule, {
  logger: new NestjsLogger(),
})

Template logger

TemplateLogger injects a fixed template applied to every message. Use it as a tagged template literal where each ${...} can be a plain value or a function that receives the current LogInfo and returns the substituted value:

import { TemplateLogger } from 'nlogs'

const logger = new TemplateLogger('http')
logger.template`[${info => info.meta.level}] ${info => info.message}`

logger.info('request received')

License

MIT - see LICENSE.