Skip to Content
Logger Documentation

Logger Documentation

This documentation explains the features and usage of Logger Module: Located at src/common/logger

Overview

Comprehensive logging system using Pino with file rotation, sensitive data redaction, Sentry integration, and custom serializers for request/response logging. The system includes HTTP request/response logging, automatic sensitive data redaction, file rotation, configurable log levels, pretty printing for development, route exclusion for health checks, request ID tracking across services, Sentry error tracking, and memory usage and uptime debugging for non-production environments.

Table of Contents

Configuration

Environment Variables

Configuration is managed through environment variables. Add these to your .env file:

# Logger Configuration LOGGER_ENABLE=true LOGGER_LEVEL=debug LOGGER_INTO_FILE=false LOGGER_PRETTIER=true LOGGER_AUTO=false # Sentry Configuration (Optional) SENTRY_DSN=https://your-sentry-dsn@sentry.io/project-id
VariableDescriptionTypeDefaultRequired
LOGGER_ENABLEEnable/disable loggingbooleanfalseNo
LOGGER_LEVELMinimum log levelstringdebugNo
LOGGER_INTO_FILEWrite logs to filesbooleanfalseNo
LOGGER_PRETTIEREnable pretty-printing in consolebooleanfalseNo
LOGGER_AUTOEnable automatic HTTP request/response loggingbooleanfalseNo
SENTRY_DSNSentry Data Source Name for error trackingstringundefinedNo

Configuration Interface

OptionDescriptionDefault
enableEnable/disable loggingfalse
levelMinimum log level (error, warn, info, verbose, debug, silly)debug
intoFileWrite logs to filesfalse
filePathDirectory path for log files/logs
autoEnable automatic HTTP request/response loggingfalse
prettierEnable pretty-printing in consolefalse
sentry.dsnSentry DSN for error trackingundefined
sentry.timeoutSentry request timeout10000ms (10s)

Usage

Use NestJS  Logger throughout the application:

import { Logger } from '@nestjs/common'; export class UserService { private readonly logger = new Logger(UserService.name); async createUser(data: CreateUserDto) { this.logger.log('Creating new user'); try { const user = await this.userRepository.create(data); this.logger.log(`User created: ${user.id}`); return user; } catch (error) { this.logger.error(`Failed to create user: ${error.message}`, error.stack); throw error; } } async deleteUser(id: string) { this.logger.warn(`Attempting to delete user: ${id}`); // deletion logic } async getUserDetails(id: string) { this.logger.debug(`Fetching user details for: ${id}`); // fetch logic } }

Log Levels

Available log levels as defined in EnumLoggerLevel:

this.logger.error('Error message'); // error level - Critical errors this.logger.warn('Warning message'); // warn level - Warning conditions this.logger.log('Info message'); // info level - General information this.logger.verbose('Verbose message'); // verbose level - Detailed information this.logger.debug('Debug message'); // debug level - Debug information

Level Hierarchy (from highest to lowest priority):

  1. error - Critical errors that need immediate attention
  2. warn - Warning conditions that should be reviewed
  3. info - General informational messages
  4. verbose - Detailed informational messages
  5. debug - Debug-level messages for development

Note: Setting LOGGER_LEVEL=warn will log only error and warn messages, filtering out info, verbose, and debug.

Log Severity

The logger maps numeric Pino levels to severity strings as defined in EnumLoggerSeverity:

Pino LevelSeverityUse Case
≥ 60CRITICALSystem-wide critical failures
≥ 50ERRORApplication errors
≥ 40WARNINGWarning conditions
≥ 30INFOGeneral information
≥ 20DEBUGDebug information
< 20TRACETrace-level debugging

Sensitive Data Redaction

The logger automatically redacts sensitive fields to prevent exposure of credentials, tokens, and personal information in logs.

Sensitive Paths

Paths where sensitive data may be located (defined in logger.constant.ts):

export const LoggerSensitivePaths = [ 'req.body', 'req.headers', 'res.body', 'res.headers', 'request.body', 'request.headers', 'response.body', 'response.headers', ];

The logger will scan these paths in request/response objects and redact any fields matching the sensitive field list.

Sensitive Fields

Fields that are automatically redacted (defined in logger.constant.ts):

export const LoggerSensitiveFields: string[] = [ // Authentication & Authorization 'password', 'newPassword', 'oldPassword', 'token', 'authorization', 'bearer', 'secret', 'credential', 'jwt', 'x-api-key', 'apiKey', 'refreshToken', 'accessToken', 'sessionId', 'privateKey', 'secretKey', 'otp', 'recoveryCode', // Location & Personal Data 'location', 'gps', 'coordinates', 'latitude', 'longitude', // Session & Cookies 'cookie', 'cookies', ];

Redaction Rules:

  • Field names are case-insensitive (e.g., Password, PASSWORD, password all match)
  • Fields with hyphens are wrapped in brackets (e.g., req.headers["x-api-key"])
  • All matching fields are replaced with [REDACTED]

Redaction Examples

Authentication Data

Request with sensitive data:

{ "username": "john.doe", "password": "secret123", "apiKey": "abc-def-ghi-jkl", "email": "john@example.com" }

Logged as:

{ "username": "john.doe", "password": "[REDACTED]", "apiKey": "[REDACTED]", "email": "john@example.com" }

Array Truncation

Arrays longer than 10 items are automatically truncated to prevent excessive logging:

{ "items": [ "item1", "item2", "item3", "item4", "item5", "item6", "item7", "item8", "item9", "item10", { "truncated": "...[TRUNCATED] - total length 50" } ] }

Buffer Handling

Binary data (Buffers) are replaced with a placeholder:

{ "file": { "buffer": "[BUFFER]" } }

Object Depth Limitation

Objects are sanitized up to a maximum depth of 5 levels to prevent:

  • Performance issues with deeply nested objects
  • Circular reference problems
  • Excessive log size

File Logging

Enable file logging by setting LOGGER_INTO_FILE=true. Logs are written to ./logs/api.log with automatic rotation using pino-roll.

Configuration

LOGGER_INTO_FILE=true

File Rotation Settings

  • File path: ./logs/api.log
  • Size limit: 10MB per file
  • Rotation: Daily or when size limit is reached
  • Directory: Automatically created if it doesn’t exist

File Structure

logs/ └── api.log # Current log file (rotates daily or at 10MB)

Log Format

When LOGGER_PRETTIER=false, logs are written in JSON format:

{"severity":"INFO","context":"UserService","timestamp":1764577182750,"msg":"User created: user-123","service":{"name":"CompleteNestjs","environment":"production","version":"8.0.0"},"level":30}

Example Usage

// Enable file logging in production // .env.production LOGGER_ENABLE=true LOGGER_LEVEL=info LOGGER_INTO_FILE=true LOGGER_PRETTIER=false LOGGER_AUTO=true

Auto Logging

Enable automatic HTTP request/response logging with LOGGER_AUTO=true. This feature automatically logs all incoming HTTP requests and their responses without manual instrumentation.

Configuration

LOGGER_AUTO=true

Logged Information

When auto-logging is enabled, the following information is automatically captured:

Request:

  • Request ID
  • HTTP method
  • URL and path
  • Route pattern
  • User-Agent
  • Content-Type
  • Client IP address
  • Authenticated user ID
  • Query parameters (sanitized)
  • Request headers (sanitized)

Response:

  • HTTP status code
  • Response time
  • Content-Length
  • Response headers (sanitized)

Excluded Routes

Routes excluded from auto-logging (defined in logger.constant.ts):

export const LoggerExcludedRoutes: string[] = [ '/api/health', '/api/health/*', '/metrics', '/metrics/*', '/favicon.ico', '/docs', '/docs/*', '/', ];

Pattern Matching Rules

  • Exact match: /api/health - matches only this exact path
  • Wildcard suffix: /api/health/* - matches /api/health/status, /api/health/check, etc.
  • Root path: / - matches only the root endpoint
  • All patterns are case-insensitive

Adding Custom Excluded Routes

To exclude additional routes, modify the constant in src/common/logger/constants/logger.constant.ts:

export const LoggerExcludedRoutes: string[] = [ '/api/health', '/api/health/*', '/metrics', '/metrics/*', '/favicon.ico', '/docs', '/docs/*', '/', // Add your custom routes '/internal/*', '/admin/debug', ];

Auto-logging Context

All auto-logged entries use the context LoggerAutoContext to distinguish them from manual logs:

{ "severity": "INFO", "context": "LoggerAutoContext", "msg": "request completed", "req": { ... }, "res": { ... } }

Console Output

The logger supports two output modes: Pretty mode for development and JSON mode for production.

Pretty Mode (LOGGER_PRETTIER=true)

Development-friendly colored output with structured formatting using pino-pretty:

INFO [2025-12-29 15:18:54.496 +0700]: [UserService] Creating new user service: { "name": "CompleteNestjs", "environment": "local", "version": "8.0.0" } additionalData: { "userId": "user-123", "action": "create" } debug: { "memory": { "rss": 449, "heapUsed": 182 }, "uptime": 2, "pid": 12345, "hostname": "localhost" }

Features:

  • Color-coded log levels (ERROR = red, WARN = yellow, INFO = green, DEBUG = blue)
  • Timestamp in system timezone
  • Context displayed in square brackets
  • Multi-line structured data for readability

Configuration:

LOGGER_PRETTIER=true LOGGER_LEVEL=debug

JSON Mode (LOGGER_PRETTIER=false)

Production-optimized structured JSON for log aggregation and analysis tools:

{"severity":"INFO","context":"UserService","timestamp":1735461534496,"msg":"Creating new user","service":{"name":"CompleteNestJs","environment":"production","version":"8.0.0"},"additionalData":{"userId":"user-123","action":"create"},"level":30}

Features:

  • Machine-readable single-line JSON format
  • Consistent structure for parsing
  • Compatible with log aggregation tools (ELK, Datadog, CloudWatch)
  • Compact output without formatting

Configuration:

LOGGER_PRETTIER=false LOGGER_LEVEL=info

Debug Information (Non-Production)

In non-production environments (app.env !== 'production'), additional debug information is automatically included in every log entry:

{ "debug": { "memory": { "rss": 413, "heapUsed": 181 }, "uptime": 1, "pid": 12345, "hostname": "dev-server" } }

Debug Fields:

FieldDescriptionUnit
memory.rssResident Set Size - total memory allocatedMB
memory.heapUsedHeap memory currently in useMB
uptimeProcess uptime since startupseconds
pidProcess IDnumber
hostnameServer hostnamestring

Use Cases:

  • Memory leak detection
  • Performance monitoring
  • Process identification in multi-instance deployments

Note: Debug information is automatically excluded in production to reduce log size and improve performance.

Request ID Tracking

The logger extracts and tracks request IDs across services for distributed tracing and correlation.

Header Priority

Request IDs are extracted from these headers in order of priority:

export const LoggerRequestIdHeaders = [ 'x-correlation-id', // First priority 'x-request-id', // Second priority ];

Fallback Behavior

If no request ID header is found, the logger falls back to:

  1. The auto-generated request.id from the framework
  2. A new UUID generated by the framework

Usage Example

Client sends request with correlation ID:

curl -H "x-correlation-id: req-abc-123" https://api.example.com/users

Logger output:

{ "req": { "id": "req-abc-123", "method": "GET", "url": "/users" } }

Cross-Service Tracking

When making requests to other services, propagate the request ID:

async callExternalService(requestId: string) { const response = await this.httpService.get('https://external-api.com/data', { headers: { 'x-correlation-id': requestId, }, }); return response.data; }

Sentry Integration

The logger includes built-in Sentry integration for error tracking and monitoring in production environments.

Sentry Configuration

Configure Sentry by setting the SENTRY_DSN environment variable:

# .env.production SENTRY_DSN=https://your-public-key@o123456.ingest.sentry.io/7654321

Configuration Details

The Sentry configuration is defined in src/configs/logger.config.ts:

sentry: { dsn?: string; // Sentry Data Source Name timeout: number; // Request timeout in milliseconds (default: 10000ms = 10s) }

Default timeout: 10 seconds (10000ms)

Error Tracking

When Sentry DSN is configured, errors logged through the logger are automatically sent to Sentry for:

  • Error aggregation and grouping
  • Stack trace analysis
  • Release tracking
  • Environment tagging
  • User context (if available)
  • Request context (URL, method, headers)

Usage Example

export class PaymentService { private readonly logger = new Logger(PaymentService.name); async processPayment(orderId: string) { try { // Process payment logic } catch (error) { // This error will be sent to Sentry automatically this.logger.error( `Payment processing failed for order: ${orderId}`, error.stack ); throw error; } } }

Sentry Context

The logger automatically includes the following context in Sentry reports:

{ "service": { "name": "CompleteNestjs", "environment": "production", "version": "8.0.0" }, "request": { "id": "req-123-abc", "method": "POST", "url": "/api/payments", "ip": "203.0.113.45", "user": "user-789" } }

Disabling Sentry

To disable Sentry integration, simply remove or comment out the SENTRY_DSN environment variable:

# SENTRY_DSN=https://...

When DSN is not configured, errors are only logged locally without being sent to Sentry.

Last updated on