1.1.1 • Published 6 months ago

@remidosol/the-nestjs-logger v1.1.1

Weekly downloads
-
License
MIT
Repository
github
Last release
6 months ago

@remidosol/the-nestjs-logger

npm License Build Downloads

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

  • 🚀 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:

# 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.

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.

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.

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.

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.

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.

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.

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.

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

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

LogData Interface

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

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

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

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

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

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

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:

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

# 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.

Support

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.