|
1 | | -import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common'; |
2 | | -import { Request, Response } from 'express'; |
3 | | -import { logger } from '../../logger/logger'; |
| 1 | +import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus } from '@nestjs/common'; |
| 2 | +import { HttpAdapterHost } from '@nestjs/core'; |
| 3 | +import { JsonWebTokenError } from 'jsonwebtoken'; |
| 4 | +import { LoggerService } from '../logger/logger.service'; |
4 | 5 |
|
5 | | -@Catch(HttpException) |
6 | | -export class HttpExceptionFilter implements ExceptionFilter { |
7 | | - catch(exception: HttpException, host: ArgumentsHost) { |
| 6 | +@Catch() |
| 7 | +export class ExceptionsLoggerFilter implements ExceptionFilter { |
| 8 | + constructor( |
| 9 | + private readonly httpAdapterHost: HttpAdapterHost, |
| 10 | + private readonly logger: LoggerService |
| 11 | + ) {} |
| 12 | + |
| 13 | + catch(exception: unknown, host: ArgumentsHost): void { |
| 14 | + const { httpAdapter } = this.httpAdapterHost; |
8 | 15 | const ctx = host.switchToHttp(); |
9 | | - const response = ctx.getResponse<Response>(); |
10 | | - const request = ctx.getRequest<Request>(); |
11 | | - const status = exception.getStatus(); |
| 16 | + let httpStatus = HttpStatus.INTERNAL_SERVER_ERROR, |
| 17 | + errorMessage = 'Internal Server Error', |
| 18 | + error = 'Server Error'; |
12 | 19 |
|
13 | | - // Log with HTTP status code for observability |
14 | | - try { |
15 | | - const method = request.method; |
16 | | - const url = (request as any).originalUrl || request.url || request.path; |
17 | | - logger.error(`HTTP ${status} ${method} ${url}`, { |
18 | | - statusCode: status, |
19 | | - method, |
20 | | - path: request.path, |
21 | | - message: exception.message, |
22 | | - response: exception.getResponse?.(), |
| 20 | + if (exception instanceof HttpException) { |
| 21 | + httpStatus = exception.getStatus(); |
| 22 | + const exceptionResp: any = exception.getResponse(); |
| 23 | + errorMessage = exceptionResp.message; |
| 24 | + error = exception.message; |
| 25 | + } else if (!(exception instanceof JsonWebTokenError)) { |
| 26 | + this.logger.error('Failure in ExceptionsLoggerFilter', { |
| 27 | + errorMessage: (exception as Error).message, |
| 28 | + errorStack: (exception as Error).stack, |
23 | 29 | }); |
24 | | - } catch (_) { |
25 | | - // no-op: never block response on logging failures |
26 | 30 | } |
27 | 31 |
|
28 | | - const payload = exception.getResponse?.(); |
29 | | - response.status(status).json({ |
30 | | - success: false, |
31 | | - error: { |
32 | | - statusCode: status, |
33 | | - message: (payload as any)?.message || exception.message, |
34 | | - details: payload, |
35 | | - path: request.path, |
36 | | - timestamp: new Date().toISOString(), |
37 | | - }, |
38 | | - }); |
| 32 | + const responseBody = { |
| 33 | + error, |
| 34 | + statusCode: httpStatus, |
| 35 | + message: errorMessage, |
| 36 | + timestamp: new Date().toISOString(), |
| 37 | + path: httpAdapter.getRequestUrl(ctx.getRequest()), |
| 38 | + }; |
| 39 | + |
| 40 | + httpAdapter.reply(ctx.getResponse(), responseBody, httpStatus); |
39 | 41 | } |
40 | 42 | } |
0 commit comments