log-m8

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
Installation
npm install @ncoderz/log-m8
Quick Start
import { LogM8 } from '@ncoderz/log-m8';
LogM8.init();
const logger = LogM8.getLogger('app.service');
logger.info('Service started');
logger.debug('Connection details:', { host: 'localhost', port: 3000 });
logger.error('Failed to connect', new Error('Connection refused'));
logger.setContext({ service: 'authentication', instance: 1 });
logger.warn('Rate limit exceeded');
const dbLogger = logger.getLogger('database');
dbLogger.setLevel('debug');
Core Concepts
Logging Levels
Log-m8 provides multiple logging levels in ascending order of verbosity:
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');
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({
level: 'info',
loggers: {
'app.database': 'debug',
'app.service': 'warn'
},
appenders: [
{
name: 'console',
formatter: 'default-formatter',
priority: 100,
color: true
},
{
name: 'file',
filename: 'app.log',
formatter: {
name: 'default-formatter',
timestampFormat: 'yyyy-MM-dd hh:mm:ss.SSS',
}
}
],
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',
formatter: 'default-formatter',
filters: ['sensitive-data']
}
File Appender
Writes log events to a file, one line per event.
{
name: 'file',
filename: 'app.log',
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 (with 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',
format: ['{timestamp} {LEVEL} [{logger}]', '{message}', '{data}'],
timestampFormat: 'hh:mm:ss.SSS',
color: true
}
JSON Formatter
Formats log events as JSON objects, useful for machine processing and log aggregation.
{
name: 'json-formatter',
format: ['timestamp', 'level', 'logger', 'message', 'data', 'context'],
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 matching against log event properties.
{
name: 'match-filter',
allow: {
'logger': 'app.service',
'data[0].type': 'audit'
},
deny: {
'context.userId': '1234',
'message': 'password'
}
}
Runtime Control
Log-m8 provides methods for controlling appenders and filters at runtime:
LogM8.disableAppender('console');
LogM8.enableAppender('file');
LogM8.flushAppenders();
LogM8.disableFilter('sensitive-data', 'console');
LogM8.enableFilter('sensitive-data', 'console');
Adjusting log levels at runtime
You can change the effective logging thresholds without recreating loggers:
LogM8.setLevel('info');
LogM8.setLevel('debug', 'app.database');
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');
LogM8.setLevel('info');
LogM8.setLevel('debug');
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);
}
}
LogM8.registerPluginFactory(new SlackAppenderFactory());
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