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();Metalog provides a fully compatible console implementation that supports all Node.js console methods:
console.log([data][, ...args])- General loggingconsole.info([data][, ...args])- Informational messagesconsole.warn([data][, ...args])- Warning messagesconsole.error([data][, ...args])- Error messagesconsole.debug([data][, ...args])- Debug messagesconsole.assert(value[, ...message])- Assertion testingconsole.clear()- Clear the consoleconsole.count([label])- Count occurrencesconsole.countReset([label])- Reset counterconsole.dir(obj[, options])- Object inspectionconsole.dirxml(...data)- XML/HTML inspectionconsole.group([...label])- Start groupconsole.groupCollapsed()- Start collapsed groupconsole.groupEnd()- End groupconsole.table(tabularData[, properties])- Table displayconsole.time([label])- Start timerconsole.timeEnd([label])- End timerconsole.timeLog([label][, ...data])- Log timer valueconsole.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.
| 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) |
Metalog supports five log tags that can be filtered independently for file and console output:
log- General logginginfo- Informational messageswarn- Warning messagesdebug- Debug messageserror- Error messages
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);
},
});// 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'],
});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"}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 settingconst 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);
});new Logger(options: LoggerOptions): Promise<Logger>Logger.create(options: LoggerOptions): Promise<Logger>- Create and open logger
open(): Promise<Logger>- Open log file and start loggingclose(): Promise<void>- Close logger and flush remaining datarotate(): Promise<void>- Manually trigger log rotationwrite(tag: string, indent: number, args: unknown[]): void- Low-level write methodflush(callback?: (error?: Error) => void): void- Flush buffer to disk
active: boolean- Whether logger is currently activepath: string- Log directory pathhome: string- Home directory for path normalizationconsole: Console- Console instance for logging
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();const formatter = new Formatter({
worker: 'W1',
home: '/app',
json: false,
});
const formatted = formatter.formatPretty('info', 0, ['Message']);
const jsonOutput = formatter.formatJson('error', 0, [error]);-
Buffer Size: Adjust
writeBufferbased on your log volume- High volume: 128KB or larger
- Low volume: 16KB or smaller
-
Flush Interval: Balance between performance and data safety
- Production: 3-10 seconds
- Development: 1-3 seconds
-
Selective Logging: Use
toFileandtoStdoutto reduce I/O// Production: Only errors to file, warnings+ to console toFile: ['error'], toStdout: ['warn', 'error']
-
Rotation Strategy: Set appropriate
keepDaysbased on storage -
Path Organization: Use structured paths for multi-service deployments
path: `/var/log/app/${process.env.NODE_ENV}/${process.env.SERVICE_NAME}`;
-
Error Handling: Always handle logger errors
logger.on('error', (error) => { // Fallback logging or alerting });
const isDevelopment = process.env.NODE_ENV === 'development';
const logger = await Logger.create({
path: './log',
home: process.cwd(),
json: !isDevelopment, // JSON in production, pretty in dev
toFile: isDevelopment ? ['log', 'info', 'warn', 'error'] : ['error'],
toStdout: isDevelopment
? ['log', 'info', 'warn', 'debug', 'error']
: ['warn', 'error'],
flushInterval: isDevelopment ? 1000 : 5000,
keepDays: isDevelopment ? 1 : 30,
});Logs not appearing in files:
- Check
pathdirectory exists and is writable - Verify
toFilearray includes desired log tags - Ensure logger is properly opened with
await logger.open()
High memory usage:
- Reduce
writeBuffersize - Increase
flushIntervalfrequency - Use selective logging with
toFile/toStdout
Missing logs on crash:
- Set
crash: 'flush'option - Handle process signals properly
- Use try/catch around critical operations
Performance issues:
- Use JSON format for high-volume logging
- Disable file logging for debug tags in production
- Consider using separate loggers for different components
// Enable debug logging
const logger = await Logger.create({
path: './log',
home: process.cwd(),
toStdout: ['debug', 'info', 'warn', 'error'],
});
logger.console.debug('Debug information', { data: 'value' });Copyright (c) 2017-2025 Metarhia contributors.
Metalog is MIT licensed.
Metalog is a part of Metarhia technology stack.
