import type { Request, Response, NextFunction } from "express"; import { createRequestId, logInfo } from "../utils/logger.js"; export function accessLogMiddleware( req: Request, res: Response, next: NextFunction ): void { const startedAt = Date.now(); const requestId = resolveRequestId(req); req.requestId = requestId; res.setHeader("X-Request-Id", requestId); res.on("finish", () => { if (shouldSkipAccessLog(req.originalUrl, res.statusCode)) { return; } logInfo("[http/access]", "request completed", { requestId, method: req.method, originalUrl: req.originalUrl, statusCode: res.statusCode, durationMs: Date.now() - startedAt, ip: req.ip, forwardedFor: String(req.headers["x-forwarded-for"] || ""), userAgent: String(req.headers["user-agent"] || ""), referer: String(req.headers.referer || ""), contentLength: Number(res.getHeader("content-length") || 0), actorUserId: req.adminSession?.userId || "", actorUsername: req.adminSession?.username || "", actorRole: req.adminSession?.role || "", }); }); next(); } function resolveRequestId(req: Request): string { const fromHeader = String(req.headers["x-request-id"] || "").trim(); return fromHeader || createRequestId("req"); } function shouldSkipAccessLog(originalUrl: string, statusCode: number): boolean { const pathname = String(originalUrl || "").split("?")[0] || ""; return ( ["/health", "/health/live", "/health/ready"].includes(pathname) && Number(statusCode) < 400 ); }