@sklv-labs/ts-nestjs-logger
v0.1.1
Published
NestJS structured logging with Pino and CLS integration
Maintainers
Readme
@sklv-labs/ts-nestjs-logger
A comprehensive structured logging package for NestJS applications with Pino, CLS integration, and BaseError support.
Features
- 🎯 Type-Safe - Full TypeScript support with comprehensive type definitions
- 🚀 Structured Logging - JSON logs in production, pretty logs in development
- 🛠️ CLS Integration - Automatic request-scoped context via
@sklv-labs/ts-nestjs-cls - 📦 BaseError Support - Respects
loggableflag and provides structured error logging - 🔌 Multi-Transport - HTTP, RPC, and WebSocket logging interceptors
- 📊 Rich Context - Automatic extraction of requestId, traceId, userId, and more
- 🔒 Security - Automatic redaction of sensitive fields
- 🌐 OpenTelemetry - Automatic trace context extraction
Installation
npm install @sklv-labs/ts-nestjs-loggerPeer Dependencies
This package requires the following peer dependencies:
npm install @nestjs/common@^11.1.11 @nestjs/core@^11.1.11 @sklv-labs/ts-nestjs-cls@^0.1.0 nestjs-cls@^6.1.0Note: This package requires Node.js 24 LTS or higher.
Quick Start
// app.module.ts
import { Module } from '@nestjs/common';
import { ClsModule } from '@sklv-labs/ts-nestjs-cls';
import { LoggerModule } from '@sklv-labs/ts-nestjs-logger';
import { Environments } from '@sklv-labs/ts-core';
@Module({
imports: [
ClsModule.forRoot(), // MUST be imported first
LoggerModule.forRoot({
appName: 'my-app',
environment: Environments.PRODUCTION,
}),
],
})
export class AppModule {}Setup Exception Filter
// main.ts
import { NestFactory } from '@nestjs/core';
import { BaseErrorExceptionFilter } from '@sklv-labs/ts-nestjs-logger';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Add BaseError exception filter
app.useGlobalFilters(new BaseErrorExceptionFilter(
app.get(LoggerService),
app.get(ClsService)
));
await app.listen(3000);
}
bootstrap();Usage
Basic Logging
import { Injectable } from '@nestjs/common';
import { LoggerService } from '@sklv-labs/ts-nestjs-logger';
@Injectable()
export class MyService {
constructor(private readonly logger: LoggerService) {}
doSomething() {
this.logger.info('Operation started', { operationId: '123' });
this.logger.debug('Debug information', { data: 'value' });
this.logger.warn('Warning message', { warningCode: 'WARN_001' });
this.logger.error('Error occurred', { errorCode: 'ERR_001' });
}
}With BaseError
import { BaseError } from '@sklv-labs/ts-nestjs-error';
import { LoggerService } from '@sklv-labs/ts-nestjs-logger';
@Injectable()
export class MyService {
constructor(private readonly logger: LoggerService) {}
async findUser(userId: string) {
try {
// ... operation
} catch (error) {
// This will be automatically logged by BaseErrorExceptionFilter
throw new BaseError('User not found', 'USER_NOT_FOUND', {
statusCode: 404,
metadata: { userId },
loggable: true, // Will be logged
});
}
}
validateInput(data: unknown) {
if (!data) {
// This won't be logged (loggable: false)
throw new BaseError('Invalid input', 'VALIDATION_ERROR', {
statusCode: 400,
loggable: false, // Won't be logged
});
}
}
}Context Management
import { Injectable } from '@nestjs/common';
import { LoggerContextService, LoggerService } from '@sklv-labs/ts-nestjs-logger';
@Injectable()
export class MyService {
constructor(
private readonly logger: LoggerService,
private readonly loggerContext: LoggerContextService
) {}
async processRequest() {
// Set context that will be included in all subsequent logs
this.loggerContext.set('userId', 'user-123');
this.loggerContext.set('tenantId', 'tenant-1');
this.loggerContext.set('operationId', 'op-456');
// All logs will automatically include userId, tenantId, and operationId
this.logger.info('Processing request');
this.logger.debug('Step 1 completed');
this.logger.info('Step 2 completed');
}
}HTTP Logging Interceptor
import { APP_INTERCEPTOR } from '@nestjs/core';
import { HttpLoggingInterceptor } from '@sklv-labs/ts-nestjs-logger';
@Module({
providers: [
{
provide: APP_INTERCEPTOR,
useClass: HttpLoggingInterceptor,
},
],
})
export class AppModule {}Async Configuration
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { ClsModule } from '@sklv-labs/ts-nestjs-cls';
import { LoggerModule } from '@sklv-labs/ts-nestjs-logger';
import { Environments } from '@sklv-labs/ts-core';
@Module({
imports: [
ConfigModule.forRoot(),
ClsModule.forRoot(),
LoggerModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
appName: config.get('APP_NAME', 'my-app'),
environment: (config.get('NODE_ENV') as Environments) || Environments.DEVELOPMENT,
level: config.get('LOG_LEVEL', 'info'),
prettyPrint: config.get('LOG_PRETTY', 'false') === 'true',
}),
}),
],
})
export class AppModule {}API Reference
LoggerService
Implements NestJS LoggerService interface with additional methods.
Methods
log(message: unknown, context?: string): void- Log at info levelerror(message: unknown, metaOrTrace?: string | Record<string, unknown>, context?: string): void- Log errorwarn(message: unknown, metaOrContext?: Record<string, unknown> | string, context?: string): void- Log warningdebug(message: unknown, context?: string): void- Log debug messageverbose(message: unknown, context?: string): void- Log verbose messageinfo(message: unknown, meta?: Record<string, unknown>, context?: string): void- Log info with metadatafatal(message: unknown, context?: string): void- Log fatal errorgetPinoLogger(): PinoLogger- Get underlying Pino logger instance
LoggerContextService
Service for managing request-scoped logging context.
Methods
get(): LoggerContext | undefined- Get current contextgetAll(): LoggerContext- Get all context (returns empty object if none)set(key: keyof LoggerContext, value: unknown): void- Set context valuegetValue<K extends keyof LoggerContext>(key: K): LoggerContext[K] | undefined- Get specific context valuerun<T>(context: LoggerContext, callback: () => T): T- Run function with context
Interceptors
HttpLoggingInterceptor
Logs HTTP requests and responses with timing, status codes, and context.
Options:
logRequestBody?: boolean- Log request body (default:true)logResponseBody?: boolean- Log response body (default:false)logQuery?: boolean- Log query parameters (default:true)logHeaders?: boolean- Log headers (default:false)maxBodyLength?: number- Max body length to log (default:1000)skipPaths?: string[]- Paths to skip logging (default:['/health', '/metrics'])skipMethods?: string[]- HTTP methods to skip
RpcLoggingInterceptor
Logs RPC requests and responses for microservices.
Options:
logRequestData?: boolean- Log request data (default:true)logResponseData?: boolean- Log response data (default:false)maxDataLength?: number- Max data length to log (default:1000)skipPatterns?: string[]- Patterns to skip logging
WebSocketLoggingInterceptor
Logs WebSocket messages and events.
Options:
logMessageData?: boolean- Log message data (default:true)logClientInfo?: boolean- Log client info (default:true)maxDataLength?: number- Max data length to log (default:1000)skipEvents?: string[]- Events to skip logging (default:['ping', 'pong'])
Filters
BaseErrorExceptionFilter
Exception filter for BaseError that:
- Respects
loggableflag (only logs ifloggable: true) - Sets transport context automatically
- Provides structured error logging
- Handles HTTP, RPC, and WebSocket transports
Configuration Options
interface LoggerModuleOptions {
environment?: Environments; // 'development' | 'production' | 'test'
appName?: string; // Application name
level?: string; // Log level: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'
prettyPrint?: boolean; // Enable pretty printing (default: true in dev)
pinoOptions?: Partial<LoggerOptions>; // Additional Pino options
redact?: string[]; // Fields to redact (default: password, token, etc.)
serviceVersion?: string; // Service version (defaults to package.json)
}Context Fields
The logger automatically includes these fields from CLS context:
- Request Correlation:
requestId,correlationId,transactionId,operationId - Distributed Tracing:
traceId,spanId,parentSpanId,traceFlags - User Context:
userId,userRole,sessionId - Service Context:
component(http/rpc/ws),service,method - Business Context:
tenantId,organizationId,action,resource,resourceId - Infrastructure:
hostname,pod,container,region,zone,version,commit
Development
# Build
npm run build
# Lint
npm run lint
# Format
npm run format
# Test
npm run test
# Type check
npm run type-checkLicense
MIT © sklv-labs
