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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@omdxp/jslog

v1.9.0

Published

Structured logging for Node.js that makes Go's log/slog look basic. Features file rotation, buffering, sampling, filtering, async handlers, middleware, and 20+ features Go slog doesn't have!

Downloads

397

Readme

@omdxp/jslog

A structured logging library for Node.js that makes Go's log/slog look basic.

Why jslog?

  • Everything Go's slog has + variadic parameters (NEW in v1.7.0!)
  • Plus 20+ features Go slog doesn't have
  • File logging with auto-rotation
  • Buffering, sampling, filtering
  • Async handlers
  • Middleware pattern
  • Metrics collection
  • Rate limiting & deduplication
  • Colorful output
  • And way more...

See full comparison in SUPERIORITY.md

Features

Core Features (Like Go slog)

  • Structured Logging: Key-value pairs for easy parsing and analysis
  • Multiple Handlers: JSON, Text, Multi, and Discard handlers
  • Log Levels: DEBUG, INFO, WARN, ERROR with dynamic level control
  • Contextual Logging: Add persistent attributes and groups to loggers
  • TypeScript First: Full type safety and IntelliSense support
  • Modern Build System: Built with tsup and tsx
  • Custom Handlers: Easy to implement custom log handlers
  • Attribute Transformation: ReplaceAttr function for redacting or transforming values
  • Rich Attribute Types: String, Int, Float, Bool, Time, Duration, Group, Error, and more
  • Nested Groups: Organize related attributes hierarchically
  • Dynamic Levels: Change log levels at runtime with LevelVar

Advanced Features (Go slog can't do this!)

  • Source Location Tracking: Automatic file/line tracking with zero dependencies
  • ColorHandler: Beautiful, colorful console output
  • PrettyHandler: Format nested objects with proper indentation
  • FileHandler: Write to files with automatic rotation
  • BufferedHandler: Batch logs for performance
  • SamplingHandler: Log only a percentage of messages
  • FilterHandler: Conditional logging based on custom logic
  • AsyncHandler: Non-blocking log operations
  • Middleware Pattern: Compose handlers with middleware
  • Metrics: Built-in logging statistics
  • Deduplication: Prevent log spam automatically
  • Rate Limiting: Automatic rate limiting
  • Fluent API: Chain attributes with AttrBuilder
  • Performance Timers: Built-in timing utilities
  • Correlation IDs: Global request/trace tracking
  • HTTP Helpers: Easy request/response logging
  • System Info: Environment and memory helpers
  • Data Masking: Built-in PII redaction
  • Stack Traces: Automatic stack trace capture
  • Error Boundaries: Catch handler errors safely

Installation

npm install @omdxp/jslog

Quick Start

import { info, warn, error, String, Int } from '@omdxp/jslog';

// Go slog-style variadic parameters (NEW in v1.7.0!)
info('Application started', 'env', 'production', 'port', 3000);
warn('High memory usage', 'percentage', 85);
error('Failed to connect', 'host', 'localhost');

// Traditional style (still works)
info('Application started', String('env', 'production'), Int('port', 3000));

// Mix both styles!
info('Mixed', String('typed', 'value'), 'key', 'value');

Usage

Basic Logging

import { Logger, TextHandler, Level, String, Int } from '@omdxp/jslog';

const logger = new Logger(new TextHandler({ level: Level.DEBUG }));

// Go slog-style (NEW in v1.7.0!)
logger.info('User logged in', 'user', 'alice', 'ip', '192.168.1.1');
logger.warn('Rate limit exceeded', 'requests', 1000);
logger.error('Database connection failed', 'error', 'timeout');

// Traditional style
logger.info('User logged in', String('user', 'alice'), String('ip', '192.168.1.1'));
logger.warn('Rate limit exceeded', Int('requests', 1000));
logger.error('Database connection failed', String('error', 'timeout'));

All Attribute Types

import { String, Int, Int64, Float64, Bool, Time, Duration, Any, Group } from '@omdxp/jslog';

// Go slog-style variadic (automatically inferred types)
logger.info('Event',
  'name', 'user.created',
  'userId', 42,
  'score', 98.5,
  'verified', true,
  'metadata', { plan: 'pro' }
);

// Traditional typed style (explicit type control)
logger.info('Event',
  String('name', 'user.created'),
  Int('userId', 42),
  Int64('bigNumber', 9007199254740991),
  Float64('score', 98.5),
  Bool('verified', true),
  Time('createdAt', new Date()),
  Duration('elapsed', 1500), // in milliseconds
  Any('metadata', { plan: 'pro' }),
  Group('address', 
    String('city', 'NYC'),
    String('country', 'USA')
  )
);

JSON Output

import { JSONHandler, New } from '@omdxp/jslog';

const logger = New(new JSONHandler());
logger.info('Request processed', String('method', 'GET'), Int('status', 200));
// Output: {"time":"2024-01-01T00:00:00.000Z","level":"INFO","msg":"Request processed","method":"GET","status":200}

Contextual Logging

// Add persistent attributes
const requestLogger = logger.with(String('request_id', '123-456'));
requestLogger.info('Processing request');
requestLogger.info('Request completed');

// Group related attributes
const dbLogger = logger.withGroup('database');
dbLogger.info('Connected', String('host', 'localhost'));
// Output: time=... level=INFO msg="Connected" database.host="localhost"

Attribute Helpers

import { String, Int, Bool, Any, Error as ErrorAttr } from '@omdxp/jslog';

logger.info('Event',
  String('name', 'user.created'),
  Int('userId', 42),
  Bool('verified', true),
  Any('metadata', { plan: 'pro' })
);

try {
  throw new Error('Something went wrong');
} catch (err) {
  logger.error('Operation failed', ErrorAttr(err as Error));
}

Dynamic Log Levels

import { LevelVar, TextHandler } from '@omdxp/jslog';

const levelVar = new LevelVar(Level.INFO);
const logger = new Logger(new TextHandler({ level: levelVar }));

logger.debug('Not visible'); // Won't show
logger.info('Visible');      // Will show

// Change level at runtime
levelVar.set(Level.DEBUG);
logger.debug('Now visible!'); // Will show

Multiple Handlers

import { MultiHandler, TextHandler, JSONHandler } from '@omdxp/jslog';

const textHandler = new TextHandler({ level: Level.INFO });
const jsonHandler = new JSONHandler({ level: Level.WARN });
const multiHandler = new MultiHandler([textHandler, jsonHandler]);

const logger = new Logger(multiHandler);
logger.info('Only in text');        // TextHandler only
logger.warn('In both formats');     // Both handlers
logger.error('In both formats');    // Both handlers

Attribute Transformation

import { TextHandler } from '@omdxp/jslog';

const logger = new Logger(new TextHandler({
  level: Level.INFO,
  replaceAttr: (groups, attr) => {
    // Redact sensitive fields
    if (attr.key === 'password' || attr.key === 'token') {
      return { key: attr.key, value: '***REDACTED***' };
    }
    // Transform time format
    if (attr.key === 'time' && attr.value instanceof Date) {
      return { key: attr.key, value: attr.value.toLocaleString() };
    }
    return attr;
  }
}));

logger.info('Login', String('user', 'alice'), String('password', 'secret'));
// Output: ... user="alice" password="***REDACTED***"

Discard Handler

import { DiscardHandler } from '@omdxp/jslog';

// Useful for benchmarking or disabling logging
const logger = new Logger(new DiscardHandler());
logger.info('This will be discarded'); // No output

Source Location Tracking

Track where log messages originate in your code with zero runtime dependencies:

import { Logger, TextHandler, JSONHandler, Level, String } from '@omdxp/jslog';

// Enable source tracking with addSource option
const logger = new Logger(new TextHandler({ 
  level: Level.INFO, 
  addSource: true 
}));

logger.info('User action', String('action', 'login'));
// Output: time=... level=INFO source=app.ts:8 msg="User action" action="login"

// Works with JSON output too
const jsonLogger = new Logger(new JSONHandler({ addSource: true }));
jsonLogger.warn('High memory', String('usage', '85%'));
// Output: {"time":"...","level":"WARN","source":{"function":"checkMemory","file":"app.ts","line":15},...}

// Source tracking in nested functions
function processOrder(orderId: number) {
  logger.info('Processing order', String('id', orderId));
  // Shows the actual line where this log call is made
}

// Works in class methods too
class UserService {
  private logger = new Logger(new JSONHandler({ addSource: true }));
  
  createUser(name: string) {
    this.logger.info('Creating user', String('name', name));
    // Source shows: UserService.createUser at line X
  }
}

Features:

  • Zero Dependencies: No runtime dependencies, pure stack trace parsing
  • TypeScript Support: Shows .ts files during development with tsx/ts-node
  • Production Ready: Shows compiled .js files in production
  • Smart Filtering: Automatically skips jslog internal frames to show your code
  • Function Names: Captures function/method names when available
  • Relative Paths: Shows paths relative to cwd for cleaner output

When to use:

  • Development and debugging
  • Troubleshooting production issues
  • Audit logging where source location matters
  • Understanding code flow in complex applications

Note: Source tracking adds minimal overhead (one stack trace capture per log call). Only enable it when needed using the addSource handler option.

API Reference

Loggers

  • Default() - Get the default logger
  • SetDefault(logger) - Set the default logger
  • New(handler) - Create a new logger with a handler

Log Levels

enum Level {
  DEBUG = -4,
  INFO = 0,
  WARN = 4,
  ERROR = 8,
}

Handlers

  • TextHandler - Human-readable text format
  • JSONHandler - Structured JSON format
  • MultiHandler - Send to multiple handlers
  • DiscardHandler - Discard all logs (for testing/benchmarking)

Handler Options

interface HandlerOptions {
  level?: Level | LevelVar;           // Minimum log level
  addSource?: boolean;                // Add source location
  replaceAttr?: (groups, attr) => Attr; // Transform attributes
}

Logger Methods

  • log(level, msg, ...attrs) - Log at specific level
  • logAttrs(level, msg, ...attrs) - Efficient logging variant
  • debug(msg, ...attrs) - Log at DEBUG level
  • debugContext(msg, ...attrs) - Debug with context (future)
  • info(msg, ...attrs) - Log at INFO level
  • infoContext(msg, ...attrs) - Info with context (future)
  • warn(msg, ...attrs) - Log at WARN level
  • warnContext(msg, ...attrs) - Warn with context (future)
  • error(msg, ...attrs) - Log at ERROR level
  • errorContext(msg, ...attrs) - Error with context (future)
  • with(...attrs) - Create logger with persistent attributes
  • withGroup(name) - Create logger with attribute group
  • enabled(level) - Check if level is enabled

Attribute Functions

  • String(key, value) - String attribute
  • Int(key, value) - Integer attribute
  • Int64(key, value) - 64-bit integer attribute
  • Uint64(key, value) - Unsigned 64-bit integer attribute
  • Float64(key, value) - Float attribute
  • Bool(key, value) - Boolean attribute
  • Time(key, date) - Date/time attribute
  • Duration(key, ms) - Duration in milliseconds
  • Any(key, value) - Any value attribute
  • Group(key, ...attrs) - Group attributes
  • Error(err) - Error attribute with stack trace
  • attr(key, value) - Generic attribute constructor

Convenience Functions

  • debug(msg, ...attrs) - Log at DEBUG level
  • debugContext(msg, ...attrs) - Debug with context
  • info(msg, ...attrs) - Log at INFO level
  • infoContext(msg, ...attrs) - Info with context
  • warn(msg, ...attrs) - Log at WARN level
  • warnContext(msg, ...attrs) - Warn with context
  • error(msg, ...attrs) - Log at ERROR level
  • errorContext(msg, ...attrs) - Error with context
  • log(level, msg, ...attrs) - Log at specific level
  • logAttrs(level, msg, ...attrs) - Efficient variant
  • with_(...attrs) - Get default logger with attributes
  • withGroup(name) - Get default logger with group

Development

# Install dependencies
npm install

# Run tests (validates all examples)
npm test

# Run individual examples
npm run test:basic      # Basic logging features
npm run test:advanced   # Advanced features
npm run test:beast      # Beast mode (all 20+ features)

# Build
npm run build

# Type check
npm run typecheck

# Watch mode for development
npm run dev

Running Tests

The test suite validates that all examples work correctly:

# Run all tests with assertions
npm test

# Expected output:
# Starting test suite
# Running: Basic Tests
# PASSED: All 15 expectations met
# Running: Advanced Tests
# PASSED: All 22 expectations met
# Running: Beast Mode Tests
# PASSED: All 22 expectations met
# All tests passed!

Tests validate:

  • Basic logging (TextHandler, JSONHandler, attributes, groups, levels)
  • Advanced features (LevelVar, all attribute types, nested groups, replaceAttr, etc.)
  • Beast mode features (20+ advanced handlers and utilities)

Graceful Shutdown

When using handlers with resources (files, timers, async operations), always call close():

import { New, FileHandler, BufferedHandler, AsyncHandler } from '@omdxp/jslog';

const fileHandler = new FileHandler({ filepath: './logs/app.log' });
const logger = New(fileHandler);

// On shutdown
process.on('SIGTERM', () => {
  // FileHandler.close() is synchronous
  fileHandler.close();
  process.exit(0);
});

// For async handlers (BufferedHandler, AsyncHandler, etc.)
const asyncHandler = new AsyncHandler({ handler: new JSONHandler() });
process.on('SIGTERM', async () => {
  // These handlers need await
  await asyncHandler.close();
  process.exit(0);
});

Handlers that need closing:

  • FileHandler - Closes file stream (sync: fileHandler.close())
  • BufferedHandler - Flushes buffer and clears timer (async: await handler.close())
  • AsyncHandler - Waits for pending operations (async: await handler.close())
  • MultiHandler - Cascades close to all wrapped handlers (async: await handler.close())
  • MiddlewareHandler - Delegates close to wrapped handler (async: await handler.close())

Comparison with Go's log/slog

This library closely mirrors Go's log/slog API:

| Go slog | jslog | Status | | ------------------- | -------------------- | ------------- | | slog.Debug() | debug() | Implemented | | slog.Info() | info() | Implemented | | slog.Warn() | warn() | Implemented | | slog.Error() | error() | Implemented | | slog.New() | New() | Implemented | | slog.Default() | Default() | Implemented | | slog.SetDefault() | SetDefault() | Implemented | | slog.With() | logger.with() | Implemented | | slog.WithGroup() | logger.withGroup() | Implemented | | slog.String() | String() | Implemented | | slog.Int() | Int() | Implemented | | slog.Bool() | Bool() | Implemented | | slog.Time() | Time() | Implemented | | slog.Duration() | Duration() | Implemented | | slog.Group() | Group() | Implemented | | slog.Any() | Any() | Implemented | | slog.TextHandler | TextHandler | Implemented | | slog.JSONHandler | JSONHandler | Implemented | | slog.Level | Level | Implemented | | slog.LevelVar | LevelVar | Implemented | | Handler interface | Handler | Implemented | | ReplaceAttr | replaceAttr option | Implemented |

Inspiration

This library is inspired by Go's log/slog package, bringing structured logging patterns to the Node.js ecosystem.

License

MIT License