apitally
Version:
Simple API monitoring & analytics for REST APIs built with Express, Fastify, NestJS, AdonisJS, Hono, H3, Elysia, Hapi, and Koa.
1 lines • 5.08 kB
Source Map (JSON)
{"version":3,"sources":["../../src/loggers/nestjs.ts","../../src/loggers/utils.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\n\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { formatMessage } from \"./utils.js\";\n\ntype LogLevel = \"log\" | \"error\" | \"warn\" | \"debug\" | \"verbose\" | \"fatal\";\n\nconst MAX_BUFFER_SIZE = 1000;\n\nlet isPatched = false;\nlet globalLogsContext: AsyncLocalStorage<LogRecord[]>;\n\nexport async function patchNestLogger(\n logsContext: AsyncLocalStorage<LogRecord[]>,\n) {\n globalLogsContext = logsContext;\n\n if (isPatched) {\n return;\n }\n\n try {\n const { Logger } = await import(\"@nestjs/common\");\n const logMethods: LogLevel[] = [\n \"log\",\n \"error\",\n \"warn\",\n \"debug\",\n \"verbose\",\n \"fatal\",\n ];\n\n // Patch static methods\n logMethods.forEach((method) => {\n const originalMethod = Logger[method];\n Logger[method] = function (message: any, ...args: any[]) {\n captureLog(method, [message, ...args]);\n return originalMethod.apply(Logger, [message, ...args]);\n };\n });\n\n // Patch prototype methods to affect all instances (new and existing)\n logMethods.forEach((method) => {\n const originalMethod = Logger.prototype[method];\n Logger.prototype[method] = function (message: any, ...args: any[]) {\n captureLog(method, [message, ...args], this.context);\n return originalMethod.apply(this, [message, ...args]);\n };\n });\n\n isPatched = true;\n } catch {\n // @nestjs/common is not installed, silently ignore\n }\n}\n\nfunction captureLog(level: LogLevel, args: any[], context?: string) {\n const logs = globalLogsContext?.getStore();\n if (logs && logs.length < MAX_BUFFER_SIZE) {\n logs.push({\n timestamp: Date.now() / 1000,\n logger: context,\n level,\n message: formatMessage(args[0], ...args.slice(1)),\n });\n }\n}\n","import { format } from \"node:util\";\n\nexport function formatMessage(message: any, ...args: any[]) {\n return [message, ...args]\n .map(formatArg)\n .filter((arg) => arg !== \"\")\n .join(\"\\n\");\n}\n\nexport function removeKeys(obj: any, keys: string[]) {\n return Object.fromEntries(\n Object.entries(obj).filter(([key]) => !keys.includes(key)),\n );\n}\n\nfunction formatArg(arg: any) {\n if (typeof arg === \"string\") {\n return arg.trim();\n }\n if (arg instanceof Error) {\n return format(arg).trim();\n }\n if (arg === undefined || arg === null || isEmptyObject(arg)) {\n return \"\";\n }\n try {\n return JSON.stringify(arg);\n } catch {\n return format(arg).trim();\n }\n}\n\nfunction isEmptyObject(obj: any) {\n return (\n obj !== null &&\n typeof obj === \"object\" &&\n Object.getPrototypeOf(obj) === Object.prototype &&\n Object.keys(obj).length === 0\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA;;;;;;;ACHA,uBAAuB;AAEhB,SAASA,cAAcC,YAAiBC,MAAW;AACxD,SAAO;IAACD;OAAYC;IACjBC,IAAIC,SAAAA,EACJC,OAAO,CAACC,QAAQA,QAAQ,EAAA,EACxBC,KAAK,IAAA;AACV;AALgBP;AAahB,SAASQ,UAAUC,KAAQ;AACzB,MAAI,OAAOA,QAAQ,UAAU;AAC3B,WAAOA,IAAIC,KAAI;EACjB;AACA,MAAID,eAAeE,OAAO;AACxB,eAAOC,yBAAOH,GAAAA,EAAKC,KAAI;EACzB;AACA,MAAID,QAAQI,UAAaJ,QAAQ,QAAQK,cAAcL,GAAAA,GAAM;AAC3D,WAAO;EACT;AACA,MAAI;AACF,WAAOM,KAAKC,UAAUP,GAAAA;EACxB,QAAQ;AACN,eAAOG,yBAAOH,GAAAA,EAAKC,KAAI;EACzB;AACF;AAfSF;AAiBT,SAASM,cAAcG,KAAQ;AAC7B,SACEA,QAAQ,QACR,OAAOA,QAAQ,YACfC,OAAOC,eAAeF,GAAAA,MAASC,OAAOE,aACtCF,OAAOG,KAAKJ,GAAAA,EAAKK,WAAW;AAEhC;AAPSR;;;ADzBT,IAAMS,kBAAkB;AAExB,IAAIC,YAAY;AAChB,IAAIC;AAEJ,eAAsBC,gBACpBC,aAA2C;AAE3CF,sBAAoBE;AAEpB,MAAIH,WAAW;AACb;EACF;AAEA,MAAI;AACF,UAAM,EAAEI,OAAM,IAAK,MAAM,OAAO,gBAAA;AAChC,UAAMC,aAAyB;MAC7B;MACA;MACA;MACA;MACA;MACA;;AAIFA,eAAWC,QAAQ,CAACC,WAAAA;AAClB,YAAMC,iBAAiBJ,OAAOG,MAAAA;AAC9BH,aAAOG,MAAAA,IAAU,SAAUE,YAAiBC,MAAW;AACrDC,mBAAWJ,QAAQ;UAACE;aAAYC;SAAK;AACrC,eAAOF,eAAeI,MAAMR,QAAQ;UAACK;aAAYC;SAAK;MACxD;IACF,CAAA;AAGAL,eAAWC,QAAQ,CAACC,WAAAA;AAClB,YAAMC,iBAAiBJ,OAAOS,UAAUN,MAAAA;AACxCH,aAAOS,UAAUN,MAAAA,IAAU,SAAUE,YAAiBC,MAAW;AAC/DC,mBAAWJ,QAAQ;UAACE;aAAYC;WAAO,KAAKI,OAAO;AACnD,eAAON,eAAeI,MAAM,MAAM;UAACH;aAAYC;SAAK;MACtD;IACF,CAAA;AAEAV,gBAAY;EACd,QAAQ;EAER;AACF;AA1CsBE;AA4CtB,SAASS,WAAWI,OAAiBL,MAAaI,SAAgB;AAChE,QAAME,OAAOf,uDAAmBgB;AAChC,MAAID,QAAQA,KAAKE,SAASnB,iBAAiB;AACzCiB,SAAKG,KAAK;MACRC,WAAWC,KAAKC,IAAG,IAAK;MACxBC,QAAQT;MACRC;MACAN,SAASe,cAAcd,KAAK,CAAA,GAAE,GAAKA,KAAKe,MAAM,CAAA,CAAA;IAChD,CAAA;EACF;AACF;AAVSd;","names":["formatMessage","message","args","map","formatArg","filter","arg","join","formatArg","arg","trim","Error","format","undefined","isEmptyObject","JSON","stringify","obj","Object","getPrototypeOf","prototype","keys","length","MAX_BUFFER_SIZE","isPatched","globalLogsContext","patchNestLogger","logsContext","Logger","logMethods","forEach","method","originalMethod","message","args","captureLog","apply","prototype","context","level","logs","getStore","length","push","timestamp","Date","now","logger","formatMessage","slice"]}