import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus, } from '@nestjs/common'; import { Request, Response } from 'express'; import { LogsService } from '../../modules/logs/logs.service'; import { getRequestCost } from '../utils/request-context.util'; @Catch() export class HttpExceptionFilter implements ExceptionFilter { constructor(private readonly logsService: LogsService) {} catch(exception: unknown, host: ArgumentsHost) { const ctx = host.switchToHttp(); const request = ctx.getRequest< Request & { requestId?: string; adminId?: number; user?: { id: number } } >(); const response = ctx.getResponse(); const statusCode = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR; const message = this.getMessage(exception, statusCode); const requestId = request.requestId ?? ''; const costMs = getRequestCost(request); this.logsService.recordRequest({ requestId, method: request.method, path: request.originalUrl ?? request.url, query: request.query, body: request.body, statusCode, responseCode: statusCode, message, costMs, userId: request.user?.id, adminId: request.adminId, ip: request.ip, userAgent: request.get('user-agent'), errorStack: exception instanceof Error ? exception.stack : undefined, }); response.status(statusCode).json({ code: statusCode, data: {}, message, timestamp: Date.now(), requestId, cost: `${costMs}ms`, }); } private getMessage(exception: unknown, statusCode: number): string { if (exception instanceof HttpException) { const response = exception.getResponse(); if (typeof response === 'string') { return response; } if ( response && typeof response === 'object' && 'message' in response ) { const message = (response as { message: string | string[] }).message; return Array.isArray(message) ? message.join('; ') : message; } } if (exception instanceof Error && statusCode === HttpStatus.INTERNAL_SERVER_ERROR) { return exception.message || 'Internal server error'; } return 'Internal server error'; } }