Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NestJS How to add custom Logger to custom ExceptionFilter

I am using NestJS 5.4.0 I have custom LoggerService, it's working perfectly. But, how can I add this LoggerService to ExceptionFilter.

// logger.service.ts
import {Injectable, LoggerService} from '@nestjs/common';
@Injectable()
export class Logger implements LoggerService {
    log(message: string) {
        console.log(message);
    }
    error(message: string, trace: string) {
        console.error(message);
    }
    warn(message: string) {
        console.warn(message);
    }
}

//logger.module.ts
import { Module } from '@nestjs/common';
import {Logger} from '../services/logger.service';
@Module({
    providers: [Logger],
    exports: [Logger],
})
export class LoggerModule {}


// user.module.ts
import { Module } from '@nestjs/common';
import {UserService} from '../services/user.service';
import {LoggerModule} from './logger.module';

@Module({
    imports: [LoggerModule],
    providers: [UserService],
    exports: [UserService],
})
export class UserModule {}

It's working perfectly.

import {Logger} from './logger.service';
export class UserService {
    constructor(
        private logger: Logger
    ) {}
    private test = () => {
        this.logger.log("test"); // log success "test" to console
    }
}

But how can I add my custom Logger to ExceptionFilter

// forbidden.exception.filter.ts
import {HttpException, HttpStatus, Injectable} from '@nestjs/common';

@Injectable()
export class ForbiddenException extends HttpException {
    constructor(message?: string) {
        super(message || 'Forbidden', HttpStatus.FORBIDDEN);
        // I want to add my custom logger here!
    }
}

Thank for reading.

like image 252
Trọng Nguyễn Công Avatar asked Nov 20 '18 14:11

Trọng Nguyễn Công


1 Answers

First of all your class ForbiddenException extends HttpException is not what it calls ExceptionFilter. ExceptionFilter is

exceptions layer which is responsible for processing all unhandled exceptions across an application

docs

You provided exmaple when you are trying to inject it to your custom HttpException. But thats wrong. Your exception don't have to be responsible for logging. Thats what ExceptionFilter should be responsible for.

Anyway, for now (17 oct 2019) there is no example in official docs how to inject providers to ExceptionFilter.

You can pass it to constructor on init, but you should to get Logger instance before with app.get<T>(...) method.

For example I've changed code from exception-filters docs:

// HttpExceptionFilter.ts

import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { Request, Response } from 'express';
import {MyLogger} from '../MyLogger'

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  constructor(private readonly logger: MyLogger) {}

  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();
    const status = exception.getStatus();

    if (status >= 500) {
      this.logger.error({ request, response });
    }

    response
      .status(status)
      .json({
        statusCode: status,
        timestamp: new Date().toISOString(),
        path: request.url,
      });
  }
}

and bootstrap.ts code:

// bootstrap.ts

const app = await NestFactory.create(MainModule, {
  logger: false,
});

const logger = app.get<MyLogger>(MyLogger);
app.useLogger(logger);
app.useGlobalFilters(new HttpExceptionFilter(logger));

This technique can be used for all this INestApplication methods:

  • app.useGlobalFilters
  • app.useGlobalGuards
  • app.useGlobalInterceptors
  • app.useGlobalPipes
  • app.useLogger
  • app.useWebSocketAdapter
like image 193
iamolegga Avatar answered Oct 13 '22 23:10

iamolegga