import { NextFunction, Request, Response } from "express" import { Client } from "@elastic/elasticsearch" import permission from "../interfaces/permission" if (!process.env.ELASTICSEARCH_INDEX) { throw new Error("Require ELASTICSEARCH_INDEX to store log.") } const ELASTICSEARCH_INDEX = process.env.ELASTICSEARCH_INDEX const LOG_LEVEL_MAP: Record = { debug: 4, info: 3, warning: 2, error: 1, none: 0, } const elasticsearch = new Client({ node: `${process.env.ELASTICSEARCH_PROTOCOL}://${process.env.ELASTICSEARCH_HOST}:${process.env.ELASTICSEARCH_PORT}`, }) async function logMiddleware(req: Request, res: Response, next: NextFunction) { if (!req.url.startsWith("/api/")) return next() let data: any const originalJson = res.json res.json = function (v: any) { data = v return originalJson.call(this, v) } const timestamp = new Date().toISOString() const start = performance.now() req.app.locals.logData = {} res.on("finish", async () => { try { if (!req.url.startsWith("/api/")) return const level = LOG_LEVEL_MAP[process.env.LOG_LEVEL ?? "debug"] || 4 if (level === 1 && res.statusCode < 500) return if (level === 2 && res.statusCode < 400) return if (level === 3 && res.statusCode < 200) return const token = req.headers["authorization"] let rootId = null try { rootId = token ? await new permission().checkRootDna(token, req.app.locals.logData.userId) : null } catch (err) { console.warn("Error fetching rootId:", err) } const obj = { logType: res.statusCode >= 500 ? "error" : res.statusCode >= 400 ? "warning" : "info", ip: req.ip, rootId: rootId?.rootDnaId ?? null, systemName: "probation", startTimeStamp: timestamp, endTimeStamp: new Date().toISOString(), processTime: performance.now() - start, host: req.hostname, method: req.method, endpoint: req.url, responseCode: String(res.statusCode === 304 ? 200 : res.statusCode), responseDescription: data?.message, input: level === 4 ? JSON.stringify(req.body, null, 2) : undefined, output: level === 4 ? JSON.stringify(data, null, 2) : undefined, ...req.app.locals.logData, } // Send log to Elasticsearch await elasticsearch.index({ index: ELASTICSEARCH_INDEX, document: obj, }) } catch (err) { console.error("Error in logMiddleware:", err) } }) return next() } export default logMiddleware