https://github.com/metarhia/metalog
Metarhia logger 📝
https://github.com/metarhia/metalog
api application-server cloud console hacktoberfest highload impress log logger logging meta-edu metarhia node nodejs server tools
Last synced: 3 months ago
JSON representation
Metarhia logger 📝
- Host: GitHub
- URL: https://github.com/metarhia/metalog
- Owner: metarhia
- License: mit
- Created: 2017-08-06T20:06:09.000Z (almost 9 years ago)
- Default Branch: master
- Last Pushed: 2025-10-13T23:28:38.000Z (8 months ago)
- Last Synced: 2025-10-20T18:35:17.988Z (7 months ago)
- Topics: api, application-server, cloud, console, hacktoberfest, highload, impress, log, logger, logging, meta-edu, metarhia, node, nodejs, server, tools
- Language: JavaScript
- Homepage: https://metarhia.com
- Size: 749 KB
- Stars: 39
- Watchers: 14
- Forks: 15
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- Funding: .github/FUNDING.yml
- License: LICENSE
- Security: SECURITY.md
- Authors: AUTHORS
Awesome Lists containing this project
README
# Meta Logger for Metarhia
[](https://github.com/metarhia/metalog/actions?query=workflow%3A%22Testing+CI%22+branch%3Amaster)
[](https://snyk.io/test/github/metarhia/impress)
[](https://www.npmjs.com/package/metalog)
[](https://www.npmjs.com/package/metalog)
[](https://www.npmjs.com/package/metalog)
[](https://github.com/metarhia/metalog/blob/master/LICENSE)
## Output example

## Usage
```js
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('
HTML content');
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
```js
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
```js
// 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
```js
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
```js
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
```js
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
```js
new Logger(options: LoggerOptions): Promise
```
#### Static Methods
- `Logger.create(options: LoggerOptions): Promise` - Create and open logger
#### Instance Methods
- `open(): Promise` - Open log file and start logging
- `close(): Promise` - Close logger and flush remaining data
- `rotate(): Promise` - 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
```js
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
```js
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
```js
// 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
```js
path: `/var/log/app/${process.env.NODE_ENV}/${process.env.SERVICE_NAME}`;
```
3. **Error Handling**: Always handle logger errors
```js
logger.on('error', (error) => {
// Fallback logging or alerting
});
```
### Development vs Production
```js
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,
});
```
## Troubleshooting
### Common Issues
**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
### Debug Mode
```js
// 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' });
```
## License & Contributors
Copyright (c) 2017-2026 [Metarhia contributors](https://github.com/metarhia/metalog/graphs/contributors).
Metalog is [MIT licensed](./LICENSE).\
Metalog is a part of [Metarhia](https://github.com/metarhia) technology stack.