import { CallHandler, ExecutionContext, HttpException, Injectable, Logger, NestInterceptor } from '@nestjs/common'; import { Observable, tap } from 'rxjs'; /** One line per request, failed ones included: 4xx as a warning, 5xx as an error. */ @Injectable() export class LoggingInterceptor implements NestInterceptor { private readonly logger = new Logger('HTTP'); intercept(context: ExecutionContext, next: CallHandler): Observable { const http = context.switchToHttp(); const request = http.getRequest(); const start = Date.now(); const line = (status: number) => { const actor = request.user?.id ?? request.device?.id ?? 'anonymous'; const venueId = request.user?.venueId ?? request.device?.venueId ?? '-'; return `${request.method} ${request.url} ${status} | actor=${actor} venue=${venueId} | ${Date.now() - start}ms`; }; return next.handle().pipe( tap({ next: () => this.logger.log(line(http.getResponse().statusCode)), error: (error: unknown) => { const status = error instanceof HttpException ? error.getStatus() : 500; if (status >= 500) this.logger.error(line(status)); else this.logger.warn(line(status)); }, }), ); } }