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

@nextrush/log

v0.3.0

Published

Universal, zero-dependency, production-grade logger for modern JavaScript runtimes

Readme

@nextrush/log

Universal logging for modern JavaScript.

Zero dependencies • Tree-shakeable • Production-ready

Node.js • Bun • Deno • Browser • React • Next.js • Edge

npm bundle license docs


Why @nextrush/log?

  • 🎯 One config controls ALL loggers — call configure() once, every createLogger() obeys it
  • 🚀 Zero dependencies — no bloat, no supply-chain risk
  • 🌍 Universal — same API on Node, Bun, Deno, edge runtimes, and the browser
  • 🔒 Production-safe by default — auto-redaction, log-injection sanitization, and a fail-safe default (redaction stays ON if the runtime environment can't be detected)
  • 📦 Small, deliberate public API — ~20 exports total, not hundreds of internal helpers leaking through

📖 Documentation · 📋 Changelog


Install

npm install @nextrush/log

Coming from v0.2.x? v0.3.0 is a breaking release that removes redundant/internal exports. See CHANGELOG.md for the full migration list.


Quick Start

import { createLogger } from '@nextrush/log';

const log = createLogger('MyApp');

log.info('Server started', { port: 3000 });
log.warn('High memory', { used: '85%' });
log.error('Failed', new Error('timeout'));

Development — pretty, colorful output:

10:30:00 INFO  [MyApp] Server started { port: 3000 }
10:30:01 WARN  [MyApp] High memory { used: '85%' }
10:30:02 ERROR [MyApp] Failed Error: timeout

Production — structured JSON for log aggregators (Datadog, CloudWatch, etc.):

{"timestamp":"2026-01-15T10:30:00.000Z","level":"info","context":"MyApp","message":"Server started","data":{"port":3000}}

Central Control

One call controls every logger created anywhere in your app.

// app-entry.ts — configure ONCE at startup
import { configure, disableLogging } from '@nextrush/log';

// Disable ALL logging instantly, from any file
disableLogging();

// Or configure globally
configure({
  enabled: process.env.NODE_ENV !== 'test',
  minLevel: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
});

Every createLogger() call anywhere in the codebase — in this file or any other — reads that same global config live. No dependency injection, no prop-drilling a logger instance through 500 files.


Log Levels

| Level | Priority | Use Case | |-------|:--------:|----------| | trace | 0 | Detailed debugging | | debug | 1 | Development info | | info | 2 | Normal operations ← production default | | warn | 3 | Potential issues | | error | 4 | Recoverable errors | | fatal | 5 | Critical failures |

const log = createLogger('App', { minLevel: 'warn' });

log.debug('ignored');  // ❌ below warn
log.warn('logged');    // ✅
log.error('logged');   // ✅

The effective minimum level is the stricter of the global configure({ minLevel }) floor and each logger's own minLevel.


Environment Behavior

| Setting | Development | Production | |---------|:-----------:|:----------:| | minLevel | trace | info | | Output | Pretty + colors | JSON | | Redaction | Off | On |

Environment is auto-detected from NODE_ENV (and Vite's MODE/PROD/DEV). If no signal is available at all (common on some edge/serverless runtimes), redaction defaults to on rather than silently turning it off — logging must never become a data leak just because a platform doesn't expose NODE_ENV.

// Auto-detects
const log = createLogger('App');

// Or force it explicitly
const log = createLogger('App', { env: 'production' });

Features

Namespace Filtering (Large Codebases)

import { configure, createLogger } from '@nextrush/log';

// Only log from specific modules
configure({ enabledNamespaces: ['api:*', 'auth:*'] });

createLogger('api:users').info('Logged');     // ✅
createLogger('db:queries').info('Ignored');   // ❌

Child Loggers

const log = createLogger('App');
const db = log.child('Database');

db.info('Connected');  // [App:Database] Connected

Request Tracing

const requestLog = log.withCorrelationId('req-abc123');
requestLog.info('Processing');
// Output includes: "correlationId": "req-abc123"

Performance Timing

const timer = log.time('db-query');
await db.query('SELECT * FROM users');
timer.end('Done', { rows: 100 });
// "Done" { duration: 42, rows: 100 }

Auto-Redaction

log.info('Login', {
  email: '[email protected]',
  password: 'secret123',  // → "[REDACTED]"
  token: 'xyz',            // → "[REDACTED]"
});

Redaction matches whole key tokens (camelCase/snake_case/kebab-case aware), so it catches apiKey/secret_token without over-redacting unrelated fields like primaryKey or passport.

Custom Transports

import { createBatchTransport } from '@nextrush/log';

const { transport, flush } = createBatchTransport(
  async (logs) => fetch('/api/logs', {
    method: 'POST',
    body: JSON.stringify(logs)
  }),
  { batchSize: 50, flushInterval: 5000 }
);

log.addTransport(transport);

Async Context Propagation

import { createContextMiddleware, runWithContext } from '@nextrush/log';

// Express/Koa-style middleware
app.use(createContextMiddleware((req) => ({
  correlationId: req.headers['x-request-id'],
  metadata: { userId: req.user?.id },
})));

// Or manually
await runWithContext({ correlationId: 'req-123' }, async () => {
  log.info('Every log in here automatically gets correlationId: req-123');
});

Uses AsyncLocalStorage on Node; on runtimes without it, context propagation is scoped to avoid cross-request state bleed rather than falling back to unsafe shared state.


Browser & React

import { createLogger } from '@nextrush/log';

const log = createLogger('App');
log.info('Works in the browser too — same API.');

Optional browser-specific helpers (error capture, beacon transport for page-unload delivery):

import { setupBrowserLogging } from '@nextrush/log/browser';

const { logger, cleanup } = setupBrowserLogging({ context: 'MyApp' });

React integration:

import { LoggerProvider, useLogger } from '@nextrush/log/react';

function App() {
  return (
    <LoggerProvider context="MyApp">
      <MyComponent />
    </LoggerProvider>
  );
}

function MyComponent() {
  const log = useLogger('MyComponent');
  return <button onClick={() => log.info('Clicked!')}>Click</button>;
}

Testing Your Code

import { createMockLogger, expectLogged } from '@nextrush/log/testing';

const mockLog = createMockLogger();
myFunction(mockLog);

expectLogged(mockLog, 'info', 'Operation completed');

The mock logger parses arguments identically to the real Logger, so assertions against it match production behavior.


API Quick Reference

| Function | Description | |----------|-------------| | createLogger(name, options?) | Create a logger instance | | log | Default pre-built logger instance | | configure(options) | Set global configuration | | disableLogging() | Disable ALL logging globally | | addGlobalTransport(fn) | Add a transport to ALL loggers | | createBatchTransport(...) | Buffer + flush logs on an interval/size threshold | | createFilteredTransport(...) | Only forward logs at/above a minimum level | | createRateLimitedTransport(...) | Token-bucket rate limiting for a transport | | runWithContext(ctx, fn) | Run code with async correlation-ID/metadata context | | createContextMiddleware(fn) | Express/Koa-style middleware for runWithContext | | getAsyncContext() | Read the current async context |

| Logger Method | Description | |---------------|-------------| | log.trace/debug/info/warn/error/fatal() | Log at a level | | log.child(name) | Create a child logger | | log.withCorrelationId(id) | Add a correlation ID | | log.withMetadata(data) | Add metadata to all subsequent logs | | log.time(label?) | Start a performance timer | | log.setLevel(level) | Change the minimum level at runtime | | log.isLevelEnabled(level) | Check if a level would log | | log.addTransport(fn) | Add a custom transport to this logger |

Additional configuration fields, submodule internals, and less-common helpers still exist — see CHANGELOG.md and the API reference for the full surface.


Documentation


License

MIT © Tanzim Hossain