fix(todo): capture error responses in metrics interceptor

Use catchError instead of tap.error to properly capture HTTP exception
status codes (401, 404, etc.) in Prometheus metrics.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Till-JS 2026-01-25 13:56:25 +01:00
parent a12c7e5f32
commit 11411ff0a0

View file

@ -3,8 +3,10 @@ import {
NestInterceptor,
ExecutionContext,
CallHandler,
HttpException,
HttpStatus,
} from '@nestjs/common';
import { Observable, tap } from 'rxjs';
import { Observable, tap, catchError, throwError } from 'rxjs';
import { Request, Response } from 'express';
import { MetricsService } from './metrics.service';
@ -28,24 +30,20 @@ export class MetricsInterceptor implements NestInterceptor {
const route = this.normalizeRoute(request.path);
return next.handle().pipe(
tap({
next: () => {
this.recordMetrics(method, route, response.statusCode, startTime);
},
error: () => {
const status = response.statusCode >= 400 ? response.statusCode : 500;
this.recordMetrics(method, route, status, startTime);
},
tap(() => {
this.recordMetrics(method, route, response.statusCode, startTime);
}),
catchError((error) => {
// Extract status code from HttpException or use 500
const status =
error instanceof HttpException ? error.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR;
this.recordMetrics(method, route, status, startTime);
return throwError(() => error);
})
);
}
private recordMetrics(
method: string,
route: string,
status: number,
startTime: number
): void {
private recordMetrics(method: string, route: string, status: number, startTime: number): void {
const duration = (Date.now() - startTime) / 1000;
const statusStr = status.toString();
@ -55,19 +53,13 @@ export class MetricsInterceptor implements NestInterceptor {
status: statusStr,
});
this.metricsService.httpRequestDuration.observe(
{ method, route, status: statusStr },
duration
);
this.metricsService.httpRequestDuration.observe({ method, route, status: statusStr }, duration);
}
private normalizeRoute(path: string): string {
// Replace UUIDs and numeric IDs with placeholders
return path
.replace(
/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi,
':id'
)
.replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, ':id')
.replace(/\/\d+/g, '/:id');
}
}