UNPKG

@fofmbarros/express-logger

Version:

Plug and play Express.js request and response middleware

1 lines 5.11 kB
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Request, RequestHandler } from \"express\";\nimport { XMLParser } from \"fast-xml-parser\";\nimport { randomUUID } from \"node:crypto\";\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Express {\n interface Request {\n requestId: string;\n }\n }\n}\n\ntype LoggerLevel = \"info\" | \"warn\" | \"error\";\n\ntype LoggerFunction = (\n context: Record<string, unknown>,\n message: string\n) => void;\n\ntype Logger = Record<LoggerLevel, LoggerFunction>;\n\ninterface Config {\n logger?: Logger;\n}\n\nconst parseBody = (body: unknown, contentType?: string) => {\n if (typeof body === \"object\" || typeof body === \"undefined\") return body;\n\n const parsedContentType = contentType?.split(\"; \")[0];\n\n switch (parsedContentType) {\n case \"image/svg+xml\":\n case \"application/xml\":\n case \"application/atom+xml\":\n case \"text/xml\": {\n const parser = new XMLParser({\n ignoreDeclaration: true,\n parseTagValue: false,\n });\n const value = parser.parse(body as string);\n return value;\n }\n case \"application/json\":\n return JSON.parse(body as string);\n default:\n return body;\n }\n};\n\nconst getLoggerLevel = (statusCode: number): LoggerLevel => {\n const level =\n statusCode >= 500 ? \"error\" : statusCode >= 400 ? \"warn\" : \"info\";\n\n return level;\n};\n\nconst getRequestIp = (req: Request): string =>\n (req.headers[\"x-envoy-external-address\"] as string) ?? req.ip ?? \"0.0.0.0\";\n\nconst requestLogger =\n (config?: Config): RequestHandler =>\n (req, res, next) => {\n const logger = config?.logger ?? {\n info: console.log,\n warn: console.warn,\n error: console.error,\n };\n\n const requestId = randomUUID();\n req.requestId = requestId;\n\n let rawResponseBody: unknown;\n let responseBody: unknown;\n\n const send = res.send;\n res.send = (body) => {\n const contentType = res.getHeader(\"Content-Type\");\n\n rawResponseBody = body;\n responseBody = parseBody(\n body,\n typeof contentType === \"string\" ? contentType : undefined\n );\n\n res.send = send;\n return res.send(body);\n };\n\n res.on(\"finish\", () => {\n const level = getLoggerLevel(res.statusCode);\n const ip = getRequestIp(req);\n\n logger[level](\n { requestId },\n `[${ip}] [${req.method}] ${\n req.originalUrl\n } ${req.protocol.toUpperCase()} ${req.httpVersion} ${res.statusCode}`\n );\n\n const requestContentType = req.header(\"Content-Type\");\n const requestBody = parseBody(req.body, requestContentType);\n\n logger[level](\n { requestId, type: \"REQUEST\" },\n JSON.stringify({\n params: req.params,\n query: req.query,\n headers: req.headers,\n cookies: req.cookies,\n rawBody: req.body,\n body: requestBody,\n })\n );\n\n logger[level](\n { requestId, type: \"RESPONSE\" },\n JSON.stringify({\n rawBody: rawResponseBody,\n body: responseBody,\n })\n );\n });\n\n next();\n };\n\nexport type { Logger, Config };\nexport default requestLogger;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,6BAA0B;AAC1B,yBAA2B;AAwB3B,IAAM,YAAY,CAAC,MAAe,gBAAyB;AACzD,MAAI,OAAO,SAAS,YAAY,OAAO,SAAS,YAAa,QAAO;AAEpE,QAAM,oBAAoB,aAAa,MAAM,IAAI,EAAE,CAAC;AAEpD,UAAQ,mBAAmB;AAAA,IACzB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK,YAAY;AACf,YAAM,SAAS,IAAI,iCAAU;AAAA,QAC3B,mBAAmB;AAAA,QACnB,eAAe;AAAA,MACjB,CAAC;AACD,YAAM,QAAQ,OAAO,MAAM,IAAc;AACzC,aAAO;AAAA,IACT;AAAA,IACA,KAAK;AACH,aAAO,KAAK,MAAM,IAAc;AAAA,IAClC;AACE,aAAO;AAAA,EACX;AACF;AAEA,IAAM,iBAAiB,CAAC,eAAoC;AAC1D,QAAM,QACJ,cAAc,MAAM,UAAU,cAAc,MAAM,SAAS;AAE7D,SAAO;AACT;AAEA,IAAM,eAAe,CAAC,QACnB,IAAI,QAAQ,0BAA0B,KAAgB,IAAI,MAAM;AAEnE,IAAM,gBACJ,CAAC,WACD,CAAC,KAAK,KAAK,SAAS;AAClB,QAAM,SAAS,QAAQ,UAAU;AAAA,IAC/B,MAAM,QAAQ;AAAA,IACd,MAAM,QAAQ;AAAA,IACd,OAAO,QAAQ;AAAA,EACjB;AAEA,QAAM,gBAAY,+BAAW;AAC7B,MAAI,YAAY;AAEhB,MAAI;AACJ,MAAI;AAEJ,QAAM,OAAO,IAAI;AACjB,MAAI,OAAO,CAAC,SAAS;AACnB,UAAM,cAAc,IAAI,UAAU,cAAc;AAEhD,sBAAkB;AAClB,mBAAe;AAAA,MACb;AAAA,MACA,OAAO,gBAAgB,WAAW,cAAc;AAAA,IAClD;AAEA,QAAI,OAAO;AACX,WAAO,IAAI,KAAK,IAAI;AAAA,EACtB;AAEA,MAAI,GAAG,UAAU,MAAM;AACrB,UAAM,QAAQ,eAAe,IAAI,UAAU;AAC3C,UAAM,KAAK,aAAa,GAAG;AAE3B,WAAO,KAAK;AAAA,MACV,EAAE,UAAU;AAAA,MACZ,IAAI,EAAE,MAAM,IAAI,MAAM,KACpB,IAAI,WACN,IAAI,IAAI,SAAS,YAAY,CAAC,IAAI,IAAI,WAAW,IAAI,IAAI,UAAU;AAAA,IACrE;AAEA,UAAM,qBAAqB,IAAI,OAAO,cAAc;AACpD,UAAM,cAAc,UAAU,IAAI,MAAM,kBAAkB;AAE1D,WAAO,KAAK;AAAA,MACV,EAAE,WAAW,MAAM,UAAU;AAAA,MAC7B,KAAK,UAAU;AAAA,QACb,QAAQ,IAAI;AAAA,QACZ,OAAO,IAAI;AAAA,QACX,SAAS,IAAI;AAAA,QACb,SAAS,IAAI;AAAA,QACb,SAAS,IAAI;AAAA,QACb,MAAM;AAAA,MACR,CAAC;AAAA,IACH;AAEA,WAAO,KAAK;AAAA,MACV,EAAE,WAAW,MAAM,WAAW;AAAA,MAC9B,KAAK,UAAU;AAAA,QACb,SAAS;AAAA,QACT,MAAM;AAAA,MACR,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAED,OAAK;AACP;AAGF,IAAO,gBAAQ;","names":[]}