@edirect/logger
v11.0.58
Published
Structured logging module for eDirect NestJS applications. Built on top of [Pino](https://github.com/pinojs/pino), providing high-performance JSON logging with AsyncLocalStorage support for automatic context propagation, file output, and seamless integrat
Maintainers
Keywords
Readme
@edirect/logger
Structured logging module for eDirect NestJS applications. Built on top of Pino, providing high-performance JSON logging with AsyncLocalStorage support for automatic context propagation, file output, and seamless integration with NestJS.
Features
- ✅ Pino-based - High-performance structured JSON logging
- ✅ AsyncLocalStorage - Automatic context propagation (sessionId, quoteId, correlationId, traceId, userId)
- ✅ SINGLETON Architecture - Better performance
- ✅ Multi-level logging - log, info, warn, error, debug, verbose
- ✅ Enhanced error logging - Multiple overloads with trace support
- ✅ File and console output - Flexible output configuration (stdout/stderr or files)
- ✅ Datadog compatible - ISO 8601 timestamps and structured logs
- ✅ NestJS integration - Native support with middleware
- ✅ Global module - Register once, inject LoggerService anywhere
- ✅ Async configuration - Supports both sync (register) and async (registerAsync) setup
Installation
pnpm add @edirect/logger
# or
npm install @edirect/loggerQuick Start
Basic Usage (Without Middleware)
import { Module } from '@nestjs/common';
import { LoggerModule } from '@edirect/logger';
@Module({
imports: [LoggerModule],
})
export class AppModule {}import { Injectable } from '@nestjs/common';
import { LoggerService } from '@edirect/logger';
@Injectable()
export class MyService {
constructor(private logger: LoggerService) {}
doSomething() {
this.logger.info('Operation started', { userId: '123' });
}
}With Middleware (Automatic Context from HTTP Headers)
If you want automatic context extraction from HTTP headers, add the middleware:
import { Module, MiddlewareConsumer, NestModule } from '@nestjs/common';
import { LoggerModule, LoggerContextMiddleware } from '@edirect/logger';
@Module({
imports: [LoggerModule],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggerContextMiddleware)
.forRoutes('*'); // Apply to all routes
}
}Manual Context Setting
import { Injectable } from '@nestjs/common';
import { LoggerService } from '@edirect/logger';
@Injectable()
export class MyService {
constructor(private logger: LoggerService) {}
doSomething() {
this.logger.info('Operation started', { userId: '123' });
// sessionId and quoteId automatically included from request context!
}
}Configuration
Basic Configuration
import { Module } from '@nestjs/common';
import { LoggerModule } from '@edirect/logger';
@Module({
imports: [
LoggerModule.register({
output: 'console', // 'console' | 'file' | 'both'
level: 'info',
logs: {
infoFile: './logs/info.log',
warningFile: './logs/warning.log',
errorFile: './logs/error.log',
exceptionsFile: './logs/exceptions.log',
},
name: 'my-service',
version: '1.0.0',
}),
],
})
export class AppModule {}Async Configuration
import { ConfigService } from '@edirect/config';
import { LoggerModule } from '@edirect/logger';
@Module({
imports: [
ConfigModule,
LoggerModule.registerAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
output: configService.get('LOGS_OUTPUT'),
level: configService.get('LOGS_LEVEL'),
logs: {
infoFile: configService.get('LOGS_INFO_FILE'),
warningFile: configService.get('LOGS_WARNING_FILE'),
errorFile: configService.get('LOGS_ERROR_FILE'),
exceptionsFile: configService.get('LOGS_EXCEPTIONS_FILE'),
},
name: configService.get('APP_NAME'),
version: configService.get('APP_VERSION'),
}),
inject: [ConfigService],
}),
],
})
export class AppModule {}API Reference
Logging Methods
// Info logging
logger.log(message: string, payload?: any);
logger.info(message: string, payload?: any);
// Warning logging
logger.warn(message: string, payload?: any);
// Debug logging
logger.debug(message: string, payload?: any);
logger.verbose(message: string, payload?: any);
// Error logging (multiple overloads)
logger.error(message: string); // Just message
logger.error(message: string, payload: any); // Message + payload to enrich
logger.error(message: string, trace: string); // Message + stack trace
logger.error(message: string, error: Error); // Message + Error object
logger.error(message: string, payload: any, trace: string); // Full contextContext Management
// Set context manually (useful for background jobs)
logger.setContext('sessionId', 'session-123');
logger.setContext('quoteId', 'quote-456');
logger.setContext('correlationId', 'corr-789');
logger.setContext('traceId', 'trace-abc');
logger.setContext('userId', 'user-xyz');AsyncLocalStorage for Background Jobs
import { AsyncContextManager } from '@edirect/logger';
@Cron('0 0 * * *')
handleCron() {
AsyncContextManager.run({ sessionId: 'cron-job', quoteId: 'batch-001' }, () => {
this.logger.info('Cron job started');
// Context automatically propagates through all async calls
});
}Context Headers
The LoggerContextMiddleware automatically extracts context from these HTTP headers:
x-session-id→sessionIdx-quote-id→quoteIdx-trace-id→traceIdx-correlation-id→correlationIdreq.user.id→userId
Log Format
All logs are structured JSON with the following fields:
{
"timestamp": "2024-03-06T14:30:00.123Z",
"level": "info",
"message": "Operation completed",
"name": "my-service",
"version": "1.0.0",
"host": "localhost",
"protocol": "http",
"sessionId": "session-123",
"quoteId": "quote-456",
"correlationId": "corr-789",
"traceId": "trace-abc",
"userId": "user-xyz",
"remote-address": "192.168.1.1",
"details": { "custom": "data" },
"trace": "Error stack trace" // Only in error logs
}Error Logging Examples
// Simple error
logger.error('Something went wrong');
// Error with enrichment details
logger.error('User not found', { userId: '123', action: 'login' });
// Error with stack trace
logger.error('Database error', 'Error: Connection timeout\n at db.connect...');
// Error with Error object (auto-extracts stack)
try {
throw new Error('Failed to process');
} catch (error) {
logger.error('Processing failed', error);
}
// Full context error
logger.error(
'Complex error',
{ context: 'payment', orderId: '456' },
'Error stack trace here'
);License
MIT
