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

@neoma/logging

v0.4.0

Published

Great logging for NestJs

Downloads

416

Readme

@neoma/logging

High-performance, production-ready logging for NestJS applications powered by Pino. Provides excellent developer experience with request-scoped loggers, field redaction, and seamless NestJS integration.

Why @neoma/logging?

  • 🚀 Drop-in replacement for NestJS built-in logger
  • 🎯 Request-scoped logging with automatic request context
  • 🔧 Global context configuration for application metadata
  • 🔒 Field redaction for sensitive data protection
  • High performance with Pino under the hood
  • 🛠️ Excellent DX with native NestJS patterns
  • 📝 Comprehensive testing with memory buffer approach

Installation

npm install @neoma/logging pino

Basic Usage

Quick Start

Replace your existing NestJS logger with ApplicationLoggerService:

import { LoggingModule, ApplicationLoggerService } from '@neoma/logging'
import { Module } from '@nestjs/common'

@Module({
  imports: [LoggingModule.forRoot()],
  providers: [ApplicationLoggerService]
})
export class AppModule {}

Using the Logger

import { Injectable } from '@nestjs/common'
import { ApplicationLoggerService } from '@neoma/logging'

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

  createUser(userData: any) {
    this.logger.log('Creating new user', { userId: userData.id })
    
    try {
      // ... user creation logic
      this.logger.log('User created successfully', { userId: userData.id })
    } catch (error) {
      this.logger.error('Failed to create user', { 
        userId: userData.id, 
        error: error.message 
      })
      throw error
    }
  }
}

Configuration

Log Levels

Configure the minimum log level to capture:

LoggingModule.forRoot({
  logLevel: 'warn' // Only log warnings, errors, and fatal messages
})

Available levels (from most to least verbose):

  • verbose (maps to Pino trace)
  • debug - Enables automatic request/response logging
  • log (maps to Pino info) - default
  • warn
  • error
  • fatal

Field Redaction

Protect sensitive data by configuring field redaction:

LoggingModule.forRoot({
  logRedact: [
    'password',           // Redact any top-level password field
    'user.ssn',          // Redact nested fields with dot notation
    '*.apiKey',          // Redact apiKey from any object
    'tokens.*.secret',   // Redact secret from any object under tokens
    'medical.*'          // Redact all fields under medical object
  ]
})

Before redaction:

logger.log('User login', {
  username: 'john_doe',
  password: 'secret123',
  profile: {
    email: '[email protected]',
    apiKey: 'sk-1234567890'
  }
})

After redaction:

{
  "level": 30,
  "msg": "User login",
  "username": "john_doe",
  "password": "[REDACTED]",
  "profile": {
    "email": "[email protected]", 
    "apiKey": "[REDACTED]"
  }
}

Log Context

Add global context that gets included with every log entry:

LoggingModule.forRoot({
  logContext: {
    service: 'user-api',
    version: '1.2.3',
    environment: 'production'
  }
})

Result in logs:

{
  "level": 30,
  "msg": "User created successfully",
  "service": "user-api",
  "version": "1.2.3", 
  "environment": "production",
  "userId": "123"
}

Automatic Request Logging

When logLevel: 'debug', the module automatically logs all incoming requests and responses:

LoggingModule.forRoot({
  logLevel: 'debug' // Enables automatic request/response logging
})

Automatic logs include:

  • Request start: Method, URL, controller, handler
  • Request completion: Response status, duration
  • Request errors: Error details and stack traces (when logErrors: true)

Example output:

{"level":20,"msg":"Processing an incoming request and dispatching it to a route handler.","controller":{"name":"UserController","path":"users"},"handler":{"name":"createUser","path":"/"},"req":{"method":"POST","url":"/users"}}
{"level":20,"msg":"Processed an incoming request that was successfully handled by a route handler.","controller":{"name":"UserController","path":"users"},"handler":{"name":"createUser","path":"/"},"res":{"statusCode":201},"duration":"45ms"}

Error Logging

Control whether intercepted errors are automatically logged:

LoggingModule.forRoot({
  logLevel: 'debug',  // Enable request logging
  logErrors: true     // Also log errors caught by interceptor
})

Complete Configuration

import { LoggingModule } from '@neoma/logging'

@Module({
  imports: [
    LoggingModule.forRoot({
      logLevel: 'debug',
      logContext: {
        service: 'user-api',
        version: '1.0.0',
        environment: process.env.NODE_ENV
      },
      logRedact: [
        'password',
        '*.secret',
        'user.personalInfo.*',
        'payment.cardNumber'
      ],
      logRequestTraceIdHeader: 'x-correlation-id',
      logErrors: true
    })
  ]
})
export class AppModule {}

API Reference

ApplicationLoggerService

Application-scoped logger for general application logging. Implements the NestJS LoggerService interface:

class ApplicationLoggerService {
  // Standard NestJS LoggerService methods
  log(message: any, ...optionalParams: any[]): void
  error(message: any, ...optionalParams: any[]): void  
  warn(message: any, ...optionalParams: any[]): void
  debug?(message: any, ...optionalParams: any[]): void
  verbose?(message: any, ...optionalParams: any[]): void
  fatal?(message: any, ...optionalParams: any[]): void
}

Usage:

@Injectable()
export class UserService {
  constructor(private logger: ApplicationLoggerService) {}
  
  processUsers() {
    this.logger.log('Processing batch of users')
    // Logs: { msg: 'Processing batch of users', service: 'user-api', version: '1.0.0' }
  }
}

RequestLoggerService

Request-scoped logger that automatically includes HTTP request context. Extends ApplicationLoggerService with additional request details:

@Injectable()
export class UserController {
  constructor(private logger: RequestLoggerService) {}
  
  @Post()
  createUser(@Body() userData: any) {
    this.logger.log('Creating user', { userId: userData.id })
    // Logs: { 
    //   msg: 'Creating user', 
    //   userId: userData.id,
    //   service: 'user-api', 
    //   version: '1.0.0',
    //   req: { method: 'POST', url: '/users', headers: {...} }
    // }
  }
}

Key features:

  • Request-scoped: New instance per HTTP request
  • Automatic context: Includes request method, URL, headers automatically
  • Request tracing: Automatic request trace ID generation with ULID
  • Header extraction: Extract correlation IDs from request headers
  • Context merging: Combines logContext configuration with request details
  • Same interface: Uses identical logging methods as ApplicationLoggerService
  • Middleware integration: Automatically available as req.logger in routes/middleware

Request Tracing

Every request automatically gets a unique trace ID included in all log entries. This enables request correlation across distributed systems:

@Controller('users')
export class UserController {
  constructor(private logger: RequestLoggerService) {}
  
  @Post()
  createUser(@Body() userData: any) {
    this.logger.log('Processing user creation')
    this.logger.log('Validating user data') 
    this.logger.log('User created successfully')
    
    // All logs will have the same requestTraceId:
    // { requestTraceId: '01HKQJQM7R8N4X3Z2T1V5B6Y9C', msg: 'Processing user creation' }
    // { requestTraceId: '01HKQJQM7R8N4X3Z2T1V5B6Y9C', msg: 'Validating user data' }
    // { requestTraceId: '01HKQJQM7R8N4X3Z2T1V5B6Y9C', msg: 'User created successfully' }
  }
}

Custom Correlation Headers

Extract trace IDs from incoming request headers (useful for microservice communication):

LoggingModule.forRoot({
  logRequestTraceIdHeader: 'x-correlation-id', // Case-insensitive header lookup
  logContext: {
    service: 'user-api'
  }
})

With header present:

curl -H "x-correlation-id: abc123" POST /users
{
  "level": 30,
  "msg": "Processing user creation",
  "requestTraceId": "abc123",
  "service": "user-api"
}

With header missing:

curl POST /users  
{
  "level": 40,
  "msg": "Request Trace Header 'x-correlation-id' not found, auto-generating trace ID: 01HKQJQM7R8N4X3Z2T1V5B6Y9C"
}
{
  "level": 30,
  "msg": "Processing user creation", 
  "requestTraceId": "01HKQJQM7R8N4X3Z2T1V5B6Y9C",
  "service": "user-api"
}

ULID Benefits:

  • Sortable: Lexicographically sortable by generation time
  • Compact: 26 characters vs 36 for UUID
  • Random: 80 bits of randomness for uniqueness
  • Readable: Crockford Base32 encoding (no confusing characters)

Middleware Integration

The module automatically attaches RequestLoggerService to all incoming requests as req.logger, making it available in middleware, guards, and route handlers:

import { Request, Response, NextFunction } from 'express'

// In middleware
export function customMiddleware(req: Request, res: Response, next: NextFunction) {
  req.logger.log('Custom middleware executed', { path: req.path })
  next()
}

// In route handlers (alternative to injection)
@Controller('users')
export class UserController {
  @Get(':id')
  getUser(@Req() req: Request, @Param('id') id: string) {
    req.logger.log('Fetching user', { userId: id })
    // This logger includes request context automatically
  }
}

### Usage Patterns

**Simple message:**
```typescript
logger.log('User logged in')

Message with context object:

logger.log('User logged in', { 
  userId: '123', 
  email: '[email protected]' 
})

Message with printf-style interpolation:

logger.log('Processing payment for user %s: %d %s', userId, amount, currency)
// Results in: { msg: 'Processing payment for user john: 100 USD' }

LoggingConfiguration

interface LoggingConfiguration {
  /**
   * Minimum log level to capture. Setting to 'debug' enables automatic request logging.
   * @default 'log'
   */
  logLevel?: 'verbose' | 'debug' | 'log' | 'warn' | 'error' | 'fatal'
  
  /**
   * Custom destination for log output (mainly for testing)
   * @default process.stdout
   */
  logDestination?: any
  
  /**
   * Fields to redact from logs for privacy/security
   * @default []
   */
  logRedact?: string[]
  
  /**
   * Global context to include with every log entry
   * @default {}
   */
  logContext?: any
  
  /**
   * Optional header name to extract trace ID from incoming requests
   * Performs case-insensitive lookup and auto-generates ULID if missing
   * @default null
   */
  logRequestTraceIdHeader?: string
  
  /**
   * Whether to log errors caught by the RequestLoggerInterceptor
   * @default false
   */
  logErrors?: boolean
}

Advanced Usage

Testing Your Logs

Use ArrayStream for testing log output:

import { Test } from '@nestjs/testing'
import { LoggingModule, ApplicationLoggerService } from '@neoma/logging'
import { ArrayStream } from '@neoma/logging/fixtures'

describe('MyService', () => {
  let logger: ApplicationLoggerService
  let logs: any[]

  beforeEach(async () => {
    logs = []
    const module = await Test.createTestingModule({
      imports: [
        LoggingModule.forRoot({
          logDestination: new ArrayStream(logs)
        })
      ]
    }).compile()
    
    logger = module.get(ApplicationLoggerService)
  })

  it('should log user creation', () => {
    logger.log('User created', { userId: '123' })
    
    expect(logs).toContainEqual(
      expect.objectContaining({
        level: 30, // INFO level
        msg: 'User created',
        userId: '123'
      })
    )
  })
})

Performance

@neoma/logging is built on Pino, one of the fastest Node.js loggers:

  • Low overhead: Minimal performance impact on your application
  • Asynchronous: Non-blocking log operations
  • Efficient: Optimized JSON serialization
  • Memory efficient: Smart object redaction without deep cloning

Comparison

| Feature | @neoma/logging | NestJS Built-in | nestjs-pino | |---------|---------------|----------------|-------------| | Performance | ⚡ High | 🐌 Low | ⚡ High | | NestJS Integration | 🎯 Native | ✅ Built-in | 🔧 Manual | | Request Scoping | ✅ Yes | ❌ No | ✅ Yes (AsyncLocalStorage) | | Global Context | ✅ Built-in | ❌ No | 🔧 Manual | | Field Redaction | ✅ Built-in | ❌ No | 🔧 Manual | | Testing DX | ✅ Excellent | ❌ Poor | 🔧 Manual | | TypeScript Support | ✅ Full | ✅ Full | ✅ Full |

Features

  • ApplicationLoggerService - Application-scoped logging with global context
  • RequestLoggerService - Request-scoped logging with automatic request context
  • Automatic request logging - Log all requests/responses when logLevel: 'debug'
  • Request tracing - Automatic ULID generation for request correlation
  • Header extraction - Extract trace IDs from request headers with fallback
  • Error interceptor - Configurable automatic error logging
  • Middleware integration - Logger available as req.logger on all requests
  • Field redaction - Built-in sensitive data protection with Pino paths
  • Global context configuration - Add application metadata to all logs
  • Memory buffer testing - ArrayStream utility for comprehensive test coverage
  • Printf-style and object context - Flexible logging patterns

Coming Soon

  • 🏷️ Default log fields - Automatic environment, version, and deployment metadata
  • 📊 Structured logging helpers - Common log patterns and utilities
  • 🔄 Log rotation - Built-in log file rotation
  • 📈 Metrics integration - Automatic logging metrics collection

Requirements

  • Node.js >= 14
  • NestJS >= 8
  • TypeScript >= 4.5

License

MIT License - see LICENSE for details.

Links