npm package: @remidosol/the-nestjs-logger
Description: A custom logger module for NestJS built with winston, pino, bunyan and common logger of NestJS
Author: remidosol
Latest version: 1.1.1

# @remidosol/the-nestjs-logger

![npm](https://img.shields.io/npm/v/@remidosol/the-nestjs-logger)
![License](https://img.shields.io/npm/l/@remidosol/the-nestjs-logger)
![Build](https://img.shields.io/github/actions/workflow/status/remidosol/nestjs-logger/ci.yml?branch=main)
![Downloads](https://img.shields.io/npm/dw/@remidosol/the-nestjs-logger)

A **flexible**, **multi-provider** logging module for **NestJS** applications. This package offers a unified logging interface with support for **Winston**, **Pino**, and **Bunyan** loggers, simplifying the integration of comprehensive logging into your NestJS projects.

## Table of Contents

- [Features](#features)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Detailed Configuration](#detailed-configuration)
  - [Winston Configuration](#winston-configuration)
  - [Pino Configuration](#pino-configuration)
  - [Bunyan Configuration](#bunyan-configuration)
  - [Async Configuration](#async-configuration)
- [Usage Examples](#usage-examples)
  - [Basic Logging](#basic-logging)
  - [Performance Profiling](#performance-profiling)
  - [Error Handling](#error-handling)
- [API Reference](#api-reference)
  - [Log Levels](#log-levels)
  - [LogData Interface](#logdata-interface)
  - [Available Methods](#available-methods)
- [Best Practices](#best-practices)
- [Contributing](#contributing)
  - [Development Setup](#development-setup)
  - [Commit Guidelines](#commit-guidelines)
- [License](#license)
- [Support](#support)
- [Acknowledgments](#acknowledgments)

## Features

- **🚀 Multiple Logger Providers**
  - **Winston** (full support)
  - **Pino** (with pretty-print support)
  - **Bunyan** (with streaming support)

- **📝 Advanced Configuration Options**
  - Type-safe configurations
  - Environment-based setup
  - Custom transport options
  - Format customization

- **🔄 File Management**
  - Daily rotating file logs
  - Size-based rotation
  - Compression support
  - Automatic cleanup

- **🌐 Network Support**
  - Syslog integration (UDP/TCP)
  - HTTP transport
  - Custom network protocols
  - Remote logging

- **🎨 Output Formatting**
  - Colorized console output
  - JSON formatting
  - Custom formatters
  - Pretty printing

- **🔍 Error Handling**
  - Detailed error tracking
  - Stack trace formatting
  - Error context preservation
  - Custom error handlers

- **📊 Context & Metadata**
  - Request context logging
  - Class context injection
  - Custom metadata
  - Global metadata

- **🔗 Request Tracking**
  - Correlation ID support
  - Request ID tracking
  - Transaction tracking
  - Request context preservation

- **⚡ Performance**
  - Performance profiling
  - Timing decorators
  - Async tracking
  - Resource monitoring

- **🔒 Security**
  - Transport-level security
  - Sensitive data masking
  - Configurable redaction
  - Secure defaults

- **🌍 Module Integration**
  - Global module support
  - Custom provider injection
  - Module configuration
  - Dynamic modules

## Installation

Install the package using your preferred package manager:

```bash
# npm
npm install @remidosol/the-nestjs-logger

# yarn
yarn add @remidosol/the-nestjs-logger

# pnpm
pnpm add @remidosol/the-nestjs-logger
```


## Quick Start

Integrate the logger into your NestJS application by configuring the `TheLoggerModule` with your preferred logger provider.

```typescript
import { Module } from '@nestjs/common';
import { TheLoggerModule, WinstonLogLevel } from '@remidosol/the-nestjs-logger';

@Module({
  imports: [
    TheLoggerModule.forRoot({
      provider: 'winston',
      defaultLevel: WinstonLogLevel.Info,
      consoleTransportOptions: [
        {
          level: WinstonLogLevel.Debug,
        },
      ],
    }),
  ],
})
export class AppModule {}
```

## Detailed Configuration

### Winston Configuration

Configure the `TheLoggerModule` to use **Winston** with advanced transport options.

```typescript
import { Module } from '@nestjs/common';
import { TheLoggerModule, WinstonLogLevel, SyslogTypeEnum } from '@remidosol/the-nestjs-logger';
import * as winston from 'winston';

@Module({
  imports: [
    TheLoggerModule.forRoot({
      provider: 'winston',
      global: true,
      winstonOptions: {
        defaultLevel: WinstonLogLevel.Info,
        defaultMeta: {
          service: 'my-service',
          environment: process.env.NODE_ENV,
        },
        consoleTransportOptions: [
          {
            level: WinstonLogLevel.Debug,
            format: winston.format.combine(
              winston.format.timestamp(),
              winston.format.colorize(),
              winston.format.json()
            ),
          },
        ],
        syslogTransportOptions: [
          {
            host: 'localhost',
            port: 514,
            protocol: 'udp4',
            type: SyslogTypeEnum.RFC5424,
            facility: 'local0',
            app_name: 'my-app',
          },
        ],
        dailyRotateFileTransportOptions: [
          {
            dirname: 'logs',
            filename: 'error-%DATE%.log',
            datePattern: 'YYYY-MM-DD-HH',
            zippedArchive: true,
            maxSize: '20m',
            maxFiles: '14d',
            level: 'error',
          },
        ],
      },
    }),
  ],
})
export class AppModule {}
```

### Pino Configuration

Set up **Pino** as your logger provider with pretty-print support and sensitive data redaction.

```typescript
import { Module } from '@nestjs/common';
import { TheLoggerModule } from '@remidosol/the-nestjs-logger';

@Module({
  imports: [
    TheLoggerModule.forRoot({
      provider: 'pino',
      pinoOptions: {
        level: 'info',
        transport: {
          target: 'pino-pretty',
          options: {
            colorize: true,
            translateTime: true,
          },
        },
        formatters: {
          level: (label) => ({ level: label }),
        },
        redact: ['password', 'secret'],
      },
    }),
  ],
})
export class AppModule {}
```

### Bunyan Configuration

Configure **Bunyan** with multiple streams and rotating file support.

```typescript
import { Module } from '@nestjs/common';
import { TheLoggerModule } from '@remidosol/the-nestjs-logger';
import * as bunyan from 'bunyan';

@Module({
  imports: [
    TheLoggerModule.forRoot({
      provider: 'bunyan',
      bunyanOptions: {
        name: 'my-app',
        level: 'info',
        streams: [
          {
            stream: process.stdout,
            level: 'debug',
          },
          {
            type: 'rotating-file',
            path: 'logs/app.log',
            period: '1d',
            count: 7,
          },
        ],
        serializers: bunyan.stdSerializers,
      },
    }),
  ],
})
export class AppModule {}
```

### Async Configuration

Load logger configurations asynchronously, such as from environment variables or external configuration services.

```typescript
import { Module } from '@nestjs/common';
import { TheLoggerModule } from '@remidosol/the-nestjs-logger';
import { ConfigModule, ConfigService } from '@nestjs/config';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
    }),
    TheLoggerModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: (configService: ConfigService) => ({
        provider: 'winston',
        winstonOptions: {
          defaultLevel: configService.get<string>('LOG_LEVEL', 'info'),
          consoleTransportOptions: [
            {
              level: configService.get<string>('CONSOLE_LOG_LEVEL', 'debug'),
            },
          ],
          syslogTransportOptions: [
            {
              host: configService.get<string>('SYSLOG_HOST', 'localhost'),
              port: configService.get<number>('SYSLOG_PORT', 514),
            },
          ],
        },
      }),
      inject: [ConfigService],
    }),
  ],
})
export class AppModule {}
```

## Usage Examples

### Basic Logging

Inject the abstract logger and utilize it within your services.

```typescript
import { Injectable } from '@nestjs/common';
import { AbstractLogger } from '@remidosol/the-nestjs-logger';

@Injectable()
export class UserService {
  constructor(private readonly logger: AbstractLogger) {}

  async createUser(userData: any) {
    this.logger.info('Creating new user', {
      context: 'UserService',
      props: { userData },
    });

    try {
      // ... user creation logic
    } catch (error) {
      this.logger.error('Failed to create user', {
        context: 'UserService',
        error,
        props: { userData },
      });
      throw error;
    }
  }
}
```

### Performance Profiling

Track performance metrics within your services.

```typescript
import { Injectable } from '@nestjs/common';
import { AbstractLogger } from '@remidosol/the-nestjs-logger';

@Injectable()
export class PerformanceService {
  constructor(private readonly logger: AbstractLogger) {}

  async heavyOperation() {
    const profileId = 'heavy-operation';

    this.logger.debug('Starting heavy operation', { context: 'PerformanceService' }, profileId);

    // Operation code here

    this.logger.debug('Completed heavy operation', { context: 'PerformanceService' }, profileId);
  }
}
```

### Error Handling

Log errors with detailed context and metadata.

```typescript
import { Injectable } from '@nestjs/common';
import { AbstractLogger } from '@remidosol/the-nestjs-logger';

@Injectable()
export class ErrorHandlingService {
  constructor(private readonly logger: AbstractLogger) {}

  async riskyOperation() {
    try {
      throw new Error('Something went wrong');
    } catch (error) {
      this.logger.error('Operation failed', {
        context: 'ErrorHandlingService',
        error,
        correlationId: 'abc-123',
        props: {
          additionalInfo: 'Some context',
          timestamp: new Date(),
        },
      });
    }
  }
}
```


## API Reference

### Log Levels

```typescript
enum CommonLogLevel {
  fatal = 'fatal',
  error = 'error',
  warn = 'warn',
  info = 'info',
  debug = 'debug',
  trace = 'trace',
}
```

### LogData Interface

```typescript
interface LogData {
  organization?: string;    // Organization name
  context?: string;         // Context name
  app?: string;             // Application name
  sourceClass?: string;     // Source class name
  correlationId?: string;   // Correlation ID
  error?: Error;            // Error object
  props?: any;              // Additional properties
}
```

## Available Methods

### `log`

```typescript
log(
  level: CommonLogLevel,
  message: string | Error,
  data?: LogData,
  profile?: string,
): void;
```

Logs a message with the specified log level.

**Parameters:**

- `level`: The severity level of the log (e.g., `info`, `error`).
- `message`: The log message or an `Error` object.
- `data`: Optional additional metadata for the log.
- `profile`: Optional profiling identifier.


### `debug`

```typescript
debug(
  message: string,
  data?: LogData,
  profile?: string,
): void;
```

Logs a debug-level message.

**Parameters:**

- `message`: The log message.
- `data`: Optional additional metadata.
- `profile`: Optional profiling identifier.


### `info`

```typescript
info(
  message: string,
  data?: LogData,
  profile?: string,
): void;
```

Logs an info-level message.

**Parameters:**

- `message`: The log message.
- `data`: Optional additional metadata.
- `profile`: Optional profiling identifier.


### `warn`

```typescript
warn(
  message: string | Error,
  data?: LogData,
  profile?: string,
): void;
```

Logs a warning-level message.

**Parameters:**

- `message`: The log message or an `Error` object.
- `data`: Optional additional metadata.
- `profile`: Optional profiling identifier.


### `error`

```typescript
error(
  message: string | Error,
  data?: LogData,
  profile?: string,
): void;
```

Logs an error-level message.

**Parameters:**

- `message`: The log message or an `Error` object.
- `data`: Optional additional metadata.
- `profile`: Optional profiling identifier.


### `fatal`

```typescript
fatal(
  message: string | Error,
  data?: LogData,
  profile?: string,
): void;
```

Logs a fatal-level message.

**Parameters:**

- `message`: The log message or an `Error` object.
- `data`: Optional additional metadata.
- `profile`: Optional profiling identifier.

**Usage Example:**

```typescript
this.logger.info('User created successfully', {
  context: 'UserService',
  userId: '12345',
});
```


## Best Practices

1. **Context Usage**
   - Always provide a context in `LogData`.
   - Use meaningful context names.
   - Maintain a consistent context hierarchy.

2. **Request Tracking**
   - Utilize correlation IDs for tracking requests across services.
   - Ensure correlation IDs are propagated through asynchronous operations.
   - Include request-specific metadata in logs.

3. **Metadata Management**
   - Include relevant metadata in the `props` field.
   - Structure metadata consistently for easier querying and analysis.
   - Avoid logging sensitive information unless properly masked or redacted.

4. **Log Levels**
   - Use appropriate log levels (`info`, `warn`, `error`, etc.) based on the severity.
   - Be consistent with log level usage across the application.
   - Document log level guidelines for team members.

5. **Error Handling**
   - Log complete error contexts, including stack traces.
   - Capture and log relevant error metadata.
   - Implement custom error handlers if necessary to enrich error logs.

6. **Performance**
   - Profile and monitor performance-intensive operations.
   - Monitor log volume to prevent performance degradation.
   - Implement log rotation and cleanup to manage log storage.

## Contributing

Contributions are welcome! Please follow the guidelines below to contribute to this project.

### Development Setup

```bash
# Clone the repository
git clone https://github.com/remidosol/nestjs-logger.git
cd nestjs-logger

# Install dependencies
npm install

# Run tests
npm run test:e2e

# Run linting
npm run lint

# Build the package
npm run build
```

### Commit Guidelines

We follow **Conventional Commits** for this project. Each commit message should adhere to the following structure:

```
<type>(<scope>): <description>

[optional body]

[optional footer(s)]
```

**Types:**

- `feat`: New feature
- `fix`: Bug fix
- `docs`: Documentation changes
- `style`: Code style changes (formatting, etc.)
- `refactor`: Code refactoring without adding features or fixing bugs
- `perf`: Performance improvements
- `test`: Adding or updating tests
- `chore`: Maintenance tasks (e.g., updating dependencies)

**Example:**

```
feat(auth): add JWT authentication support

Implemented JWT-based authentication to enhance security and scalability.
Added necessary guards and strategies.
```

## License

This project is licensed under the [MIT License](LICENSE).

## Support

- **Create an Issue:** [GitHub Issues](https://github.com/remidosol/nestjs-logger/issues)
- **Email:** [ibrahim.aksut.dev@gmail.com](mailto:ibrahim.aksut.dev@gmail.com)

## Acknowledgments

- **NestJS Team:** For providing an excellent framework.
- **Winston Contributors:** For the robust logging foundation.
- **Pino Contributors:** For high-performance logging solutions.
- **Bunyan Contributors:** For structured logging capabilities.
- **All Open-Source Contributors:** Your efforts make projects like this possible.