### Run NestJS 10 Example Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/README.md Instructions to install dependencies and start the basic NestJS 10 example application. ```bash cd examples/nestjs10-example npm install npm start ``` -------------------------------- ### Initial Project Setup Source: https://github.com/adird/nestjs-context-logger/blob/main/CONTRIBUTING.md Clone the repository, install dependencies, and run tests to verify your setup. ```bash git clone https://github.com/YOUR_USERNAME/nestjs-context-logger.git # Install dependencies npm install # Run tests to verify setup npm test ``` -------------------------------- ### Install Dependencies and Build Project Source: https://github.com/adird/nestjs-context-logger/blob/main/examples/nestjs-bullmq-example/README.md Installs project dependencies and builds the NestJS application. Navigate to the example directory before running. ```bash cd examples/nestjs-bullmq-example npm install npm run build ``` -------------------------------- ### Install Prometheus Client Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/integration-guide.md Install the prom-client package to enable Prometheus metrics. ```bash npm install prom-client ``` -------------------------------- ### Basic Context Logger Setup Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/configuration.md Enables context logging with default correlationId and duration. Use this for a straightforward setup. ```typescript ContextLoggerModule.forRoot() ``` -------------------------------- ### Install nestjs-context-logger Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/README.md Install the package using npm. This is the first step to integrate the logger into your project. ```bash npm install nestjs-context-logger ``` -------------------------------- ### ContextLoggerModule Configuration Example Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/types.md Provides a comprehensive example of configuring ContextLoggerModule with options for ignoring bootstrap logs, custom context adaptation, asynchronous context enrichment, field grouping, hooks, and Pino HTTP settings. ```typescript import { Module, ExecutionContext } from '@nestjs/common'; import { ContextLoggerModule } from 'nestjs-context-logger'; @Module({ imports: [ ContextLoggerModule.forRoot({ ignoreBootstrapLogs: true, contextAdapter: (context) => ({ ...context, sensitive: undefined, // Remove sensitive data timestamp: Date.now() // Add new fields }), enrichContext: async (ctx: ExecutionContext) => { const request = ctx.switchToHttp().getRequest(); return { userId: request.user?.id, tenantId: request.headers['x-tenant-id'] }; }, groupFields: { contextKey: 'metadata', bindingsKey: 'params' }, hooks: { error: [ (message, bindings) => { // Send errors to external service errorReporter.notify(message, bindings); } ] }, pinoHttp: { level: 'info', transport: { target: 'pino-pretty' } } }) ] }) export class AppModule {} ``` -------------------------------- ### Configure Jest Setup File Source: https://github.com/adird/nestjs-context-logger/blob/main/README.md This JSON configuration snippet shows how to tell Jest to use the custom setup file for tests. Ensure the path to your setup file is correctly specified. ```json // package.json { "jest": { "setupFilesAfterEnv": [ "jest-expect-message", "/../jest/setupFile.ts" ] } } ``` -------------------------------- ### Initial Context Initialization Example Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/init-context-middleware.md An example of the initial context object created by the middleware for a request, featuring a generated correlation ID. ```json { "correlationId": "550e8400-e29b-41d4-a716-446655440000" } ``` -------------------------------- ### URL Pattern Matching Logic Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/request-interceptor.md Demonstrates how URL exclusion patterns are matched against the request URL using prefix matching. This example shows the core logic for checking if a URL starts with a given pattern. ```typescript const request = { url: '/api/users/123' }; ['/health', '/api/public'].some(pattern => request.url.indexOf(pattern) === 0 ); // '/api/users/123'.indexOf('/health') === 0 ? false // '/api/users/123'.indexOf('/api/public') === 0 ? false ``` -------------------------------- ### Run Redis with Docker Source: https://github.com/adird/nestjs-context-logger/blob/main/examples/nestjs-bullmq-example/README.md Starts a Redis instance using Docker for BullMQ to connect to. Ensure Redis is running before proceeding. ```bash # Using Docker docker run -d -p 6379:6379 redis:latest ``` -------------------------------- ### RequestInterceptor Example Flow Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/request-interceptor.md Illustrates the lifecycle of a request processed by the RequestInterceptor, from arrival to response. ```text HTTP Request Arrives ↓ Middleware initializes context with correlationId ↓ RequestInterceptor runs ├─ Check if excluded → skip if matched ├─ Record start time ├─ Create base context { requestMethod: 'GET', requestUrl: '/api/users' } ├─ Call enrichContext(executionContext) if provided ├─ Merge enriched context into store └─ Call next handler ↓ Handler executes (any logs include enriched context) ↓ Handler completes ↓ RequestInterceptor logs duration ↓ Response sent ↓ AsyncLocalStorage cleanup ``` -------------------------------- ### Basic Module Setup Source: https://github.com/adird/nestjs-context-logger/blob/main/README.md Configure the ContextLoggerModule in your AppModule to enable contextual logging. This setup automatically includes 'correlationId' and 'duration' in your logs. ```typescript // app.module.ts import { ContextLoggerModule } from 'nestjs-context-logger'; @Module({ imports: [ ContextLoggerModule.forRoot() ], }) export class AppModule {} ``` -------------------------------- ### Install BullMQ Dependencies Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/integration-guide.md Install the necessary packages for BullMQ integration with NestJS. ```bash npm install @nestjs/bullmq bullmq ``` -------------------------------- ### Example Log Output with Context Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/context-logger-class.md Illustrates the structure of a log entry generated by ContextLogger, showing how context information like userId and correlationId is automatically included. ```json { "level": "info", "time": "2024-01-01T12:00:00.000Z", "userId": "user_123", "correlationId": "abc-123-def", "message": "Fetching user", "id": "user_456" } ``` -------------------------------- ### Log Field Grouping Example (Before and After) Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/README.md Illustrates how log fields are reorganized using the `groupFields` configuration. Contextual data is moved under a 'metadata' key. ```json { "userId": "123", "correlationId": "abc", "message": "..." } ``` ```json { "metadata": { "userId": "123", "correlationId": "abc" }, "message": "..." } ``` -------------------------------- ### Example Log Output with Context Source: https://github.com/adird/nestjs-context-logger/blob/main/README.md Illustrates how log output includes both standard Pino fields and custom context data like correlationId and userId. ```typescript logger.info('User updated'); // Output includes both Pino's standard fields and your context: // { // "level": "info", // "time": "2024-...": // From Pino // "pid": 123, // From Pino // "correlationId": "abc", // From context-logger // "userId": "456", // From your context // "message": "User updated" // } ``` -------------------------------- ### Logger Hook Usage Example Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/types.md Demonstrates how to configure log hooks for specific log levels or all levels using the LoggerHookKeys type. ```typescript import { ContextLogger, ContextLoggerModule } from 'nestjs-context-logger'; import type { LoggerHookKeys } from 'nestjs-context-logger'; ContextLoggerModule.forRoot({ hooks: { error: [ (message, bindings) => { console.error('Error logged:', message); } ], all: [ (message, bindings) => { metrics.increment('log.count'); } ] } }) ``` -------------------------------- ### Log with Bindings Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/types.md Example of how to use the Bindings type with the ContextLogger to add custom data to log entries. ```typescript import { ContextLogger } from 'nestjs-context-logger'; const logger = new ContextLogger('MyService'); const bindings: Bindings = { userId: '123', action: 'create', duration: 250, success: true }; logger.log('Operation completed', bindings); ``` -------------------------------- ### Run NestJS Application Source: https://github.com/adird/nestjs-context-logger/blob/main/examples/nestjs-bullmq-example/README.md Starts the NestJS application for development or production. The application will be accessible at http://localhost:3000. ```bash npm start # or for development npm run dev ``` -------------------------------- ### Internal LogEntry Structure Example Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/types.md Illustrates the internal LogEntry structure created when logging an error, showing how context and bindings are combined. ```typescript // When you call: logger.error('Operation failed', new Error('Timeout')); // A LogEntry is created internally: // { // level: 'error', // correlationId: '...', // userId: '...', // err: Error('Timeout'), // message: 'Operation failed' // } ``` -------------------------------- ### Initialization Order for ContextLoggerModule Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/context-logger-module.md Shows the correct order for importing ContextLoggerModule within the AppModule. Configuration modules should be imported first, followed by the logger setup, and then other application modules. ```typescript @Module({ imports: [ ConfigModule.forRoot(), // Configuration first ContextLoggerModule.forRoot(), // Logger setup DatabaseModule, // Other modules ], }) export class AppModule {} ``` -------------------------------- ### UserService Logging Example Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/types.md Illustrates logging within a service using ContextLogger, including custom bindings and automatic context enrichment. The logger is initialized with the service name. ```typescript @Injectable() export class UserService { private readonly logger = new ContextLogger(UserService.name); async getUser(id: string): Promise { const bindings: Bindings = { id, timestamp: Date.now() }; this.logger.log('Fetching user', bindings); const user = await this.database.findOne(id); // This log will include bindings and context this.logger.log('User fetched', { role: user.role }); return user; } } ``` -------------------------------- ### Conventional Commits Examples Source: https://github.com/adird/nestjs-context-logger/blob/main/CONTRIBUTING.md Examples of commit messages following the Conventional Commits specification for different types of changes. ```markdown - `feat: ` - New features that add functionality - Triggers **MINOR** version bump (1.1.0 → 1.2.0) - Example: `feat: add support for custom serializers` - `fix: ` - Bug fixes and patches - Triggers **PATCH** version bump (1.1.1 → 1.1.2) - Example: `fix: prevent context leak in concurrent requests` - `BREAKING CHANGE: ` or `feat!: ` - Changes that break backward compatibility - Triggers **MAJOR** version bump (1.0.0 → 2.0.0) - Example: `feat!: change logger API to async methods` - `docs: ` - Documentation changes only - **No version bump** - Example: `docs: improve API reference section` - `test: ` - Adding or modifying tests - **No version bump** - Example: `test: add e2e tests for Express adapter` - `refactor: ` - Code changes that neither fix bugs nor add features - **No version bump** - Example: `refactor: simplify context storage logic` - `chore: ` - Maintenance tasks, dependency updates, etc - **No version bump** - Example: `chore: update nestjs to v10` ``` -------------------------------- ### Interceptor Order Example Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/request-interceptor.md Illustrates the registration order of RequestInterceptor as a global interceptor. Context enriched by RequestInterceptor is available to subsequent interceptors and handlers. ```typescript // RequestInterceptor is registered first by ContextLoggerModule ContextLoggerModule.forRoot(), // Other global interceptors execute after { provide: APP_INTERCEPTOR, useClass: OtherInterceptor } ``` -------------------------------- ### Example Structured Log Output Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/request-interceptor.md Illustrates the structured JSON output generated by the request interceptor, including request details and duration. ```json { "level": "debug", "time": "2024-01-01T12:00:00.000Z", "correlationId": "abc-123-def", "requestMethod": "POST", "requestUrl": "/api/users", "userId": "user_123", "tenantId": "tenant_456", "duration": 125, "message": "Request completed" } ``` -------------------------------- ### Register ContextLoggerModule Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/integration-guide.md Register the ContextLoggerModule in your AppModule to enable context-aware logging. This is the minimum setup required. ```typescript import { Module } from '@nestjs/common'; import { ContextLoggerModule } from 'nestjs-context-logger'; import { AppController } from './app.controller'; @Module({ imports: [ContextLoggerModule.forRoot()], controllers: [AppController], }) export class AppModule {} ``` -------------------------------- ### Asynchronous Configuration of ContextLoggerModule Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/types.md Demonstrates how to use ContextLoggerModule.forRootAsync to configure logging asynchronously. This example injects ConfigService to set log level and enrich context with environment-specific details. ```typescript import { Module } from '@nestjs/common'; import { ConfigModule, ConfigService } from '@nestjs/config'; import { ContextLoggerModule } from 'nestjs-context-logger'; @Module({ imports: [ ConfigModule.forRoot(), ContextLoggerModule.forRootAsync({ imports: [ConfigModule], inject: [ConfigService], useFactory: (configService: ConfigService) => ({ pinoHttp: { level: configService.get('LOG_LEVEL'), }, enrichContext: async (ctx) => ({ environment: configService.get('NODE_ENV'), version: configService.get('APP_VERSION') }) }) }) ] }) export class AppModule {} ``` -------------------------------- ### Minimal NestJS Context Logger Setup Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/00-START-HERE.md Import and configure the ContextLoggerModule in your AppModule and instantiate ContextLogger in your services. Logs will automatically include correlation IDs and request details. ```typescript // app.module.ts import { ContextLoggerModule } from 'nestjs-context-logger'; @Module({ imports: [ContextLoggerModule.forRoot()] }) export class AppModule {} // any.service.ts import { ContextLogger } from 'nestjs-context-logger'; @Injectable() export class MyService { private readonly logger = new ContextLogger(MyService.name); doSomething() { this.logger.log('Working', { detail: 'value' }); // Logs include: correlationId, requestMethod, requestUrl, duration } } ``` -------------------------------- ### Register ContextLoggerModule with forRoot() Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/context-logger-module.md Use forRoot() for static configuration when the logger setup does not depend on external services. This method registers the module with synchronous options. ```typescript import { Module } from '@nestjs/common'; import { ContextLoggerModule } from 'nestjs-context-logger'; import { AppController } from './app.controller'; @Module({ imports: [ ContextLoggerModule.forRoot() ], controllers: [AppController], }) export class AppModule {} ``` -------------------------------- ### Production Configuration for ContextLoggerModule Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/INDEX.md Provides an example of configuring the ContextLoggerModule for production environments using `forRootAsync`, including setting log levels, enriching context, and excluding specific routes. ```typescript ContextLoggerModule.forRootAsync({ imports: [ConfigModule], inject: [ConfigService], useFactory: (config) => ({ pinoHttp: { level: config.get('LOG_LEVEL') }, enrichContext: async (ctx) => ({ /* ... */ }), ignoreBootstrapLogs: true, exclude: ['/health', '/metrics'], contextAdapter: (ctx) => { /* filter sensitive data */ } }) }) ``` -------------------------------- ### Context Logger Integration Example Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/context-logger-class.md Demonstrates how to use ContextLogger within a NestJS application. It shows setting up the logger, updating context in a guard, and logging within a service, with context automatically propagating. ```typescript import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; import { ContextLogger } from 'nestjs-context-logger'; @Injectable() export class UserGuard implements CanActivate { private readonly logger = new ContextLogger(UserGuard.name); async canActivate(context: ExecutionContext): Promise { const request = context.switchToHttp().getRequest(); const userId = request.headers['x-user-id']; if (!userId) { this.logger.warn('Request missing user identification'); return false; } // Update context for entire request lifecycle ContextLogger.updateContext({ userId }); this.logger.debug('User authenticated', { userId }); return true; } } @Injectable() export class UserService { private readonly logger = new ContextLogger(UserService.name); async getUser(id: string) { // Context automatically includes userId from guard this.logger.log('Fetching user', { id }); const user = await this.database.findOne(id); // Log includes context from guard + these bindings this.logger.log('User retrieved', { id: user.id, email: user.email }); return user; } } ``` -------------------------------- ### Log Structure for Aggregation Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/integration-guide.md Example of a log entry structured for aggregation systems like ELK Stack. It includes custom fields like '@timestamp', 'environment', and 'version'. ```json { "level": "info", "time": "2024-01-01T12:00:00.000Z", "@timestamp": "2024-01-01T12:00:00.000Z", "context": { "correlationId": "abc-123", "userId": "user_456", "tenantId": "tenant_789", "requestMethod": "POST", "requestUrl": "/api/users" }, "data": { "action": "create", "email": "user@example.com" }, "environment": "production", "version": "1.0.1", "message": "User created" } ``` -------------------------------- ### Configure ContextLoggerModule with Pino Options Source: https://github.com/adird/nestjs-context-logger/blob/main/README.md Integrate ContextLoggerModule into your NestJS application by providing Pino options. This setup allows for custom logging levels and transports like pino-pretty. ```typescript import { ContextLoggerModule } from '@//adird/nestjs-context-logger'; @Module({ imports: [ ContextLoggerModule.forRoot({ // Regular Pino options pinoHttp: { level: 'info', transport: { target: 'pino-pretty' } } }) ] }) ``` -------------------------------- ### Context from Method Arguments with @WithContext Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/with-context-decorator.md Extract values from method parameters to build context dynamically. This example uses job data from a BullMQ queue to populate the context with job-specific details. ```typescript import { Processor, WorkerHost } from '@nestjs/bullmq'; import { Job } from 'bullmq'; import { WithContext, ContextLogger } from 'nestjs-context-logger'; interface EmailJobData { to: string; subject: string; body: string; } @Processor('email-queue') export class EmailProcessor extends WorkerHost { private readonly logger = new ContextLogger(EmailProcessor.name); @WithContext((job: Job) => ({ jobId: job.id, jobName: job.name, queueName: job.queueName, emailRecipient: job.data.to })) async process(job: Job) { this.logger.log('Processing email job'); // Context includes jobId, jobName, queueName, emailRecipient try { await this.sendEmail(job.data); this.logger.log('Email sent successfully'); } catch (error) { this.logger.error('Failed to send email', error as Error); } } } ``` -------------------------------- ### Configure Logger Asynchronously with Environment Variables Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/context-logger-module.md Dynamically configure the logger using forRootAsync() and environment variables. This example sets the log level based on NODE_ENV and conditionally modifies context data for production. ```typescript ContextLoggerModule.forRootAsync({ useFactory: () => { const isProduction = process.env.NODE_ENV === 'production'; return { pinoHttp: { level: isProduction ? 'info' : 'debug' }, ignoreBootstrapLogs: isProduction, contextAdapter: (context) => { if (isProduction) { // Remove sensitive data in production const { sensitive, ...rest } = context; return rest; } return context; } }; } }) ``` -------------------------------- ### NestJS Controller with ContextLogger Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/with-context-decorator.md Example of a NestJS controller using ContextLogger. The logger is initialized with the controller's name. The getUser method demonstrates an asynchronous operation that will inherit and potentially merge context. ```typescript import { Controller, Get, Param } from '@nestjs/common'; import { ContextLogger } from '../context-logger'; // Assuming ContextLogger is in a shared location @Controller('users') export class UserController { private readonly logger = new ContextLogger(UserController.name); @Get(':id') async getUser(@Param('id') id: string) { // HTTP context: { correlationId: 'req-123', userId: 'user-456' } await this.userService.processUser(id); // Context restored after method completes } } ``` -------------------------------- ### Configure Advanced Hooks for Critical Errors and Warnings Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/configuration.md This example demonstrates advanced hook configurations, including alerting on critical errors and logging warnings to a secondary system. It highlights conditional logic within hooks. ```typescript hooks: { error: [ (message, bindings) => { // Alert on critical errors if (bindings.severity === 'critical') { alerting.sendAlert({ title: message, details: bindings, channel: 'slack' }); } } ], warn: [ (message, bindings) => { // Log warnings to secondary system secondaryLogger.warn(message, bindings); } ] } ``` -------------------------------- ### init() Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/context-logger-class.md Initializes the ContextLogger with the underlying Pino logger instance and configuration options. This method is called automatically by the `ContextLoggerModule` during module initialization. ```APIDOC ## init() ```typescript static init(logger: NestJSPinoLogger, options?: ContextLoggerFactoryOptions): void ``` ### Description Initializes the ContextLogger with the underlying Pino logger instance and configuration options. This method is called automatically by the `ContextLoggerModule` during module initialization. ### Parameters #### Path Parameters - **logger** (NestJSPinoLogger) - Required - The Pino logger instance from nestjs-pino - **options** (ContextLoggerFactoryOptions) - Optional - Configuration options for context enrichment, field grouping, hooks, etc. **Source:** `src/context-logger.ts:14` ``` -------------------------------- ### Register and Use ContextLogger Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/INDEX.md Demonstrates the basic steps to register the ContextLoggerModule, create an instance of ContextLogger, and log messages with additional fields. ```typescript // 1. Register module ContextLoggerModule.forRoot() // 2. Create logger private readonly logger = new ContextLogger(MyService.name); // 3. Log messages this.logger.log('Message', { field: 'value' }); ``` -------------------------------- ### Bootstrap Logs vs. Request Logs Source: https://github.com/adird/nestjs-context-logger/blob/main/README.md Illustrates the difference between logs generated during application bootstrap and standard contextual logs. Bootstrap logs may lack context due to asynchronous initialization. ```text [Nest] 12345 - 12/08/2024, 2:43:09 PM LOG [RouterExplorer] Mapped {/api/users, GET} route +0ms [Nest] 12345 - 12/08/2024, 2:43:09 PM LOG [RouterExplorer] Mapped {/api/users/:id, POST} route +0ms [Nest] 12345 - 12/08/2024, 2:43:09 PM LOG [RoutesResolver] UserController {/api/users}: +0ms ``` ```json { "level": "info", "time": "2024-12-08T14:43:09.123Z", "correlationId": "abc-123", "service": "UserService", "message": "Processing user request" } ``` -------------------------------- ### Platform Support: Express and Fastify Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/context-logger-module.md Demonstrates how to create a NestJS application instance with either the default Express platform or the Fastify platform using FastifyAdapter. ```typescript // Express (default) const app = await NestFactory.create(AppModule); // Fastify const app = await NestFactory.create( AppModule, new FastifyAdapter() ); ``` -------------------------------- ### Constructor Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/context-logger-class.md Creates a new ContextLogger instance. The module name is included in all log output for identification purposes. ```APIDOC ## Constructor ```typescript constructor(moduleName: string) ``` ### Description Creates a new ContextLogger instance. The module name is included in all log output for identification purposes. ### Parameters #### Path Parameters - **moduleName** (string) - Required - Name of the module or class using the logger. Typically the class name (e.g., `UserService.name`). Included in log output for traceability. ### Example ```typescript import { ContextLogger } from 'nestjs-context-logger'; @Injectable() export class UserService { private readonly logger = new ContextLogger(UserService.name); async findUser(id: string) { this.logger.log('Finding user', { userId: id }); } } ``` ``` -------------------------------- ### Running Tests Source: https://github.com/adird/nestjs-context-logger/blob/main/CONTRIBUTING.md Execute the test suite using npm commands. Use watch mode for continuous testing during development. ```bash # Run full test suite npm test # Run tests in watch mode npm run test:watch ``` -------------------------------- ### Correlation ID in Logs Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/init-context-middleware.md Example of how a correlation ID appears in log entries, enabling tracking of a single request across different systems. ```json { "level": "info", "time": "2024-01-01T12:00:00.000Z", "correlationId": "550e8400-e29b-41d4-a716-446655440000", "message": "Processing request" } ``` -------------------------------- ### @WithContext Decorator - Basic Usage Source: https://github.com/adird/nestjs-context-logger/blob/main/README.md Demonstrates the basic usage of the @WithContext decorator with a static object for initializing context in a message pattern handler. ```APIDOC ## @WithContext Decorator - Basic Usage ### Description This example shows how to use the `@WithContext` decorator with a static object to set context for a NestJS message pattern. ### Method Signature `@WithContext({ key: 'value' })` ### Example ```typescript import { WithContext } from 'nestjs-context-logger'; @Injectable() export class UserService { private readonly logger = new ContextLogger(UserService.name); @WithContext({ service: 'UserService' }) @MessagePattern('user.created') async handleUserCreated(data: CreateUserDto) { this.logger.log('Processing user creation'); // Output: { service: 'UserService', message: "Processing user creation" } } } ``` ``` -------------------------------- ### ContextLoggerModule.forRoot() Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/context-logger-module.md Registers the ContextLoggerModule with synchronous configuration options. Use this method when your configuration is static and does not depend on external services. ```APIDOC ## ContextLoggerModule.forRoot() ### Description Registers the `ContextLoggerModule` with synchronous configuration options. Use this method when your configuration is static and does not depend on external services. ### Method `static forRoot(options?: ContextLoggerFactoryOptions): DynamicModule` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters Table | Parameter | Type | Required | Default | Description | |-----------|----------|----------|---------|-------------| | options | ContextLoggerFactoryOptions | No | {} | Configuration object for the logger module | ### Returns A NestJS `DynamicModule` that configures the logging system. ### Example: Basic Setup ```typescript import { Module } from '@nestjs/common'; import { ContextLoggerModule } from 'nestjs-context-logger'; import { AppController } from './app.controller'; @Module({ imports: [ ContextLoggerModule.forRoot() ], controllers: [AppController], }) export class AppModule {} ``` ### Example: With Pino Configuration ```typescript import { Module } from '@nestjs/common'; import { ContextLoggerModule } from 'nestjs-context-logger'; @Module({ imports: [ ContextLoggerModule.forRoot({ pinoHttp: { level: 'debug', transport: { target: 'pino-pretty', options: { colorize: true, } } } }) ], }) export class AppModule {} ``` ### Example: With Custom Context Enrichment ```typescript import { Module, ExecutionContext } from '@nestjs/common'; import { ContextLoggerModule } from 'nestjs-context-logger'; @Module({ imports: [ ContextLoggerModule.forRoot({ enrichContext: (context: ExecutionContext) => { const request = context.switchToHttp().getRequest(); return { requestId: request.id, userAgent: request.headers['user-agent'], ip: request.ip }; } }) ], }) export class AppModule {} ``` ### Example: With Field Grouping ```typescript ContextLoggerModule.forRoot({ groupFields: { contextKey: 'metadata', bindingsKey: 'params' } }) ``` This groups log fields into structured sections rather than spreading them at the root level. ### Example: With Hooks ```typescript ContextLoggerModule.forRoot({ hooks: { error: [ (message, bindings) => { // Send error to external service externalErrorReporting.notify(message, bindings); } ], all: [ (message, bindings) => { metrics.increment('logs.total'); } ] } }) ``` ``` -------------------------------- ### Get Current Logging Context Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/README.md Retrieve the current logging context, which includes automatically generated fields like correlationId and any custom fields added. ```typescript const context = ContextLogger.getContext(); ``` -------------------------------- ### Running Code with Context Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/init-context-middleware.md Demonstrates how to run a block of code with a specific context, ensuring the context is accessible within the block and automatically cleaned up afterward. This is useful for setting up request-specific data. ```typescript runWithCtx(() => { // Context accessible here ContextLogger.getContext(); // Even in nested async await asyncOperation(); }, { correlationId: '...' }); // After function returns, context is cleaned up // getContext() would return {} if called here (outside middleware scope) ``` -------------------------------- ### NestJS Service with @WithContext Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/with-context-decorator.md Example of a NestJS service demonstrating the @WithContext decorator. The processUser method merges its own context with any inherited context, with decorator values taking precedence. ```typescript import { Injectable } from '@nestjs/common'; import { ContextLogger, WithContext } from '../context-logger'; // Assuming ContextLogger and WithContext are in a shared location @Injectable() export class UserService { private readonly logger = new ContextLogger(UserService.name); @WithContext({ operation: 'process', service: 'UserService' }) async processUser(id: string) { // Merged context: // { // correlationId: 'req-123', (inherited from HTTP request) // userId: 'user-456', (inherited from HTTP request) // operation: 'process', (from decorator) // service: 'UserService' (from decorator) // } this.logger.log('Processing user'); } } ``` -------------------------------- ### Conditional Context Transformation for Production Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/configuration.md Adapt log context differently based on the environment. This example strips debug fields in production while returning the original context otherwise. ```typescript contextAdapter: (context) => { if (process.env.NODE_ENV === 'production') { // Strip debug fields in production const { debug, internal, ...safe } = context; return safe; } return context; } ``` -------------------------------- ### Configure ContextLoggerModule with Pino Options Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/context-logger-module.md Customize the underlying Pino logger by passing pinoHttp configuration options to forRoot(). This allows setting log levels and enabling pretty-printing for development. ```typescript import { Module } from '@nestjs/common'; import { ContextLoggerModule } from 'nestjs-context-logger'; @Module({ imports: [ ContextLoggerModule.forRoot({ pinoHttp: { level: 'debug', transport: { target: 'pino-pretty', options: { colorize: true, } } } }) ], }) export class AppModule {} ``` -------------------------------- ### runWithCtx(fx, context) Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/context-store.md Executes a function within a new context scope, creating an isolated AsyncLocalStorage context. Updates within the function are scoped to that execution. ```APIDOC ## runWithCtx(fx: (ctx: Record) => any, context?: Record): any ### Description Executes a function within a new context scope. Creates an isolated `AsyncLocalStorage` context that executes the provided function. Any context updates within the function are scoped to that execution and do not affect the parent context. ### Parameters #### Path Parameters - **fx** (Function) - Required - The function to execute. Receives the current context as a parameter. - **context** (Record) - Optional - Initial context for this scope. Merged with any existing parent context. ### Returns The return value of the executed function. ### Example: Basic Usage ```typescript import { runWithCtx, ContextStore } from 'nestjs-context-logger'; runWithCtx(() => { ContextStore.updateContext({ userId: '123' }); console.log(ContextStore.getContext().userId); // '123' }, { correlationId: 'abc' }); console.log(ContextStore.getContext().userId); // undefined ``` ### Example: Context Merging ```typescript import { runWithCtx, ContextStore } from 'nestjs-context-logger'; ContextStore.updateContext({ parentField: 'parent' }); runWithCtx(() => { const ctx = ContextStore.getContext(); console.log(ctx.parentField); // 'parent' console.log(ctx.childField); // 'child' }, { childField: 'child' }); ``` ### Example: Async Operations ```typescript import { runWithCtx, ContextStore } from 'nestjs-context-logger'; async function processRequest(requestId: string) { return runWithCtx(async () => { ContextStore.updateContext({ requestId }); await delay(100); console.log(ContextStore.getContext().requestId); await innerAsyncOperation(); return 'done'; }); } async function innerAsyncOperation() { console.log(ContextStore.getContext().requestId); } ``` ### Example: Exception Handling ```typescript import { runWithCtx, ContextStore } from 'nestjs-context-logger'; try { runWithCtx(() => { ContextStore.updateContext({ operation: 'process' }); throw new Error('Operation failed'); }); } catch (error) { console.log(ContextStore.getContext().operation); // undefined console.log(error.message); // 'Operation failed' } ``` ``` -------------------------------- ### Get Current Context Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/context-store.md Retrieves a shallow copy of the current context. Returns an empty object if no context is available. Modifications to the returned object do not affect the stored context. ```typescript import { ContextStore } from 'nestjs-context-logger'; const context = ContextStore.getContext(); console.log(context.userId); // Access context fields console.log(context.correlationId); // Read-only access ``` -------------------------------- ### Context Transformation for Sensitive Data Removal Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/README.md Customize the logging context by transforming it before it's logged. This example removes sensitive fields like 'password' and 'apiKey' and adds a 'timestamp'. ```typescript ContextLoggerModule.forRoot({ contextAdapter: (context) => { const { password, apiKey, ...safe } = context; return { ...safe, timestamp: Date.now() }; } }) ``` -------------------------------- ### Multi-Parameter Context Extraction with @WithContext Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/with-context-decorator.md When the decorated method has multiple parameters, the context function receives all of them. This example extracts context from both payload and metadata arguments of a message pattern handler. ```typescript import { MessagePattern } from '@nestjs/microservices'; import { WithContext, ContextLogger } from 'nestjs-context-logger'; import { v4 as uuid } from 'uuid'; @Injectable() export class TransactionService { private readonly logger = new ContextLogger(TransactionService.name); @MessagePattern('transaction.process') @WithContext((payload, metadata) => ({ transactionId: payload.id, customerId: payload.customerId, amount: payload.amount, messageId: metadata.messageId, correlationId: uuid() })) async processTransaction(payload: any, metadata: any) { this.logger.log('Processing transaction'); // Full context available from both payload and metadata } } ``` -------------------------------- ### InitContextMiddleware Implementation Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/init-context-middleware.md The core implementation of the InitContextMiddleware. It uses `runWithCtx` to create an isolated context scope for each request, initializing it with a generated UUID v4 correlation ID before proceeding to the next middleware or handler. ```typescript import { Injectable, NestMiddleware } from '@nestjs/common'; import { runWithCtx } from 'nestjs-context-logger'; import { v4 as uuidv4 } from 'uuid'; @Injectable() export class InitContextMiddleware implements NestMiddleware { use(_req: unknown, _res: unknown, next: () => void) { runWithCtx(async () => next(), { correlationId: uuidv4(), }); } } ``` -------------------------------- ### Access Enriched Tenant Context in Services Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/integration-guide.md Services can access the enriched tenant context directly using `ContextLogger.getContext()`. This example shows how to retrieve the `tenantId` and include it when logging or saving data. ```typescript @Injectable() export class UserService { private readonly logger = new ContextLogger(UserService.name); async createUser(data: CreateUserDto) { // Context automatically includes tenantId this.logger.log('Creating user', { email: data.email }); const user = await this.database.users.create({ ...data, tenantId: ContextLogger.getContext().tenantId }); this.logger.log('User created', { userId: user.id }); return user; } } ``` -------------------------------- ### Multi-Tenant Configuration for Context Logger Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/configuration.md Dynamically enriches log context with tenant-specific information fetched asynchronously. Use this in multi-tenant applications to identify logs by tenant. ```typescript ContextLoggerModule.forRootAsync({ imports: [ConfigModule], inject: [ConfigService], useFactory: (configService: ConfigService) => ({ pinoHttp: { level: configService.get('LOG_LEVEL') }, enrichContext: async (context) => { const request = context.switchToHttp().getRequest(); const tenantId = request.headers['x-tenant-id']; if (!tenantId) { return {}; } const tenant = await tenantService.findOne(tenantId); return { tenantId, tenantName: tenant.name, logLevel: tenant.logLevel || 'info' }; } }) }) ``` -------------------------------- ### Mock ContextLogger for Unit Tests Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/integration-guide.md Mock the ContextLogger for unit tests to verify logging behavior without actual I/O operations. This setup replaces the actual logger with Jest mock functions. ```typescript // test setup jest.mock('nestjs-context-logger', () => ({ ContextLogger: jest.fn().mockImplementation(() => ({ log: jest.fn(), debug: jest.fn(), warn: jest.fn(), error: jest.fn(), fatal: jest.fn(), info: jest.fn(), verbose: jest.fn() })) })); // In tests import { ContextLogger } from 'nestjs-context-logger'; describe('UserService', () => { let service: UserService; let logSpy: jest.SpyInstance; beforeEach(async () => { logSpy = jest.spyOn(ContextLogger.prototype, 'log'); service = new UserService(); }); it('should log user creation', async () => { await service.createUser({ email: 'test@example.com' }); expect(logSpy).toHaveBeenCalledWith( 'User created', expect.objectContaining({ email: 'test@example.com' }) ); }); }); ``` -------------------------------- ### Logging Hooks for Side Effects Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/README.md Execute custom logic when logs are generated using logging hooks. This example shows how to notify an error reporting service for errors and increment a metric for all logs. ```typescript ContextLoggerModule.forRoot({ hooks: { error: [ (message, bindings) => { errorReporting.notify(message, bindings); } ], all: [ (message, bindings) => { metrics.increment('logs.total'); } ] } }) ``` -------------------------------- ### Instantiate and Use ContextLogger Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/README.md Create a logger instance for a specific service and log messages with optional context. ```typescript const logger = new ContextLogger(MyService.name); logger.log('Message', { customField: 'value' }); logger.debug('Debug message'); logger.warn('Warning'); logger.error('Error occurred', error); logger.fatal('Fatal error', error); ``` -------------------------------- ### Static Context Object with @WithContext Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/with-context-decorator.md Use a static context object when the context is the same for every method invocation. This example demonstrates setting static service and operation context for a message pattern handler. ```typescript import { MessagePattern } from '@nestjs/microservices'; import { WithContext, ContextLogger } from 'nestjs-context-logger'; @Injectable() export class UserService { private readonly logger = new ContextLogger(UserService.name); @MessagePattern('user.validate') @WithContext({ service: 'UserService', operation: 'validate' }) async validateUser(data: any) { this.logger.log('Validating user'); // Context: { service: 'UserService', operation: 'validate', correlationId: '...', ... } } } ``` -------------------------------- ### Log a message with bindings Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/context-logger-class.md Use the log method to record informational messages with additional context. This is the recommended method for general logging. ```typescript this.logger.log('User created successfully', { userId: newUser.id, email: newUser.email }); ``` -------------------------------- ### Sensitive Data Filtering in Context Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/request-interceptor.md Filter out sensitive data from the log context. This example specifically avoids logging sensitive headers or query parameters, focusing only on essential user and path information. ```typescript enrichContext: (context: ExecutionContext) => { const request = context.switchToHttp().getRequest(); const enriched = { userId: request.user?.id, path: request.path }; // Don't log sensitive headers or query parameters return enriched; } ``` -------------------------------- ### NestJS Context Logger Module Configuration Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/types.md Configures the ContextLoggerModule with custom context adapters and enrichment functions. This example shows how to add user and tenant IDs to logs based on request data. ```typescript import { Module, ExecutionContext } from '@nestjs/common'; import { ContextLoggerModule, ContextLogger, Bindings } from 'nestjs-context-logger'; interface CustomContext extends Bindings { userId?: string; tenantId?: string; timestamp: number; } @Module({ imports: [ ContextLoggerModule.forRoot({ contextAdapter: (context: Record): Record => { const customContext: CustomContext = { ...context, timestamp: Date.now() }; return customContext; }, enrichContext: async (executionContext: ExecutionContext): Promise => { const request = executionContext.switchToHttp().getRequest(); return { userId: request.user?.id, tenantId: request.headers['x-tenant-id'] }; } }) ] }) export class AppModule {} ``` -------------------------------- ### Instantiate ContextLogger Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/context-logger-class.md Create a new ContextLogger instance, providing the module name for identification in log output. Typically, the class name is used. ```typescript import { ContextLogger } from 'nestjs-context-logger'; @Injectable() export class UserService { private readonly logger = new ContextLogger(UserService.name); async findUser(id: string) { this.logger.log('Finding user', { userId: id }); } } ``` -------------------------------- ### Run Code with Custom Context Scope Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/context-store.md Executes a given task within an isolated context, allowing for custom context data to be set for background operations. Ensure `uuid` is installed for taskId generation. ```typescript import { Injectable } from '@nestjs/common'; import { runWithCtx, ContextStore, ContextLogger } from 'nestjs-context-logger'; import { v4 as uuid } from 'uuid'; @Injectable() export class BackgroundService { private readonly logger = new ContextLogger(BackgroundService.name); async executeInBackground(taskName: string, task: () => Promise) { // Create isolated context for background execution return runWithCtx(async () => { ContextStore.updateContext({ taskName, taskId: uuid(), executedAt: new Date().toISOString() }); this.logger.log('Background task started'); try { await task(); this.logger.log('Background task completed'); } catch (error) { this.logger.error('Background task failed', error as Error); throw error; } }); } } ``` -------------------------------- ### Development Configuration for Context Logger Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/configuration.md Configures pretty-printed logs with debug level and includes bootstrap messages. Ideal for local development environments. ```typescript ContextLoggerModule.forRoot({ pinoHttp: { level: 'debug', transport: { target: 'pino-pretty', options: { colorize: true } } }, ignoreBootstrapLogs: false }) ``` -------------------------------- ### Context Enrichment by RequestInterceptor Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/api-reference/init-context-middleware.md Illustrates the context object's evolution from middleware initialization to RequestInterceptor enrichment, showing added request details and custom fields. ```typescript // After middleware only { correlationId: 'abc-123' } ``` ```typescript // After interceptor { correlationId: 'abc-123', requestMethod: 'GET', requestUrl: '/api/users', userId: 'user_456', // from enrichContext tenantId: 'tenant_789' // from enrichContext } ``` -------------------------------- ### Logging with Context in Background Jobs Source: https://github.com/adird/nestjs-context-logger/blob/main/_autodocs/00-START-HERE.md Utilize the @WithContext decorator on a processor method to automatically enrich logs with job-specific data. This example adds jobId and recipient to logs within the email processing job. ```typescript @Processor('email-queue') export class EmailProcessor { @WithContext((job: Job) => ({ jobId: job.id, recipient: job.data.to })) async process(job: Job) { this.logger.log('Sending email'); // Includes jobId, recipient } } ``` -------------------------------- ### Mock ContextLogger for Jest Tests Source: https://github.com/adird/nestjs-context-logger/blob/main/README.md This TypeScript code creates a mock implementation of ContextLogger for use in Jest tests. It mocks all logging methods and static context methods. Configure Jest to use this setup file. ```typescript // jest/setupFile.ts import 'jest-expect-message'; class MockContextLogger { public log() { return jest.fn(); } public debug() { return jest.fn(); } public warn() { return jest.fn(); } public error() { return jest.fn(); } public static getContext() { return {}; } public static updateContext() { return jest.fn(); } } jest.mock('nestjs-context-logger', () => { return { ContextLogger: MockContextLogger }; }); ```