SkillAgentSearch skills...

Metalog

Metarhia logger 📝

Install / Use

/learn @metarhia/Metalog

README

Meta Logger for Metarhia

ci status snyk npm version npm downloads/month npm downloads license

Output example

<img src="https://user-images.githubusercontent.com/4405297/111154959-7b99c700-859c-11eb-81bb-0f8398535106.png" width="60%"/>

Usage

const logger = await Logger.create({
  path: './log', // absolute or relative path
  workerId: 7, // mark for process or thread
  flushInterval: 3000, // flush log to disk interval (default: 3s)
  writeBuffer: 64 * 1024, // buffer size (default: 64kb)
  keepDays: 5, // delete after N days, 0 - disable (default: 1)
  home: process.cwd(), // remove substring from paths
  json: false, // print logs in JSON format (default: false)
  toFile: ['log', 'info', 'warn', 'error'], // tags to write to file (default: all)
  toStdout: ['log', 'info', 'warn', 'error'], // tags to write to stdout (default: all)
  createStream: () => fs.createWriteStream, // custom stream factory (optional)
  crash: 'flush', // crash handling: 'flush' to flush buffer on exit (optional)
});

const { console } = logger;

console.log('Test message');
console.info('Info message');
console.warn('Warning message');
console.error('Error message');
console.debug('Debug message');

console.assert(true, 'Assertion passed');
console.assert(false, 'Assertion failed');
console.count('counter');
console.count('counter');
console.countReset('counter');

console.time('operation');
// ... some operation ...
console.timeEnd('operation');
console.timeLog('operation', 'Checkpoint');

console.group('Group 1');
console.log('Nested message');
console.groupCollapsed('Group 2');
console.log('Collapsed group message');
console.groupEnd();
console.groupEnd();

console.dir({ key: 'value' });
console.dirxml('<div>HTML content</div>');
console.table([
  { name: 'John', age: 30 },
  { name: 'Jane', age: 25 },
]);

console.trace('Trace message');

await logger.close();

Console API Compatibility

Metalog provides a fully compatible console implementation that supports all Node.js console methods:

  • console.log([data][, ...args]) - General logging
  • console.info([data][, ...args]) - Informational messages
  • console.warn([data][, ...args]) - Warning messages
  • console.error([data][, ...args]) - Error messages
  • console.debug([data][, ...args]) - Debug messages
  • console.assert(value[, ...message]) - Assertion testing
  • console.clear() - Clear the console
  • console.count([label]) - Count occurrences
  • console.countReset([label]) - Reset counter
  • console.dir(obj[, options]) - Object inspection
  • console.dirxml(...data) - XML/HTML inspection
  • console.group([...label]) - Start group
  • console.groupCollapsed() - Start collapsed group
  • console.groupEnd() - End group
  • console.table(tabularData[, properties]) - Table display
  • console.time([label]) - Start timer
  • console.timeEnd([label]) - End timer
  • console.timeLog([label][, ...data]) - Log timer value
  • console.trace([message][, ...args]) - Stack trace

All methods maintain the same behavior as Node.js native console, with output routed through the metalog system for consistent formatting and file logging.

Configuration Options

LoggerOptions

| Option | Type | Default | Description | | --------------- | ---------- | ------------------------------------------- | --------------------------------------------------- | | path | string | required | Directory path for log files (absolute or relative) | | home | string | required | Base path to remove from stack traces | | workerId | number | undefined | Worker/process identifier (appears as W0, W1, etc.) | | flushInterval | number | 3000 | Flush buffer to disk interval in milliseconds | | writeBuffer | number | 65536 | Buffer size threshold before flushing (64KB) | | keepDays | number | 1 | Days to keep log files (0 = disable rotation) | | json | boolean | false | Output logs in JSON format | | toFile | string[] | ['log', 'info', 'warn', 'debug', 'error'] | Log tags to write to file | | toStdout | string[] | ['log', 'info', 'warn', 'debug', 'error'] | Log tags to write to stdout | | createStream | function | fs.createWriteStream | Custom stream factory function | | crash | string | undefined | Crash handling mode ('flush' to flush on exit) |

Log Tags

Metalog supports five log tags that can be filtered independently for file and console output:

  • log - General logging
  • info - Informational messages
  • warn - Warning messages
  • debug - Debug messages
  • error - Error messages

Advanced Usage

Custom Stream Factory

const logger = await Logger.create({
  path: './log',
  home: process.cwd(),
  createStream: (filePath) => {
    // Custom compression stream
    const fs = require('fs');
    const zlib = require('zlib');
    const gzip = zlib.createGzip();
    const writeStream = fs.createWriteStream(filePath + '.gz');
    return gzip.pipe(writeStream);
  },
});

Selective Logging

// Only log errors to file, all tags to console
const logger = await Logger.create({
  path: './log',
  home: process.cwd(),
  toFile: ['error'],
  toStdout: ['log', 'info', 'warn', 'debug', 'error'],
});

// Only log info and above tags to both file and console
const logger = await Logger.create({
  path: './log',
  home: process.cwd(),
  toFile: ['info', 'warn', 'error'],
  toStdout: ['info', 'warn', 'error'],
});

JSON Logging

const logger = await Logger.create({
  path: './log',
  home: process.cwd(),
  json: true,
});

logger.console.info('User action', { userId: 123, action: 'login' });
// Output: {"timestamp":"2025-01-07T10:30:00.000Z","worker":"W0","tag":"info","message":"User action","userId":123,"action":"login"}

Log Rotation and Cleanup

const logger = await Logger.create({
  path: './log',
  home: process.cwd(),
  keepDays: 7, // Keep logs for 7 days
  workerId: 1,
});

// Manual rotation
await logger.rotate();

// Log files are automatically rotated daily
// Old files are cleaned up based on keepDays setting

Error Handling

const logger = await Logger.create({
  path: './log',
  home: process.cwd(),
  crash: 'flush', // Flush buffer on process exit
});

logger.on('error', (error) => {
  console.error('Logger error:', error.message);
});

// Graceful shutdown
process.on('SIGTERM', async () => {
  await logger.close();
  process.exit(0);
});

API Reference

Logger Class

Constructor

new Logger(options: LoggerOptions): Promise<Logger>

Static Methods

  • Logger.create(options: LoggerOptions): Promise<Logger> - Create and open logger

Instance Methods

  • open(): Promise<Logger> - Open log file and start logging
  • close(): Promise<void> - Close logger and flush remaining data
  • rotate(): Promise<void> - Manually trigger log rotation
  • write(tag: string, indent: number, args: unknown[]): void - Low-level write method
  • flush(callback?: (error?: Error) => void): void - Flush buffer to disk

Properties

  • active: boolean - Whether logger is currently active
  • path: string - Log directory path
  • home: string - Home directory for path normalization
  • console: Console - Console instance for logging

BufferedStream Class

const stream = new BufferedStream({
  stream: fs.createWriteStream('output.log'),
  writeBuffer: 32 * 1024, // 32KB buffer
  flushInterval: 5000, // 5 second flush interval
});

stream.write(Buffer.from('data'));
stream.flush();
await stream.close();

Formatter Class

const formatter = new Formatter({
  worker: 'W1',
  home: '/app',
  json: false,
});

const formatted = formatter.formatPretty('info', 0, ['Message']);
const jsonOutput = formatter.formatJson('error', 0, [error]);

Best Practices

Performance Optimization

  1. Buffer Size: Adjust writeBuffer based on your log volume

    • High volume: 128KB or larger
    • Low volume: 16KB or smaller
  2. Flush Interval: Balance between performance and data safety

    • Production: 3-10 seconds
    • Development: 1-3 seconds
  3. Selective Logging: Use toFile and toStdout to reduce I/O

    // Production: Only errors to file, warnings+ to console
    toFile: ['error'],
    toStdout: ['warn', 'error']
    

Log Management

  1. Rotation Strategy: Set appropriate keepDays based on storage

  2. Path Organization: Use structured paths for multi-service deployments

    path: `/var/log/app/${process.env.NODE_ENV}/${process.env.SERVICE_NAME}`;
    
  3. Error Handling: Always handle logger errors

    logger.on('error', (error) => {
      // Fallback logging or alerting
    });
    

Development vs Production

View on GitHub
GitHub Stars39
CategoryDevelopment
Updated11d ago
Forks15

Languages

JavaScript

Security Score

90/100

Audited on Mar 19, 2026

No findings