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 setting
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);
});
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
writeBuffer
based 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
toFile
andtoStdout
to reduce I/O// Production: Only errors to file, warnings+ to console toFile: ['error'], toStdout: ['warn', 'error']
-
Rotation Strategy: Set appropriate
keepDays
based 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
path
directory exists and is writable - Verify
toFile
array includes desired log tags - Ensure logger is properly opened with
await logger.open()
High memory usage:
- Reduce
writeBuffer
size - Increase
flushInterval
frequency - 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.