import { Request, Response, NextFunction } from 'express'; import { randomUUID } from 'crypto'; import { getLogger } from '../utils/logging.js'; /** * Generate a request ID * @returns A unique request ID */ export function generateRequestId(): string { return randomUUID(); } /** * Extended Express Request with request ID */ export interface RequestWithId extends Request { id: string; startTime: number; } /** * Add request ID and timing to request object */ export function requestTracker(req: Request, res: Response, next: NextFunction): void { const requestId = req.headers['x-request-id'] || generateRequestId(); const startTime = Date.now(); // Add properties to request object (req as RequestWithId).id = String(requestId); (req as RequestWithId).startTime = startTime; // Add response header with request ID res.setHeader('x-request-id', requestId); // Create child logger with request ID const logger = getLogger().child({ requestId: String(requestId) }); // Log request start logger.info(`${req.method} ${req.path}`, { method: req.method, path: req.path, query: req.query, headers: { 'user-agent': req.headers['user-agent'], 'content-type': req.headers['content-type'], 'accept': req.headers['accept'] }, ip: req.ip }); // Log response when finished res.on('finish', () => { const responseTime = Date.now() - startTime; logger.info(`${req.method} ${req.path} ${res.statusCode} ${responseTime}ms`, { method: req.method, path: req.path, statusCode: res.statusCode, responseTime, contentLength: res.getHeader('content-length') }); }); next(); }