npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@samofprog/nestjs-request-logger

v1.0.0

Published

A production-ready NestJS middleware for comprehensive HTTP request/response logging with security features

Readme

📡 NestJS Request Logger

npm version npm downloads License: MIT Node.js Version

A powerful, production-ready HTTP middleware for logging requests and responses in NestJS applications with enterprise-grade features.

Overview

NestJS Request Logger provides comprehensive HTTP request/response logging with:

  • Security-First Design: Automatic masking of sensitive headers (authorization, cookies, API keys)
  • High-Precision Timing: Nanosecond-accurate request duration measurement
  • Framework Agnostic: Full support for Express and Fastify adapters
  • Flexible Configuration: Customizable formatters, sanitizers, and path filters
  • Production Ready: Zero external dependencies, extensive error handling, TypeScript support

Perfect for debugging, monitoring, auditing, and compliance requirements in enterprise NestJS applications.

✨ Features

| Feature | Description | |------------------------------------------|----------------------------------------------------------------| | 📥 Detailed request and response logging | Logs HTTP method, path, headers, status codes, and duration | | 🔒 Sensitive header masking | Allows masking sensitive headers like Authorization or Cookie | | 🚫 Path ignoring | Ignore logging on specific paths | | 📝 Custom log message formatting | Customize incoming and completed request log messages | | 🛠 Custom logger support | Use your own LoggerService or fallback to NestJS global logger | | ⚠️ Log level distinction | Successful responses logged with log, errors with error | | ⚙️ Framework compatibility | Works with both Express and Fastify | | 🎛️ Configurable logging levels | Control what data to log: headers, request body, response data |

📦 Installation

Install the package using npm or yarn:

npm install @samofprog/nestjs-request-logger
# or
yarn add @samofprog/nestjs-request-logger

🚀 Usage

Method 1: Using the Helper Function (Recommended)

Use the helper function in your NestJS bootstrap file:

import { requestLoggerFactory } from '@samofprog/nestjs-request-logger';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  app.use(requestLoggerFactory());

  await app.listen(3000);
}
bootstrap();

Method 2: Using Providers (Advanced)

For more advanced use cases with dependency injection:

import { createRequestLoggerProviders } from '@samofprog/nestjs-request-logger';

@Module({
  providers: [
    ...createRequestLoggerProviders({
      ignorePaths: ['/health'],
      headerFields: ['content-type', 'authorization'],
    }),
  ],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(RequestLoggerMiddleware).forRoutes('*');
  }
}

⚙️ Usage with Custom Configuration

You can customize the middleware behavior with options:

import { requestLoggerFactory } from '@samofprog/nestjs-request-logger';

app.use(requestLoggerFactory({
  ignorePaths: ['/health', '/metrics'],
  sensitiveHeaders: ['authorization', 'cookie'],
  sanitizeHeaders: (headers) => {
    const sanitized = { ...headers };
    ['authorization', 'cookie'].forEach(key => {
      if (sanitized[key]) sanitized[key] = '[REDACTED]';
    });
    return sanitized;
  },
  incomingRequestMessage: (details) =>
    `Incoming: ${details.method} ${details.url} → headers: ${JSON.stringify(details.headers)}`,
  completedRequestMessage: (details) =>
    `Completed: ${details.method} ${details.url} ← status ${details.statusCode} in ${details.durationMs} ms`,
}));

🛠 Options

| Option | Type | Description | Default | |---------------------------|---------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|-------------------------------| | logger | LoggerService | Custom logger implementing NestJS LoggerService interface. | NestJS default logger | | ignorePaths | string[] | List of URL paths to ignore from logging. | [] | | sensitiveHeaders | string[] | List of header names to mask in logs (case-insensitive). | ['authorization', 'cookie', 'set-cookie', 'x-api-key'] | | sanitizeHeaders | (headers: Record<string, any>) => Record<string, any> | Function to transform headers before logging (e.g., to mask values). | Identity function (no change) | | incomingRequestMessage | (details) => string | Function returning the log message for incoming requests. Receives { method, url, headers, body }. | Default formatted string | | completedRequestMessage | (details) => string | Function returning the log message for completed requests. Receives { method, url, statusCode, durationMs }. | Default formatted string | | logRequestBody | boolean | Whether to include request body in the log messages. | false | | headerFields | string[] | List of specific header fields to include in logs. | All headers |


🧩 Examples

🚫 Ignore paths and 🔒 mask sensitive headers

app.use(requestLoggerFactory({
  ignorePaths: ['/health', '/metrics'],
  sensitiveHeaders: ['authorization', 'cookie'],
}));

🧼 Custom sanitization of headers

app.use(requestLoggerFactory({
  sanitizeHeaders: (headers) => {
    const sanitized = { ...headers };
    if (sanitized['authorization']) sanitized['authorization'] = '[TOKEN REDACTED]';
    if (sanitized['cookie']) sanitized['cookie'] = '[COOKIE REDACTED]';
    return sanitized;
  }
}));

🎛️ Configure logging levels

app.use(requestLoggerFactory({
  logRequestBody: true,    // Include request body in logs (default: false)
  headerFields: ['content-type', 'authorization'], // Specific headers to log
}));

🛠 Custom logger

import { Logger } from '@nestjs/common';

const customLogger = new Logger('MyCustomLogger');

app.use(requestLoggerFactory({ logger: customLogger }));

🔧 Default Sensitive Headers

By default, the following headers are automatically masked:

const DEFAULT_SENSITIVE_HEADERS = [
  'authorization',
  'cookie',
  'set-cookie',
  'x-api-key'
];

📋 Default Log Message Format

The middleware formats log messages in a structured key=value format with descriptive prefixes for easy parsing and readability:

Incoming Request:

Incoming request: method=GET path=/api/users content-type=application/json

Completed Request:

Request completed: method=GET path=/api/users statusCode=200 durationMs=45.23ms

This format provides:

  • Clear prefixes identifying request lifecycle
  • Key=value pairs for easy parsing by log aggregation tools
  • camelCase keys following Node.js conventions
  • Structured data that's human-readable and machine-parseable

📊 Custom Message Formatters

Format log messages to match your requirements:

app.use(requestLoggerFactory({
  incomingRequestMessage: (details) => {
    const timestamp = new Date().toISOString();
    return `[${timestamp}] → ${details.method} ${details.url}`;
  },
  completedRequestMessage: (details) => {
    const logLevel = details.statusCode >= 400 ? '❌ ERROR' : '✅ SUCCESS';
    return `[${logLevel}] ← ${details.method} ${details.url} | Status: ${details.statusCode} | Duration: ${details.durationMs}ms`;
  },
}));

🔗 With ConfigService (NestJS Config)

Load configuration from environment variables:

import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { requestLoggerFactory } from '@samofprog/nestjs-request-logger';

@Module({
  imports: [ConfigModule.forRoot()],
})
export class AppModule implements NestModule {
  constructor(private configService: ConfigService) {}

  configure(consumer: MiddlewareConsumer) {
    const headerFields = this.configService.get('HEADER_FIELDS', '').split(',').filter(Boolean);
    const logBody = this.configService.get('LOG_REQUEST_BODY') === 'true';
    const ignorePaths = this.configService.get('IGNORE_PATHS', '/health,/metrics').split(',');

    consumer
      .apply(requestLoggerFactory({
        headerFields,
        logRequestBody: logBody,
        ignorePaths,
      }))
      .forRoutes('*');
  }
}

🎯 Path Matching Patterns

The middleware supports multiple path matching strategies:

app.use(requestLoggerFactory({
  ignorePaths: [
    // Exact substring match
    '/health',
    '/metrics',
    '/swagger',

    // Wildcard patterns (converted to regex)
    '/static/*',
    '/api/internal/*',
    '/uploads/*',

    // Complex regex patterns
    '/api/v[0-9]+/public',
    '/temp/.*\\.tmp',
  ],
}));

🔐 Advanced Security Configuration

Implement granular control over sensitive data:

app.use(requestLoggerFactory({
  sensitiveHeaders: [
    'authorization',
    'cookie',
    'set-cookie',
    'x-api-key',
    'x-auth-token',
    'x-custom-secret',
  ],
  sanitizeHeaders: (headers) => {
    const sanitized = { ...headers };

    // Partial masking for tokens
    if (sanitized['authorization']) {
      const auth = sanitized['authorization'];
      sanitized['authorization'] = typeof auth === 'string'
        ? `${auth.substring(0, 7)}...${auth.substring(auth.length - 10)}`
        : auth;
    }

    // Mask other sensitive headers completely
    ['cookie', 'x-api-key', 'x-auth-token'].forEach(key => {
      if (sanitized[key]) sanitized[key] = '*'.repeat(20);
    });

    return sanitized;
  },
}));

📈 Performance Monitoring

Combine with performance analysis:

app.use(requestLoggerFactory({
  completedRequestMessage: (details) => {
    const duration = parseFloat(details.durationMs);
    let performanceLevel = '🟢';

    if (duration > 1000) performanceLevel = '🔴';
    else if (duration > 500) performanceLevel = '🟡';
    else if (duration > 100) performanceLevel = '🟡';

    return `${performanceLevel} ${details.method} ${details.url} - ${details.statusCode} in ${details.durationMs}ms`;
  },
}));

📋 Requirements

  • Node.js: 14.0.0 or higher
  • NestJS: 8.0.0 or higher
  • Express: 4.0.0 or higher (for Express adapter)
  • Fastify: 4.0.0 or 5.0.0 (for Fastify adapter)

🔄 Version Compatibility

| NestJS Version | Package Support | |---|---| | 8.x | ✅ Full Support | | 9.x | ✅ Full Support | | 10.x | ✅ Full Support | | 11.x | ✅ Full Support |


🐛 Troubleshooting

Headers not being logged

Ensure headerFields is set in your configuration:

app.use(requestLoggerFactory({ headerFields: ['content-type', 'authorization'] }));

Custom logger not being used

Make sure your custom logger implements the NestJS LoggerService interface:

import { LoggerService } from '@nestjs/common';

export class MyLogger implements LoggerService {
  log(message: string) { /* ... */ }
  error(message: string, trace?: string) { /* ... */ }
  warn(message: string) { /* ... */ }
  debug(message: string) { /* ... */ }
  verbose(message: string) { /* ... */ }
}

Performance impact on high-traffic applications

The middleware is optimized for production use. If you experience performance issues:

  1. Use ignorePaths to exclude high-frequency endpoints (health checks, metrics)
  2. Consider disabling headerFields and logRequestBody if not needed
  3. Use an async logger that doesn't block the request

📝 API Reference

requestLoggerFactory(options?)

Creates and returns an Express/Fastify compatible middleware function.

Parameters:

  • options (optional): Partial<RequestLoggerOptions>

Returns: (req: Req, res: Res, next: Function) => void

Example:

const middleware = requestLoggerFactory({ headerFields: ['content-type', 'authorization'] });
app.use(middleware);

createRequestLoggerProviders(options?)

Creates NestJS providers for dependency injection.

Parameters:

  • options (optional): RequestLoggerModuleOptions

Returns: Provider[]

createRequestLoggerAsyncProviders(options)

Creates async NestJS providers for dynamic configuration.

Parameters:

  • options: RequestLoggerAsyncOptions with useFactory and inject

Returns: Provider[]


🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📧 Support

For issues, questions, or suggestions:

  • Open an issue on GitHub
  • Check existing documentation and examples

📄 License

This package is open-source and available under the MIT License.

Copyright (c) 2024 samofprog


🙏 Acknowledgments

Built with ❤️ for the NestJS community. Special thanks to all contributors and users who have provided feedback and improvements.