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 🙏

© 2026 – Pkg Stats / Ryan Hefner

nestjs-log-decorator

v1.5.0

Published

Decorator that removes try catch boilerplate logging from NestJS service methods

Readme

Build Status npm version Bundle Size NPM Downloads License: AGPL-3.0

TypeScript decorators that eliminate logging boilerplate from NestJS applications.

Quick StartHow It WorksUsageOptionsAPI ReferenceAdvanced Example

Description

@Log() decorator replaces the try-catch logging pattern in NestJS service methods by automatically logging method success and errors, with optional invocation and result logging.

Key Features

  • By default uses structured output
  • Prettifies Axios errors
  • Zero configuration
  • Minimal dependencies
  • Uses default @nestjs/common Logger instance

Installation

npm install nestjs-log-decorator @nestjs/common

Quick Start

Simply apply @Log() to your class or method:

import { Log } from 'nestjs-log-decorator';

class UserService {
  @Log()
  createUser(name: string, email: string) {
    return { id: 1, name, email };
  }
}

Once a service method is called, it will log the method invocation with all arguments.

const result = service.createUser('John', '[email protected]');
// console output:
// [UserService] { method: 'createUser', state: 'success', args: { name: 'John', email: '[email protected]' } }

Error Logging

If a method throws an error, by default the decorator logs and throws it, preserving the original stack trace.

@Log()
createUser(name: string) {
  throw new Error('Validation failed');
}

Example call with error:

const result = service.createUser('John');
// console output:
// [UserService] { method: 'createUser', state: 'error', args: { name: 'John' }, error: Error: Validation failed }

Invocation Logging

If you want to log the method invocation, you can use the onInvoke option.

@Log({ onInvoke: true })
async createUser(name: string) {
  return await Promise.resolve({ name });
}

Example call with invocation logging:

const resultPromise = service.createUser('John');
// [UserService] { method: 'createUser', state: 'invoked', args: { name: 'John' } }
const result = await resultPromise;
// [UserService] { method: 'createUser', state: 'success', args: { name: 'John' } }

Result Logging

If you want to include method results in success logs, use the result option.

class UserService {
  // Logs result as-is
  @Log({ result: true })
  findUser(id: number) {
    return { id, name: 'John', email: '[email protected]' };
  }

  // Logs formatted result
  @Log({
    result: (res: { id: number; name: string; email: string }) => ({ id: res.id, name: res.name }),
  })
  findPublicUser(id: number) {
    return { id, name: 'John', email: '[email protected]' };
  }
}

Example success output:

// [UserService] { method: 'findUser', state: 'success', args: { id: 1 }, result: { id: 1, name: 'John', email: '[email protected]' } }
// [UserService] { method: 'findPublicUser', state: 'success', args: { id: 1 }, result: { id: 1, name: 'John' } }

Complete Example

After installation, no additional configuration is needed. If the class has logger properly, the @Log() decorator will use it log method. If the logger is missing, the decorator will inject @nestjs/common Logger instance using the class name as the context.

import { Log } from 'nestjs-log-decorator';

class PaymentService {

  @Log()
  async processPayment(amount: number, currency: string) {
    // Automatically logged on success or error
    return await this.gateway.processPayment(amount, currency);
  }

  async refund(transactionId: string) {
    // Not logged without @Log() decorator
    return await this.gateway.refund(transactionId);
  }
}

Explicit Logger (Optional)

If you need a custom logger (e.g., for testing or a different context), you can still define your own:

import { Logger } from '@nestjs/common';
import { Log } from 'nestjs-log-decorator';

@Log()
class PaymentService {
  // Explicit logger takes precedence over auto-injected one
  readonly logger = new Logger('CustomPaymentContext');

  async processPayment(amount: number, currency: string) {
    // Logs using the explicit logger with 'CustomPaymentContext' context
    return await this.gateway.processPayment(amount, currency);
  }
}

How It Works

The @Log() decorator wraps your methods with automatic try-catch logging. It extracts parameter names, captures arguments, and logs structured output on success or error.

┌─────────────────────────────────────────────────────────────────────────────┐
│                            @Log() Decorator Flow                            │
└─────────────────────────────────────────────────────────────────────────────┘

  Method Call
       │
       ▼
┌──────────────────┐
│ Extract Args     │  ──▶  { id: 1, name: 'John' }
│ (auto or custom) │
└────────┬─────────┘
         │
         ▼
┌──────────────────┐       ┌─────────────────────────────────────┐
│ onInvoke: true?  │──YES─▶│ logger.log({ state: 'invoked' })    │
└────────┬─────────┘       └─────────────────────────────────────┘
         │ NO
         ▼
┌──────────────────────┐
│ Execute Original     │
│ Method (sync/async)  │
└────────┬─────────────┘
         │
    ┌────┴────┐
    ▼         ▼
 SUCCESS    ERROR
    │         │
    ▼         ▼
┌────────┐ ┌──────────────────────────────────────────────────────┐
│log()   │ │ logger.error({ state: 'error', error: prettify(e) })│
│success │ │ (Axios errors auto-prettified)                      │
└────────┘ └──────────────────────────────────────────────────────┘
    │         │
    ▼         ▼
 Return    Re-throw
 Result    Error

Usage

Method-Level Decorator

Apply @Log() to specific methods for granular control:

import { Log } from 'nestjs-log-decorator';

class DataService {
  @Log()
  async fetchData(id: number) {
    // This method is logged
    return await this.repository.findById(id);
  }

  helperMethod() {
    // This method is NOT logged
    return 'helper';
  }
}

Class-Level Decorator

If you want to log all methods in a class, use the @Log() decorator on its definition:

import { Log } from 'nestjs-log-decorator';

@Log()
@Injectable()
class PaymentService {
  processPayment(amount: number, currency: string) {
    // Automatically logged on success or error
    return { status: 'completed', amount, currency };
  }

  async refund(transactionId: string) {
    // Async methods are also logged
    return await this.gateway.refund(transactionId);
  }
}

Optional: Excluding Methods with @NoLog()

When using class-level @Log(), you can exclude specific methods with @NoLog():

import { Log, NoLog } from 'nestjs-log-decorator';

@Log()
class UserService {
  createUser(name: string) {
    // Logged
    return { name };
  }

  @NoLog()
  internalHelper() {
    // NOT logged
    return 'helper';
  }
}

Options

onInvoke

Log method invocation (before execution), not just completion:

@Log({ onInvoke: true })
async fetchExternalData(url: string) {
  const response = await fetch(url);
  return response.json();
}
// Logs: { method: 'fetchExternalData', state: 'invoked', args: { url: '...' } }
// Logs: { method: 'fetchExternalData', state: 'success', args: { url: '...' } }

Class-level with onInvoke:

@Log({ onInvoke: true })
class ApiService {
  // All methods will log invocation + completion
}

args — Custom Argument Formatting

Control what arguments are logged. Useful for:

  • Excluding large objects from logs
  • Hiding sensitive data (passwords, tokens)
  • Logging only specific arguments
interface LargePayload {
  data: Buffer;
  metadata: object;
}

class SyncService {
  // Only log the ID, exclude the large payload
  @Log({ args: (id: number, _payload: LargePayload) => ({ id }) })
  async syncData(id: number, payload: LargePayload) {
    return await this.process(id, payload);
  }

  // Log multiple specific args
  @Log({ args: (userId: number, txId: string, _data: object) => ({ userId, txId }) })
  async processTransaction(userId: number, txId: string, data: object) {
    return await this.execute(userId, txId, data);
  }

  // Return a custom string
  @Log({ args: (id: number, name: string) => `${id}:${name}` })
  lookupUser(id: number, name: string) {
    return this.users.find(id, name);
  }
}

Output:

[SyncService] { method: 'syncData', state: 'success', args: { id: 123 } }
[SyncService] { method: 'processTransaction', state: 'success', args: { userId: 1, txId: 'tx_abc' } }
[SyncService] { method: 'lookupUser', state: 'success', args: '1:John' }

result — Success Result Logging

Control how return values are included in success logs:

  • result: true logs the raw return value
  • result: (value) => ... logs a formatted value
class PaymentService {
  // Log full return value
  @Log({ result: true })
  createPayment(id: number) {
    return { id, status: 'success', cardToken: 'tok_123' };
  }

  // Log only safe result fields
  @Log({
    result: (res: { id: number; status: string; cardToken: string }) => ({ id: res.id, status: res.status }),
  })
  createPaymentSafe(id: number) {
    return { id, status: 'success', cardToken: 'tok_123' };
  }
}

Log Format

All logs are structured JSON objects:

Success Log

{
  method: 'methodName',
  state: 'success',
  args: { param1: value1, param2: value2 },
  // Present only when `result` option is configured
  result: { any: 'value' }
}

Invocation Log (when onInvoke: true)

{
  method: 'methodName',
  state: 'invoked',
  args: { param1: value1, param2: value2 }
}

Error Log

{
  method: 'methodName',
  state: 'error',
  args: { param1: value1, param2: value2 },
  error: Error | PrettifiedAxiosError
}

Methods with No Arguments

{
  method: 'methodName',
  state: 'success',
  args: undefined
}

Error Handling

Standard Errors

Regular JavaScript errors are logged as-is and re-thrown:

@Log()
processPayment(amount: number) {
  if (amount <= 0) {
    throw new Error('Invalid amount');
  }
  return { status: 'success' };
}

Log Output:

{
  method: 'processPayment',
  state: 'error',
  args: { amount: -10 },
  error: {
    message: 'Invalid amount',
    stack: '...',
    ...
  }
}

Axios Errors (Auto-Prettified)

Axios errors are automatically formatted with structured request/response info:

@Log()
async fetchData(url: string) {
  const response = await this.httpClient.get(url);
  return response.data;
}

Prettified Axios Error Output:

{
  method: 'fetchData',
  state: 'error',
  args: { url: 'http://api.example.com/data' },
  error: {
    name: 'AxiosError',
    error: 'Request failed with status code 404',
    code: 'ERR_BAD_REQUEST',
    config: {
      method: 'get',
      url: 'http://api.example.com/data',
      headers: { ... },
    },
    response: {
      status: 404,
      statusText: 'Not Found',
      data: { message: 'Resource not found' },
      headers: { ... }
    }
  }
}

API Reference

Log(options?)

Decorator that can be applied to classes or methods. When applied to a class, by default all methods are logged.

| Option | Type | Default | Description | |--------|------|---------|-------------| | onInvoke | boolean | false | Log method invocation before execution | | args | (...args) => any | undefined | Custom function to format logged arguments | | result | true \| (result) => any | undefined | Include and optionally format successful method result |

NoLog()

Method decorator that excludes a method from class-level @Log() logging.

Exported Types

import { Log, NoLog, LogOptions, Loggable, isLoggable } from 'nestjs-log-decorator';

| Export | Type | Description | |--------|------|-------------| | Log | Decorator | Main logging decorator | | NoLog | Decorator | Exclude method from logging | | LogOptions | Interface | Options for @Log() decorator | | Loggable | Interface | Interface for classes with a logger property (optional) | | isLoggable | Function | Type guard to check if instance has logger |

Advanced Example

import { Injectable, Logger } from '@nestjs/common';
import { Log, NoLog } from 'nestjs-log-decorator';

@Log()
@Injectable()
export class OrderService {
  // Optional: explicit logger takes precedence over auto-injected one
  readonly logger = new Logger(OrderService.name);

  constructor(
    readonly orderRepo: OrderRepository,
    readonly paymentGateway: PaymentGateway,
  ) {}

  // Logged with all args
  async createOrder(userId: number, items: OrderItem[]) {
    const order = await this.orderRepo.create({ userId, items });
    return order;
  }

  // Logged with invocation + custom args (exclude sensitive card data)
  @Log({
    onInvoke: true,
    args: (orderId: number, _cardDetails: CardDetails) => ({ orderId })
  })
  async processPayment(orderId: number, cardDetails: CardDetails) {
    const result = await this.paymentGateway.charge(orderId, cardDetails);
    return result;
  }

  // Not logged - internal helper
  @NoLog()
  calculateTotal(items: OrderItem[]): number {
    return items.reduce((sum, item) => sum + item.price * item.quantity, 0);
  }

  // Logged - errors will include prettified Axios details if from HTTP call
  async syncWithExternalSystem(orderId: number) {
    const response = await this.externalApi.post('/orders', { orderId });
    return response.data;
  }
}