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

@jshow/logger

v1.0.11

Published

<p align="center"> <a href="https://jshow.org" target="_blank"> <img width="100" src="https://jshow.org/images/jshow.png" alt="jShow logo" /> </a> </p> <h1 align="center">@jshow/logger</h1>

Readme

pro-ci pro-co pro-dm pro-ver

pro-lic pro-ct


Introduction

@jshow/logger is a powerful, flexible, and feature-rich logging library for TypeScript/JavaScript applications. It provides a clean API for structured logging with support for namespaces, tags, extra information, and customizable output formats.

Features

  • Multiple Log Levels: Support for error, warn, info, and debug levels
  • Namespace Support: Organize logs by module or feature using hierarchical namespaces
  • Tags & Extra Info: Add structured metadata to logs for better filtering and analysis
  • Color Support: Beautiful colored output in both Node.js (ANSI) and Browser (CSS) environments
  • Flexible Output: Support for both text and JSON output formats
  • Highly Configurable: Custom transformers, filters, and hooks for advanced use cases
  • Hooks Support: Execute custom logic after log output (e.g., send to monitoring systems)
  • Filtering: Built-in support for filtering logs by namespace using DEBUG_IGNORE environment variable
  • TypeScript: Full TypeScript support with comprehensive type definitions
  • Cross-Platform: Works in both Node.js and Browser environments
  • Lightweight: Minimal dependencies, optimized for performance

Supporting

jShow is an MIT-Licensed open source project with its ongoing development made possible entirely by the support of these awesome backers. If you'd like to join them, please consider:

What's the difference between Patreon and OpenCollective?

Funds donated via Patreon go directly to support @jshow/logger You's full-time work on jShow. Funds donated via OpenCollective are managed with transparent expenses and will be used for compensating work and expenses for core team members or sponsoring community events. Your name/logo will receive proper recognition and exposure by donating on either platform.



Installation

npm install @jshow/logger
# or
pnpm add @jshow/logger
# or
yarn add @jshow/logger

Requirements

  • Node.js >= 14 (for Node.js environment)
  • Modern browsers with ES6+ support (for browser environment)
  • TypeScript >= 4.0 (optional, for TypeScript projects)

Quick Start

import { configure, logger } from '@jshow/logger';

// Configure the logger (only need to call once at application startup)
configure();

// Use different log levels
logger.error('This is an error message');
logger.warn('This is a warning message');
logger.info('This is an info message');
logger.debug('This is a debug message');

Basic Usage

Log Levels

@jshow/logger supports four log levels, ordered by severity from high to low:

  • error - Error level
  • warn - Warning level
  • info - Info level (default)
  • debug - Debug level
logger.error('Error message');
logger.warn('Warning message');
logger.info('Info message');
logger.debug('Debug message');

Namespace

Use namespaces to organize and categorize logs:

// Create a logger with namespace
const appLogger = logger.fork({ namespace: 'app' });
appLogger.info('Application started');

const dbLogger = logger.fork({ namespace: 'database' });
dbLogger.info('Database connected');

// Nested namespaces
const apiLogger = logger.fork({ namespace: 'api' });
const userApiLogger = apiLogger.fork({ namespace: 'user' });
userApiLogger.info('Get user information');

Scope

Use the scope method to execute code in a specific context:

logger.scope({ namespace: 'request' }, log => {
  log.info('Request processing started');
  log.info('Processing request...');
  log.info('Request processing completed');
});

Raw Write

If you want a "stream-like" write (bypassing level selection but still applying filter/hook), use logger.write(XX).

logger.write('hello');
logger.write('world\n'); // You need to manually add the newline character at the end

Advanced Features

Tags

Use tags to categorize and filter logs:

const taggedLogger = logger.fork({
  namespace: 'payment',
  tags: { module: 'payment', version: '1.0.0' }
});

taggedLogger.info('Processing payment request', { amount: 100, currency: 'USD' });

Extra Information

Use extra information to add structured data:

const loggerWithExtra = logger.fork({
  namespace: 'api',
  extra: { requestId: 'req-123', userId: 'user-456' }
});

loggerWithExtra.info('API request processing');

Dynamic Log Level

Each logger instance can have its own log level settings, which work together with the global log level. You can dynamically change the log level for a specific logger instance without affecting other loggers.

Using setLevel()

setLevel() sets a threshold level. Only logs with severity equal to or higher than the threshold will be output. The severity order is: error > warn > info > debug.

const debugLogger = logger.fork({ namespace: 'debug' });
debugLogger.setLevel('debug');
debugLogger.debug('This debug message will be shown'); // ✓ Output
debugLogger.info('This info message will be shown');   // ✓ Output
debugLogger.warn('This warn message will be shown');  // ✓ Output
debugLogger.error('This error message will be shown'); // ✓ Output

debugLogger.setLevel('info');
debugLogger.debug('This debug message will NOT be shown'); // ✗ Filtered
debugLogger.info('This info message will be shown');       // ✓ Output
debugLogger.warn('This warn message will be shown');      // ✓ Output
debugLogger.error('This error message will be shown');     // ✓ Output

debugLogger.setLevel('error');
debugLogger.debug('This debug message will NOT be shown'); // ✗ Filtered
debugLogger.info('This info message will NOT be shown');   // ✗ Filtered
debugLogger.warn('This warn message will NOT be shown');   // ✗ Filtered
debugLogger.error('This error message will be shown');     // ✓ Output

Using setLevels()

setLevels() sets a whitelist of allowed log levels. Only logs with levels in the whitelist will be output.

const customLogger = logger.fork({ namespace: 'custom' });
customLogger.setLevels('info', 'error');
customLogger.debug('This debug message will NOT be shown'); // ✗ Not in whitelist
customLogger.info('This info message will be shown');       // ✓ In whitelist
customLogger.warn('This warn message will NOT be shown');   // ✗ Not in whitelist
customLogger.error('This error message will be shown');     // ✓ In whitelist

// Clear the whitelist (use all levels)
customLogger.setLevels();
customLogger.debug('This debug message will be shown'); // ✓ Output (if global level allows)

Interaction with Global Log Level

Instance-level log level settings work together with global log level settings. Both conditions must be satisfied for a log to be output:

import { setLogLevel, logger } from '@jshow/logger';

// Set global log level to 'warn'
setLogLevel('warn');

const appLogger = logger.fork({ namespace: 'app' });
appLogger.setLevel('debug'); // Instance level: debug

// Even though instance level is 'debug', global level is 'warn'
appLogger.debug('This will NOT be shown'); // ✗ Filtered by global level
appLogger.info('This will NOT be shown');  // ✗ Filtered by global level
appLogger.warn('This will be shown');      // ✓ Both levels allow
appLogger.error('This will be shown');     // ✓ Both levels allow

Inheritance in Forked Loggers

When you create a child logger using fork(), the child logger inherits the parent's log level settings:

const parentLogger = logger.fork({ namespace: 'parent' });
parentLogger.setLevel('info');

const childLogger = parentLogger.fork({ namespace: 'child' });
// childLogger inherits the 'info' level from parentLogger

childLogger.debug('This will NOT be shown'); // ✗ Filtered
childLogger.info('This will be shown');      // ✓ Output

// You can override the level for the child logger
childLogger.setLevel('debug');
childLogger.debug('This will be shown');     // ✓ Output (if global level allows)

Resetting Log Level

To reset a logger instance to use only the global log level, call setLevels() with no arguments to clear the instance-level whitelist:

const testLogger = logger.fork({ namespace: 'test' });
testLogger.setLevel('debug');
// ... use logger ...

// Reset to use global level only (clear instance-level settings)
testLogger.setLevels(); // Clear the whitelist, now uses global level only

Configuration

Basic Configuration

import { configure, LoggerFactoryOfConsole } from '@jshow/logger';

configure({
  createCoreLogger: LoggerFactoryOfConsole,
  config: {
    format: 'text', // 'text' or 'json'
    enableNamespacePrefix: true,
    enableNamespacePrefixColors: true,
    appendTagsForTextPrint: true,
    appendExtraForTextPrint: true
  }
});

JSON Format

configure({
  config: {
    format: 'json'
  }
});

Custom Transformers

configure({
  config: {
    format: 'text',
    transformTagsForTextPrint: (tags, context) => {
      return `[Tags: ${Object.keys(tags).join(', ')}]`;
    },
    transformExtraForTextPrint: (extra, context) => {
      return `[Extra: ${JSON.stringify(extra)}]`;
    }
  }
});

Filter

Use filters to control which logs are output:

configure({
  config: {
    filter: (namespace, tags) => {
      // Only show logs from production environment
      return tags.env === 'production';
    }
  }
});

Hook

Use hook functions to execute custom logic after log output:

configure({
  config: {
    hook: (level, context, ...messages) => {
      if (level === 'error') {
        // Send errors to monitoring system
        sendToMonitoring(level, context, messages);
      }
    }
  }
});

Global Log Level

Set global log level:

import { setLogLevel, setLogLevels } from '@jshow/logger';

// Set a single log level threshold
setLogLevel('debug'); // Show all log levels
setLogLevel('info'); // Show only info, warn, error
setLogLevel('warn'); // Show only warn, error
setLogLevel('error'); // Show only error

// Set multiple allowed log levels
setLogLevels('debug', 'info', 'warn', 'error'); // Show all log levels
setLogLevels('info', 'warn', 'error'); // Show only info, warn, error
setLogLevels('warn', 'error'); // Show only warn, error
setLogLevels('error'); // Show only error

useLogger Hook

Use the useLogger hook to automatically create loggers with namespaces extracted from context:

import { useLogger } from '@jshow/logger';

// Use string as namespace
const logger = useLogger('UserService');
logger.info('User created'); // Output: [UserService] User created

// Use class as context
class UserService {
  constructor() {
    this.logger = useLogger(this);
  }
}
// logger namespace will be 'UserService'

// Use function as context
function handleRequest() {
  const logger = useLogger(handleRequest);
  logger.debug('Processing request');
}
// logger namespace will be 'handleRequest'

Filtering Logs with DEBUG_IGNORE

You can filter out specific namespaces using the DEBUG_IGNORE environment variable:

# Ignore logs from UserService and ApiClient namespaces
DEBUG_IGNORE=UserService,ApiClient node app.js

When a namespace is in the ignore list, useLogger returns a no-op logger that won't output anything.


Color Module

The Color module provides utilities for color manipulation and display:

import { Color } from '@jshow/logger';

// Generate color from text
const color = Color.makeColorHexFromText('error'); // Returns [r, g, b]

// Invert color
const inverted = Color.invertHex([255, 128, 64]);

// Check if a color is "bright enough"
// Note: the function name is historical; it returns true when the color is bright.
const isBright = Color.isDarkColor([50, 50, 50]);

// Optimize color for better log display
const optimized = Color.betterLogColor([255, 0, 0]);

// Wrap text with ANSI colors (Node.js)
const ansiText = Color.wrapColorANSI('Hello', {
  contentColor: [255, 0, 0],
  backgroundColor: [0, 0, 0]
});

// Wrap text with CSS colors (Browser)
const [cssContent, cssStyle] = Color.wrapColorCSS('Hello', {
  contentColor: [255, 0, 0],
  backgroundColor: [0, 0, 0]
});

API Reference

Logger Methods

logger.error(...msg: unknown[])

Log error level messages

logger.warn(...msg: unknown[])

Log warning level messages

logger.info(...msg: unknown[])

Log info level messages

logger.debug(...msg: unknown[])

Log debug level messages

logger.write(msg: string)

Write output with "raw write" semantics (Node: stdout.write, Browser: fallback to info)

logger.fork(context: LoggerSubContext)

Create a new child logger instance

logger.scope(context: LoggerSubContext, fn: (logger: Logger) => void)

Execute callback function in specified context

logger.setLevel(level: LogLevel)

Set the output level for current logger

logger.setLevels(...levels: LogLevel[])

Set multiple allowed log levels for current logger

useLogger(ctx: string | Function | object)

Create a logger instance with namespace extracted from context. Returns a no-op logger if namespace is in DEBUG_IGNORE environment variable.

setLoggerIgnore(ignore: string)

Programmatically set the list of namespaces to ignore. Takes a comma-separated string of namespace names (case-insensitive).

import { setLoggerIgnore } from '@jshow/logger';

// Ignore logs from UserService and ApiClient namespaces
setLoggerIgnore('UserService,ApiClient');

Functions

configure(options?)

Configure the logger. Can only be called once. If called multiple times, throws an error.

import { configure, LoggerFactoryOfConsole } from '@jshow/logger';

// Use default console logger with default config
configure();

// Use default console logger with custom config
configure({
  config: {
    format: 'json',
    enableNamespacePrefix: true
  }
});

// Use custom logger factory with custom config
configure({
  createCoreLogger: LoggerFactoryOfConsole,
  config: {
    format: 'text',
    enableNamespacePrefix: true
  }
});

setLogLevel(level: LogLevel)

Set global log level threshold

setLogLevels(...levels: LogLevel[])

Set global allowed log levels

useLogger(ctx: string | Function | object)

Create a logger with namespace extracted from context

setLoggerIgnore(ignore: string)

Programmatically set the list of namespaces to ignore

Types

LogLevel

type LogLevel = 'error' | 'warn' | 'info' | 'debug';

LoggerContext

interface LoggerContext {
  tags?: { [x: string]: unknown };
  extra?: { [x: string]: string | number | boolean | undefined | null };
  namespace?: string[];
  readonly config: LoggerConfig;
}

LoggerConfig

interface LoggerConfig {
  format: 'text' | 'json';
  enableNamespacePrefix: boolean;
  enableNamespacePrefixColors: boolean;
  appendTagsForTextPrint: boolean;
  appendExtraForTextPrint: boolean;
  transformTagsForTextPrint?: (
    tags: LoggerContext['tags'],
    context: LoggerContext
  ) => unknown;
  transformExtraForTextPrint?: (
    extra: LoggerContext['extra'],
    context: LoggerContext
  ) => unknown;
  filter?: (
    namespace: NonNullable<LoggerContext['namespace']>,
    tags: NonNullable<LoggerContext['tags']>
  ) => boolean;
  hook?: (
    level: LogLevel,
    context: LoggerContext,
    ...messages: Array<unknown>
  ) => unknown;
}

Best Practices

  1. Configure once at startup: Call configure() only once when your application starts
  2. Use namespaces: Organize logs by feature or module using namespaces
  3. Use tags for filtering: Use tags to categorize logs that can be filtered later
  4. Use extra for context: Use extra information for structured data like request IDs
  5. Set appropriate log levels: Use setLogLevel() or setLogLevels() to control verbosity in different environments
  6. Use hooks for monitoring: Implement hooks to send critical logs to monitoring systems
  7. Use filters for production: Use filters to reduce log noise in production environments
  8. Use TypeScript: Take advantage of full TypeScript support for better type safety and IDE autocomplete
  9. Leverage useLogger: Use useLogger hook for automatic namespace extraction from classes and functions
  10. Environment-based configuration: Use different configurations for development, staging, and production

Examples

For more usage examples, see the examples directory:


Environment Variables

DEBUG_IGNORE

Comma-separated list of namespace names (case-insensitive) to ignore. When using useLogger, loggers with namespaces in this list will return no-op loggers.

DEBUG_IGNORE=UserService,ApiClient,Database

You can also set this programmatically:

import { setLoggerIgnore } from '@jshow/logger';

setLoggerIgnore('UserService,ApiClient,Database');

TypeScript Support

@jshow/logger is written in TypeScript and provides full type definitions out of the box. All APIs are fully typed, providing excellent IDE autocomplete and type safety.

import { logger, type Logger, type LogLevel } from '@jshow/logger';

// All methods are fully typed
const appLogger: Logger = logger.fork({ namespace: 'app' });
const level: LogLevel = 'info';

Browser Support

The library works in both Node.js and browser environments:

  • Node.js: Uses ANSI color codes for terminal output
  • Browser: Uses CSS styles for console output (works with browser DevTools)

The same API works in both environments without any code changes.


Performance

@jshow/logger is designed with performance in mind:

  • Minimal overhead when logs are filtered out
  • Efficient namespace and context management
  • No-op loggers for ignored namespaces have zero overhead
  • Safe JSON serialization handles circular references efficiently

Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.


Testing

pnpm test

Questions

The issue list of this repo is exclusively for bug reports and feature requests.


License

MIT


Copyright (c) 2022 jShow.org