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

@twg-group/nestjs-logger

v1.0.35

Published

Enhanced logger for NestJS applications with JSON formatting, redaction and more

Downloads

100

Readme

Logger Module for NestJS

Extended logger for NestJS with additional features:

  • Colored console formatting
  • JSON logging format
  • Sensitive data redaction
  • Additional fields and context
  • Flexible logging levels

Table of Contents

Installation

npm install @twg-group/nestjs-logger

Quick Start

Global Usage

// app.module.ts
import { Module } from '@nestjs/common';
import { LoggerModule } from '@twg-group/nestjs-logger';

@Module({
  imports: [
    LoggerModule.forRoot({
      loggerOptions: {
        id: 'MyService',
        jsonFormat: false,
        prettyPrintJson: false,
        redactKeys: ['password', 'token', 'secret'],
        logLevels: ['log', 'error', 'warn', 'debug', 'verbose', 'fatal', 'info']
      }
    }),
    // other modules
  ],
})
export class AppModule {}

Builder Pattern Configuration

// Advanced configuration using method chaining
const logger = new Logger('UserService')
  .setLogLevels(['log', 'error', 'warn', 'fatal', 'info'])
  .setRedactKeys(['password', 'token', 'apiKey'])
  .addField('version', '1.0.0')
  .addField('environment', process.env.NODE_ENV)
  .setCtxParams(['service:users']);

// Configure based on environment
if (process.env.NODE_ENV === 'production') {
  // Production: Enable JSON format, disable pretty printing for performance
  logger.enableJsonFormat().disablePrettyPrint();
}

logger.info('Logger configured successfully');

Usage in Services

// user.service.ts
import { Injectable } from '@nestjs/common';
import { Logger } from '@twg-group/nestjs-logger';

@Injectable()
export class UserService {
  constructor(private readonly logger: Logger) {
    // Context is automatically set to 'UserService'
  }

  async createUser(userData: any) {
    this.logger.log('Creating user', `email:${userData.email}`);
    
    try {
      // user creation logic
      const user = await this.createUserInDatabase(userData);
      this.logger.info('User created successfully', `userId:${user.id}`);
      return user;
    } catch (error) {
      this.logger.error('Failed to create user', error);
      throw error;
    }
  }
}

Usage Examples

Basic Logging

// Simple message
logger.log('User logged in');

// Message with parameters as strings
logger.log('Processing request', 'userId:123', 'requestId:abc');

// Object logging (pass as message, not parameter)
logger.log({ user: { id: 1, name: 'John' }, action: 'login' });

Different Log Levels

logger.log('Regular message');
logger.info('Informational message');
logger.warn('Warning');
logger.error('Error');
logger.debug('Debug information');
logger.verbose('Verbose information');
logger.fatal('Critical error');

Error Handling

try {
  throw new Error('Something went wrong');
} catch (error) {
  logger.error('Operation failed', error);
}

// With custom errors
const customError = new Error('Custom error');
(customError as any).cause = new Error('Root cause');
logger.error('Database connection failed', customError);

Configuration

Logger Options

const loggerOptions = {
  id: 'MyService',           // Service identifier (defaults to process.env.SERVICE_NAME or 'Nest')
  jsonFormat: false,         // Log format: JSON or text (default: false)
  prettyPrintJson: false,    // Pretty JSON formatting (default: false)
  redactKeys: ['password', 'token', 'secret'], // Keys to redact
  logLevels: ['log', 'error', 'warn', 'debug', 'verbose', 'fatal', 'info'] // Active levels
};

Global Configuration

// main.ts or app.module.ts
LoggerModule.forRoot({
  loggerOptions: {
    id: process.env.SERVICE_NAME || 'MyApp',
    jsonFormat: process.env.NODE_ENV === 'production',
    redactKeys: ['password', 'token', 'apiKey', 'secret'],
    logLevels: ['log', 'error', 'warn', 'fatal', 'info'] // exclude debug and verbose in production
  }
})

Output Examples

Text Format (Default)

[Nest] 2025-07-26T22:20:43.510Z  INFO [ExampleService][test] Message without timestamp
[Nest] 2025-07-26T22:20:43.512Z   LOG [ExampleService] { message: 'message1', test: 123, jest: 1233 }
[Nest] 2025-07-26T22:20:43.513Z DEBUG [ExampleService] Debug message
[Nest] 2025-07-26T22:20:43.513Z  INFO [AppController][Constructor] Message with additional context +0ms
[Nest] 2025-07-26T22:20:43.514Z   LOG [AppController][Constructor][email:[email protected]] Create user request received +1ms
[Nest] 2025-07-26T22:20:43.527Z  INFO [App] Service started on: 3033 port.
[Nest] 2025-07-26T22:20:44.514Z  INFO [AppController][Constructor] Message after 1000ms +1000ms

JSON Format (Production - Compact)

{"timestamp":"2025-07-26T22:20:43.510Z","service":"MyService","level":"INFO","context":"ExampleService","data":{"message":"Message without timestamp"},"tags":["test"]}

JSON Format (Development - Pretty Printed)

{
  "timestamp": "2025-07-26T22:20:43.510Z",
  "service": "MyService",
  "level": "INFO",
  "context": "ExampleService",
  "data": {
    "message": "Message without timestamp"
  },
  "tags": ["test"]
}

Error Logging

{
  "timestamp": "2025-07-26T22:20:43.514Z",
  "service": "MyService",
  "level": "ERROR",
  "context": "UserService",
  "data": {
    "error": {
      "name": "Error",
      "message": "Database connection failed",
      "stack": [
        "Error: Database connection failed",
        "    at UserService.createUser (/src/user.service.ts:15:11)",
        "    at processTicksAndRejections (node:internal/process/task_queues:96:5)"
      ]
    }
  }
}

Timestamp Feature

The logger automatically adds timestamp differences when enabled:

// Enable timestamp tracking
logger.resetTimestamp(); // Reset timestamp counter

// First log will show +0ms
logger.info('Service started');

// Subsequent logs show time difference
setTimeout(() => {
  logger.info('Message after delay'); // Shows +1000ms or similar
}, 1000);

Usage in Different Parts of Application

In Controllers

@Controller('users')
export class UserController {
  constructor(private readonly logger: Logger) {
    // Context is automatically set to 'UserController'
  }

  @Post()
  async createUser(@Body() userData: CreateUserDto) {
    this.logger.log('Create user request received', `email:${userData.email}`);
    return this.userService.createUser(userData);
  }
}

In Guards and Interceptors

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private readonly logger: Logger) {
    // Context is automatically set to 'AuthGuard'
  }

  canActivate(context: ExecutionContext): boolean {
    this.logger.debug('Checking authentication');
    // authentication logic
    return true;
  }
}

Creating Separate Instances

// For specific usage
const customLogger = new Logger('CustomContext', {
  jsonFormat: true,
  prettyPrintJson: false,
  redactKeys: ['sensitive'],
  logLevels: ['error', 'warn']
});

customLogger.error('Custom error message');

Best Practices

  1. Use Context: Always set meaningful context for the logger
  2. Redact Sensitive Data: Configure redactKeys for security
  3. Proper Levels: Use appropriate levels for different message types
  4. Structured Data: Pass objects as message content, not as parameters
  5. Parameters as Strings: Pass additional context as string parameters (e.g., 'userId:123')
  6. Avoid Object Parameters: Don't pass objects as parameters - they will display as [object Object]
  7. Builder Pattern: Use method chaining for complex logger configuration
  8. Production Settings: Use compact JSON format in production for better performance and logging system compatibility
  9. Development Settings: Enable pretty printing in development for better readability
  10. Global Configuration: Configure logger at application level for consistency

License

MIT