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

@stool/logging

v3.2.5

Published

Logger

Readme

@stool/logging

A simple, logging library inspired by Python's logging module. Features include multiple log levels, custom formatters, filters, and handlers.

Features

  • 🏗️ Hierarchical logger structure with parent-child relationships
  • 📊 Multiple log levels (DEBUG, INFO, WARN, ERROR, FATAL/CRITICAL)
  • 🎨 Customizable formatters for log output
  • 🔍 Filtering capabilities for fine-grained log control
  • 📤 Multiple handlers (Console, and extensible for custom handlers)
  • 🌐 Global logger factory for consistent logging across your application

Install

npm install @stool/logging

Quick Start

import { getLogger, ConsoleHandler, SimpleFormater } from '@stool/logging';

// Get a logger instance
const logger = getLogger('app');
logger.setLevel('DEBUG');

// Add a console handler with custom formatting
const consoleHandler = new ConsoleHandler();
consoleHandler.setFormater(new SimpleFormater('{name} {levelName} {msg}'));
logger.addHandler(consoleHandler);

// Start logging
logger.info('Application started');
logger.error('Something went wrong');

Basic Usage

Creating Loggers

import { getLogger } from '@stool/logging';

// Root logger
const rootLogger = getLogger();

// Named logger
const appLogger = getLogger('app');

// Child logger (inherits from parent)
const dbLogger = getLogger('app.database');
const userLogger = getLogger('app.user');

Log Levels

const logger = getLogger('myapp');

// Set minimum log level
logger.setLevel('INFO'); // or use Levels.INFO

// Logging methods (in order of severity)
logger.debug('Debug information');     // Lowest priority
logger.info('General information');
logger.warn('Warning message');        // or logger.warning()
logger.error('Error occurred');
logger.fatal('Critical error');        // or logger.critical()

// Exception logging
try {
    throw new Error('Something failed');
} catch (error) {
    logger.exception(error); // Logs error with stack trace
}

Advanced Logging with Extra Data

const logger = getLogger('app');

// Log with extra context data
logger.info('User login', { userId: 123, ip: '192.168.1.1' });
logger.error('Database error', new Error('Connection failed'), { 
    query: 'SELECT * FROM users',
    duration: 1500 
});

Handlers

Handlers determine where log messages are sent. You can add multiple handlers to a logger.

Console Handler

import { ConsoleHandler, SimpleFormater } from '@stool/logging';

const logger = getLogger('app');

// Basic console handler
const handler = new ConsoleHandler();
logger.addHandler(handler);

// Console handler with custom formatting
const customHandler = new ConsoleHandler();
customHandler.setFormater(new SimpleFormater('{levelName}: {msg}'));
customHandler.setLevel('WARN'); // Only log warnings and above
logger.addHandler(customHandler);

Creating Custom Handlers

import { BaseHandler, IRecord } from '@stool/logging';

class FileHandler extends BaseHandler {
    constructor(private filename: string) {
        super();
    }

    emit(record: IRecord): void {
        const message = this.formater.format(record);
        // Write to file (implement your file writing logic)
        console.log(`Writing to ${this.filename}: ${message}`);
    }
}

// Usage
const fileHandler = new FileHandler('app.log');
logger.addHandler(fileHandler);

Formatters

Formatters control the structure and appearance of log messages.

Built-in Formatters

import { SimpleFormater } from '@stool/logging';

const logger = getLogger('app');
const handler = new ConsoleHandler();

// Predefined formats
handler.setFormater(new SimpleFormater(SimpleFormater.FULL));    // Full details
handler.setFormater(new SimpleFormater(SimpleFormater.BASIC));   // Basic info
handler.setFormater(new SimpleFormater(SimpleFormater.MINIMAL)); // Just message

// Custom format template
handler.setFormater(new SimpleFormater('{created} [{levelName}] {name}: {msg}'));

Available Format Variables

  • {created} - ISO timestamp
  • {timestamp} - Unix timestamp
  • {name} - Logger name
  • {level} - Numeric level
  • {levelName} - Level name (DEBUG, INFO, etc.)
  • {msg} - Log message
  • {exception} - Exception information
  • {extra} - Extra context data

Custom Formatters

import { IFormater, IRecord } from '@stool/logging';

class JsonFormater implements IFormater {
    format(record: IRecord): string {
        return JSON.stringify({
            timestamp: record.timestamp,
            level: record.levelName,
            logger: record.name,
            message: record.msg,
            extra: record.extra
        });
    }
}

// Usage
const handler = new ConsoleHandler();
handler.setFormater(new JsonFormater());

Filters

Filters provide fine-grained control over which log records are processed.

Built-in Filter

import { Filter } from '@stool/logging';

const logger = getLogger('app');
const handler = new ConsoleHandler();

// Only log records from 'app.database' and its children
const filter = new Filter('app.database');
handler.addFilter(filter);

logger.addHandler(handler);

Custom Filters

// Function-based filter
const errorOnlyFilter = (record) => record.level >= Levels.ERROR;
handler.addFilter(errorOnlyFilter);

// Class-based filter
class TimeFilter {
    constructor(private startHour: number, private endHour: number) {}
    
    filter(record: IRecord): boolean {
        const hour = record.created.getHours();
        return hour >= this.startHour && hour <= this.endHour;
    }
}

// Only log during business hours
handler.addFilter(new TimeFilter(9, 17));

Hierarchical Logging

Loggers form a hierarchy based on their names (separated by dots). Child loggers inherit settings from parents and can propagate messages up the hierarchy.

const appLogger = getLogger('app');
const dbLogger = getLogger('app.database');
const userDbLogger = getLogger('app.database.users');

// Add handler to parent
const handler = new ConsoleHandler();
appLogger.addHandler(handler);

// Child loggers will use parent's handler
dbLogger.info('Database connected');     // Will use app's handler
userDbLogger.info('User table ready');   // Will also use app's handler

// Add specific handler to child
const dbHandler = new ConsoleHandler();
dbHandler.setFormater(new SimpleFormater('DB: {msg}'));
dbLogger.addHandler(dbHandler);

// Now dbLogger will use both handlers
dbLogger.info('Query executed'); // Appears in both formats

Complete Example

import { 
    getLogger, 
    ConsoleHandler, 
    SimpleFormater, 
    Filter,
    Levels 
} from '@stool/logging';

// Create main application logger
const appLogger = getLogger('myapp');
appLogger.setLevel(Levels.DEBUG);

// Set up console handler with custom formatting
const consoleHandler = new ConsoleHandler();
consoleHandler.setFormater(new SimpleFormater(
    '{created} [{levelName}] {name}: {msg} {extra}'
));
appLogger.addHandler(consoleHandler);

// Create specialized loggers
const httpLogger = getLogger('myapp.http');
const dbLogger = getLogger('myapp.database');

// Add filter to only show errors for database
const dbHandler = new ConsoleHandler();
dbHandler.setLevel(Levels.ERROR);
dbHandler.setFormater(new SimpleFormater('DB ERROR: {msg}'));
dbLogger.addHandler(dbHandler);

// Usage
appLogger.info('Application starting');
httpLogger.info('Server listening on port 3000');
dbLogger.info('Database connected'); // Won't show (below ERROR level)
dbLogger.error('Query failed', { query: 'SELECT * FROM users' });

// Exception handling
try {
    throw new Error('Something went wrong');
} catch (error) {
    appLogger.exception(error);
}

API Reference

Logger Methods

  • setLevel(level: LevelType) - Set minimum log level
  • addHandler(handler: IHandler) - Add output handler
  • removeHandler(handler: IHandler) - Remove handler
  • debug(msg: string) - Log debug message
  • info(msg: string, extra?: any) - Log info message
  • warn(msg: string, exception?: any, extra?: any) - Log warning
  • error(msg: string, exception?: any, extra?: any) - Log error
  • fatal(msg: string, exception?: any, extra?: any) - Log fatal error
  • exception(error: Error) - Log exception with stack trace

Log Levels

import { Levels } from '@stool/logging';

Levels.DEBUG    // 1
Levels.INFO     // 2  
Levels.WARN     // 4
Levels.ERROR    // 8
Levels.FATAL    // 16
Levels.NOTSET   // 0

License

MIT