feat: add logging
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
import { Injectable, NestMiddleware } from '@nestjs/common';
|
||||
import type { NextFunction, Request, Response } from 'express';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import { RequestContextService } from './request-context.service';
|
||||
import { StructuredLogger } from './structured-logger.service';
|
||||
|
||||
const uuid =
|
||||
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
||||
|
||||
@Injectable()
|
||||
export class RequestLoggingMiddleware implements NestMiddleware {
|
||||
constructor(
|
||||
private readonly requestContext: RequestContextService,
|
||||
private readonly logger: StructuredLogger,
|
||||
) {}
|
||||
|
||||
use(request: Request, response: Response, next: NextFunction): void {
|
||||
const incoming = request.header('x-request-id');
|
||||
const clientRequestId =
|
||||
incoming && uuid.test(incoming) ? incoming : undefined;
|
||||
const existingRequestId = (request as Request & { id?: unknown }).id;
|
||||
const requestId =
|
||||
typeof existingRequestId === 'string' ? existingRequestId : randomUUID();
|
||||
(request as unknown as { id: string }).id = requestId;
|
||||
const startedAt = performance.now();
|
||||
|
||||
response.setHeader('X-Request-ID', requestId);
|
||||
response.on('finish', () => {
|
||||
const routeRequest: unknown = request;
|
||||
const routePath = (routeRequest as { route?: { path?: unknown } }).route
|
||||
?.path;
|
||||
const route =
|
||||
typeof routePath === 'string'
|
||||
? `${request.baseUrl}${routePath}`
|
||||
: '<unmatched>';
|
||||
const context = {
|
||||
method: request.method,
|
||||
route,
|
||||
status: response.statusCode,
|
||||
durationMs: Math.round(performance.now() - startedAt),
|
||||
...(response.locals.publicErrorCode
|
||||
? { code: response.locals.publicErrorCode as string }
|
||||
: {}),
|
||||
...(response.locals.errorStack
|
||||
? { stack: response.locals.errorStack as string }
|
||||
: {}),
|
||||
};
|
||||
const level =
|
||||
response.statusCode >= 500
|
||||
? 'error'
|
||||
: response.statusCode === 429 ||
|
||||
response.statusCode === 401 ||
|
||||
response.statusCode === 403
|
||||
? 'warn'
|
||||
: 'info';
|
||||
this.logger.event(level, 'http.request.completed', context);
|
||||
});
|
||||
|
||||
this.requestContext.run(
|
||||
{
|
||||
requestId,
|
||||
...(clientRequestId ? { clientRequestId } : {}),
|
||||
},
|
||||
next,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user