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

@ncoderz/log-m8

v1.2.5

Published

Logging system for TypeScript / JavaScript

Downloads

55

Readme

log-m8

Build & Test npm version License

A fast, small, flexible and extensible logging system for TypeScript and JavaScript applications.

Features

  • 🌲 Hierarchical loggers - organize by module with inheritance
  • 🔌 Plugin architecture - extensible with custom appenders, formatters, and filters
  • 🎨 Multiple output targets - console, file, and more with custom formatters
  • 🔍 Configurable filters - control what gets logged and where
  • 🚀 Performance-optimized - designed for minimal overhead
  • 🌐 Browser & Node.js support - works in any JavaScript environment
  • 📦 ESM & CommonJS compatible - use with any module system
  • 💪 Zero dependencies - lightweight and fast (minified + gzipped ~6kB)

Installation

npm install @ncoderz/log-m8

Quick Start

import { LogM8 } from '@ncoderz/log-m8';

// Configure the logging system
LogM8.init();

// Get a logger
const logger = LogM8.getLogger('app.service');

// Log at various levels
logger.info('Service started');
logger.debug('Connection details:', { host: 'localhost', port: 3000 });
logger.error('Failed to connect', new Error('Connection refused'));

// Use context for structured logging
logger.setContext({ service: 'authentication', instance: 1 });
logger.warn('Rate limit exceeded');

// Child loggers inherit parent settings but can be configured separately
const dbLogger = logger.getLogger('database');  // app.service.database
dbLogger.setLevel('debug');

Core Concepts

Logging Levels

Log-m8 provides multiple logging levels in ascending order of verbosity:

| Level | Description | |-------|-------------| | off | Disables all logging | | fatal | Critical system failures requiring immediate intervention | | error | Failures preventing normal operation | | warn | Potentially problematic situations | | info | General informational messages about normal operation | | debug | Detailed diagnostic information for development | | track | Analytics and user behavior tracking events | | trace | Most detailed execution information for fine-grained debugging |

Hierarchical Loggers

Loggers are organized hierarchically using dot notation:

const appLogger = LogM8.getLogger('app');
const dbLogger = LogM8.getLogger('app.database');
const cacheLogger = appLogger.getLogger('cache'); // 'app.cache'

This allows you to configure logging granularly by component while maintaining a clean organizational structure.

Configuration

The LogM8.init() method configures the logging system:

LogM8.init({
  // Default log level for all loggers (defaults to 'info')
  level: 'info',

  // Per-logger level overrides
  loggers: {
    'app.database': 'debug',
    'app.service': 'warn'
  },

  // Appender configurations
  appenders: [
    {
      name: 'console',
      formatter: {
        name: 'default-formatter',
        format: ['{timestamp} {LEVEL} [{logger}]', '{message}', '{data}'],
        timestampFormat: 'yyyy-MM-dd hh:mm:ss.SSS',
        color: true
      },
      // Optional priority (higher runs first)
      priority: 100,
    },
    {
      name: 'file',
      filename: 'app.log',
      formatter: {
        name: 'json-formatter',
        format: ['timestamp', 'level', 'logger', 'message', 'data'],
        timestampFormat: 'iso',
      }
    }
  ],

  // Global filters
  filters: [
    {
      name: 'match-filter',
      deny: { 'context.sensitive': true }
    }
  ]
});

Appenders

Appenders are responsible for outputting log events to specific destinations.

Built-in Appenders

Console Appender

Outputs log events to the console, mapping log levels to the appropriate console methods.

{
  name: 'console',
  // Optional formatter configuration
  formatter: 'default-formatter',
  // Optional per-appender filters
  filters: ['sensitive-data']
}

File Appender

Writes log events to a file, one line per event.

{
  name: 'file',
  filename: 'app.log',
  // Optional: append to existing file (default: false)
  append: true,
  formatter: 'json-formatter'
}

Formatters

Formatters transform log events into output formats suitable for different appenders.

Supported Formatter Tokens

  • timestamp: Formatted timestamp
  • LEVEL: Uppercase level label (Default Formatter Only. With standard padding, and optional colorization)
  • level: Lowercase level name
  • logger: Logger name
  • message: Primary log message
  • data: Additional data arguments
  • context.*: Nested context properties

All tokens support accessing nested items with data[0].property like notation.

Built-in Formatters

Default Formatter

A human-readable text formatter with customizable templates and optional colorized output.

{
  name: 'default-formatter',
  // Optional: custom format with token placeholders
  format: ['{timestamp} {LEVEL} [{logger}]', '{message}', '{data}'],
  // Optional: timestamp format ('iso', 'locale', or custom pattern)
  timestampFormat: 'hh:mm:ss.SSS',
  // Optional: colorize level labels
  color: true
}

JSON Formatter

Formats log events as JSON objects, useful for machine processing and log aggregation.

{
  name: 'json-formatter',
  // Optional fields to include
  format: ['timestamp', 'level', 'logger', 'message', 'data', 'context'],
  // Pretty print
  pretty: true
}

Filters

Filters control which log events are processed by appenders.

Supported Filter Tokens

See Supported Formatter Tokens.

Built-in Filters

Match Filter

Provides allow/deny rules based on path-based equality or regex matching against log event properties.

{
  name: 'match-filter',
  // Optional: all rules must match to allow (AND logic)
  allow: {
    'logger': '/^app.*$/',
    'data[0].type': 'audit'
  },
  // Optional: any match denies (OR logic)
  deny: {
    'context.userId': '1234',
    'message': '/.*password.*/'
  }
}

Runtime Control

Log-m8 provides methods for controlling appenders and filters at runtime:

// Disable console appender (e.g., in production)
LogM8.disableAppender('console');

// Enable file appender
LogM8.enableAppender('file');

// Flush all appenders
LogM8.flushAppenders();

// Disable a filter for a specific appender
LogM8.disableFilter('sensitive-data', 'console');

// Enable a filter for a specific appender
LogM8.enableFilter('sensitive-data', 'console');

Adjusting log levels at runtime

You can change the effective logging thresholds without recreating loggers:

// Set global log level gate (does not change individual logger levels)
LogM8.setLevel('info');

// Set a specific logger's level via manager (equivalent to getLogger(...).setLevel)
LogM8.setLevel('debug', 'app.database');

// Or use the logger instance directly
const alpha = LogM8.getLogger('alpha');
alpha.setLevel('warn');

Behavior rules:

  • A message is emitted only if its level is enabled by BOTH the logger’s level and the global level.
  • Think of the effective level as the stricter bound: effective = min(loggerLevel, globalLevel) in the level order (off < fatal < error < warn < info < debug < track < trace).

Example sequence:

const warnLogger = LogM8.getLogger('alpha');
warnLogger.setLevel('warn');
const debugLogger = LogM8.getLogger('beta');
debugLogger.setLevel('debug');

// Global: info → beta logs info+, alpha logs warn+
LogM8.setLevel('info');

// Global: debug → beta logs debug+, alpha still logs warn+
LogM8.setLevel('debug');

// Global: info again → beta logs info+, alpha still logs warn+
LogM8.setLevel('info');

Extending with Custom Plugins

You can extend log-m8 with custom appenders, formatters, and filters.

For example:

class SlackAppenderFactory implements PluginFactory {
  name = 'slack';
  kind = PluginKind.appender;

  create(config) {
    return new SlackAppender(config);
  }
}

// Register before initialization
LogM8.registerPluginFactory(new SlackAppenderFactory());

// Use in configuration
LogM8.init({
  appenders: [
    {
      name: 'slack',
      webhookUrl: 'https://hooks.slack.com/...',
      channel: '#alerts'
    }
  ]
});

Browser Usage

Log-m8 works in browsers with automatic environment detection:

<script src="https://cdn.jsdelivr.net/npm/@ncoderz/log-m8@latest/dist/browser/log-m8.global.js"></script>
<script>
  const { LogM8 } = window.logM8;

  LogM8.init({
    level: 'info',
    appenders: [{ name: 'console', formatter: 'default-formatter' }]
  });

  const logger = LogM8.getLogger('app');
  logger.info('Application started');
</script>

License

BSD-2-Clause