@lazhus/kg-central-logger
v1.0.0
Published
Central logging system with RabbitMQ support and fallback file logging
Maintainers
Readme
@sendeo/central-logger
Central logging system with RabbitMQ support and fallback file logging. This package is a Node.js/TypeScript implementation inspired by the .NET CentralLogging system.
Features
- 🚀 Asynchronous logging with internal queue
- 🐰 RabbitMQ integration with topic exchange
- 📁 Automatic fallback to file logging on RabbitMQ failure
- 🔄 Automatic reconnection on connection loss
- 📊 Log levels (Trace, Debug, Information, Warning, Error, Critical)
- 🏷️ Enrichers support
- 🎯 Scope support with AsyncLocalStorage
- ⚙️ Configurable channel bounds and parallelism
- 🎨 Category-based log level filtering
Installation
npm install @sendeo/central-loggerQuick Start
import { createCentralLogger, LogLevel } from '@sendeo/central-logger';
// Create logger provider
const provider = createCentralLogger(
'amqp://localhost:5672',
(config) => {
config
.setLogKey('my-service')
.setExchangeName('logs-exchange')
.setDefaultLogLevel(LogLevel.Information)
.addEnricher('Environment', 'production')
.addEnricher('ServiceName', 'my-service');
}
);
// Create logger instance
const logger = provider.createLogger('MyController');
// Log messages
logger.info('Application started', { version: '1.0.0' });
logger.error('Something went wrong', new Error('Test error'), { userId: '123' });
// Use scopes
const scope = logger.beginScope({ requestId: 'abc-123' });
logger.info('Processing request'); // Will include requestId in properties
scope.dispose();
// Cleanup on shutdown
await provider.dispose();Configuration
CentralLoggerConfiguration
const config = new CentralLoggerConfiguration()
.setLogKey('my-service') // Required: Service identifier
.setExchangeName('logs-exchange') // Required: RabbitMQ exchange name
.setConnectionKey('default') // Optional: Connection identifier
.setIsSpecific() // Optional: Use specific routing
.setChannelBound(20000) // Optional: Max queue size (default: 20000)
.setMaxParallelism(20) // Optional: Parallel processing (default: 20)
.setFailedLogsBaseFolder('logs') // Optional: Fallback folder (default: 'CentralFailedLogs')
.setDefaultLogLevel(LogLevel.Info) // Optional: Default log level
.setMinimumLogLevel('MyController', LogLevel.Debug) // Optional: Category-specific level
.addEnricher('key', 'value'); // Optional: Add enrichersUsage Examples
Basic Logging
const logger = provider.createLogger('UserService');
logger.trace('Trace message');
logger.debug('Debug message');
logger.info('Info message');
logger.warn('Warning message');
logger.error('Error message', new Error('Something failed'));
logger.critical('Critical error', new Error('System failure'));Logging with Properties
logger.info('User logged in', {
userId: '12345',
username: 'john.doe',
ipAddress: '192.168.1.1'
});Using Scopes
// Scopes add properties to all logs within the scope
const scope = logger.beginScope({
requestId: 'req-123',
correlationId: 'corr-456'
});
logger.info('Starting process'); // Includes requestId and correlationId
logger.info('Process completed'); // Includes requestId and correlationId
scope.dispose(); // Clean up scopeNested Scopes
const outerScope = logger.beginScope({ requestId: 'req-123' });
logger.info('Outer scope');
const innerScope = logger.beginScope({ operationId: 'op-456' });
logger.info('Inner scope'); // Includes both requestId and operationId
innerScope.dispose();
logger.info('Back to outer'); // Only includes requestId
outerScope.dispose();Category-based Log Levels
const provider = createCentralLogger('amqp://localhost', (config) => {
config
.setLogKey('my-service')
.setExchangeName('logs')
.setDefaultLogLevel(LogLevel.Information)
.setMinimumLogLevel('DatabaseService', LogLevel.Debug)
.setMinimumLogLevel('CacheService', LogLevel.Warning);
});
const dbLogger = provider.createLogger('DatabaseService');
dbLogger.debug('This will be logged'); // Debug enabled for DatabaseService
const cacheLogger = provider.createLogger('CacheService');
cacheLogger.info('This will NOT be logged'); // Only Warning+ for CacheService
cacheLogger.warn('This will be logged');Log Entry Structure
Each log entry contains:
{
logKey: string; // Service identifier
timestamp: Date; // Log timestamp
level: string; // Log level (Trace, Debug, Information, etc.)
source?: string; // Logger category name
eventId?: number; // Optional event ID
eventName?: string; // Optional event name
message?: string; // Log message
messageTemplate?: string; // Message template with placeholders
exception?: { // Exception details (if any)
type?: string;
message?: string;
stackTrace?: string;
innerException?: {...};
};
enrichers: Record<string, string>; // Global enrichers
properties?: Record<string, string|null>; // Log properties + scope properties
}RabbitMQ Integration
Routing Key Format
Logs are published to RabbitMQ with the following routing key format:
project.{logKey}.{suffix}logKey: Your service identifier (lowercase)suffix: Eitherspecificorgeneral(based onsetIsSpecific())
Example: project.my-service.general
Exchange Configuration
The logger creates a topic exchange with durable flag. Make sure your RabbitMQ consumers bind to this exchange with appropriate routing key patterns.
Automatic Reconnection
The logger automatically attempts to reconnect to RabbitMQ if the connection is lost. During disconnection, logs are written to fallback files.
Fallback File Logging
When RabbitMQ is unavailable, logs are automatically written to files in the configured folder (default: CentralFailedLogs).
Files are named: failed-logs-{timestamp}.json
Each line in the file is a JSON-serialized log entry.
Performance Considerations
- Internal Queue: Logs are queued internally and processed asynchronously
- Bounded Channel: Queue size is limited (default: 20,000). Oldest logs are dropped when full
- Parallel Processing: Multiple logs are published in parallel (default: 20)
- Non-blocking: Logging operations never block the main thread
Cleanup
Always dispose the provider when shutting down your application:
process.on('SIGTERM', async () => {
await provider.dispose();
process.exit(0);
});TypeScript Support
This package is written in TypeScript and includes full type definitions.
License
MIT
Credits
Inspired by the Sendeo.Core.CentralLogging .NET library.
