简体   繁体   中英

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.

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

First of all, to use dependency injection with Exception filters you cannot register them using the useGlobalFilters() method:

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

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

//Remove this line
//app.useGlobalFilters(new HttpExceptionFilter(logger));

Next in your MainModule , add your custom exception filter as a provider (note: filters are automatically set as global no matter what module you add them to but as a best practice, add them to your top level module):

import { Module } from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';
import { LoggerModule } from './logger.module';
import { ForbiddenException } from './forbidden.exception.filter.ts';

@Module({
  imports: [
    LoggerModule //this is your logger module
  ],
  providers: [
    {
      provide: APP_FILTER, //you have to use this custom provider
      useClass: ForbiddenException //this is your custom exception filter
    }
  ]
})
export class MainModule {}

Now you can inject the logger into your custom exception filter:

import {HttpException, HttpStatus, Injectable} from '@nestjs/common';
import { Logger } from './path/to/logger';

@Injectable()
export class ForbiddenException extends HttpException {

  constructor(private logger: Logger) {}

  catch(exception: HttpException, response) {
    this.logger.log('test');
  }
}

Pseudo code but I think you get the idea.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM