{"version":3,"sources":["../../src/loggers/pino.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\n\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { formatMessage, removeKeys } from \"./utils.js\";\n\nconst MAX_BUFFER_SIZE = 1000;\n\nconst originalStreamSym = Symbol.for(\"apitally.originalStream\");\nconst logLevelMap: Record<number, string> = {\n  10: \"trace\",\n  20: \"debug\",\n  30: \"info\",\n  40: \"warn\",\n  50: \"error\",\n  60: \"fatal\",\n};\n\nexport async function patchPinoLogger(\n  logger: any,\n  logsContext: AsyncLocalStorage<LogRecord[]>,\n) {\n  try {\n    // Find stream and message key symbols on the logger and its prototype\n    const symbols = [\n      ...Object.getOwnPropertySymbols(logger),\n      ...Object.getOwnPropertySymbols(Object.getPrototypeOf(logger)),\n    ];\n    const streamSym = symbols.find(\n      (sym) => sym.toString() === \"Symbol(pino.stream)\",\n    );\n    const messageKeySym = symbols.find(\n      (sym) => sym.toString() === \"Symbol(pino.messageKey)\",\n    );\n    if (!streamSym || !messageKeySym) {\n      // not a pino logger\n      return false;\n    }\n\n    if (!(originalStreamSym in logger)) {\n      logger[originalStreamSym] = logger[streamSym];\n    }\n\n    const originalStream = logger[originalStreamSym];\n    if (originalStream) {\n      const pino = await import(/* webpackIgnore: true */ \"pino\");\n      const captureStream = new ApitallyLogCaptureStream(\n        logsContext,\n        logger[messageKeySym],\n      );\n      logger[streamSym] = pino.default.multistream(\n        [\n          { level: 0, stream: originalStream },\n          { level: 0, stream: captureStream },\n        ],\n        {\n          levels: logger.levels,\n        },\n      );\n    }\n    return true;\n  } catch {\n    // ignore errors\n    return false;\n  }\n}\n\nfunction filterLogs(obj: any, messageKey: string) {\n  return obj[messageKey] !== \"request completed\";\n}\n\nclass ApitallyLogCaptureStream {\n  private logsContext: AsyncLocalStorage<LogRecord[]>;\n  private messageKey: string;\n\n  constructor(logsContext: AsyncLocalStorage<LogRecord[]>, messageKey: string) {\n    this.logsContext = logsContext;\n    this.messageKey = messageKey;\n  }\n\n  write(msg: string): void {\n    const logs = this.logsContext.getStore();\n    if (!logs || !msg || logs.length >= MAX_BUFFER_SIZE) {\n      return;\n    }\n\n    let obj: any;\n    try {\n      obj = JSON.parse(msg);\n    } catch (e) {\n      return;\n    }\n    if (\n      obj === null ||\n      typeof obj !== \"object\" ||\n      !filterLogs(obj, this.messageKey)\n    ) {\n      return;\n    }\n\n    try {\n      let message = obj[this.messageKey];\n      const ignoreKeys = [\n        \"hostname\",\n        \"level\",\n        this.messageKey,\n        \"pid\",\n        \"time\",\n        \"reqId\",\n        \"req\",\n        \"res\",\n      ];\n      if (!message && \"data\" in obj && \"tags\" in obj) {\n        // hapi-pino uses data and tags instead of the message key\n        message = obj.data;\n        ignoreKeys.push(\"data\");\n        ignoreKeys.push(\"tags\");\n      }\n      const rest = removeKeys(obj, ignoreKeys);\n      const formattedMessage = formatMessage(message, rest);\n      if (formattedMessage) {\n        logs.push({\n          timestamp: this.convertTime(obj.time),\n          level: logLevelMap[obj.level] || \"info\",\n          message: formattedMessage,\n        });\n      }\n    } catch (e) {\n      // ignore\n    }\n  }\n\n  private convertTime(time: any): number {\n    if (typeof time === \"number\" && !isNaN(time)) {\n      return time / 1000; // Convert milliseconds to seconds\n    }\n    return Date.now() / 1000; // Fallback to current time\n  }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA;;;;;AAAA,mBAA0C;AAA1C;AAEA,MAAMA,kBAAkB;AAExB,MAAMC,oBAAoBC,uBAAOC,IAAI,yBAAA;AACrC,MAAMC,cAAsC;EAC1C,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;AACN;AAEA,eAAsBC,gBACpBC,QACAC,aAA2C;AAE3C,MAAI;AAEF,UAAMC,UAAU;SACXC,OAAOC,sBAAsBJ,MAAAA;SAC7BG,OAAOC,sBAAsBD,OAAOE,eAAeL,MAAAA,CAAAA;;AAExD,UAAMM,YAAYJ,QAAQK,KACxB,CAACC,QAAQA,IAAIC,SAAQ,MAAO,qBAAA;AAE9B,UAAMC,gBAAgBR,QAAQK,KAC5B,CAACC,QAAQA,IAAIC,SAAQ,MAAO,yBAAA;AAE9B,QAAI,CAACH,aAAa,CAACI,eAAe;AAEhC,aAAO;IACT;AAEA,QAAI,EAAEf,qBAAqBK,SAAS;AAClCA,aAAOL,iBAAAA,IAAqBK,OAAOM,SAAAA;IACrC;AAEA,UAAMK,iBAAiBX,OAAOL,iBAAAA;AAC9B,QAAIgB,gBAAgB;AAClB,YAAMC,OAAO,MAAM;;QAAiC;MAAA;AACpD,YAAMC,gBAAgB,IAAIC,yBACxBb,aACAD,OAAOU,aAAAA,CAAc;AAEvBV,aAAOM,SAAAA,IAAaM,KAAKG,QAAQC,YAC/B;QACE;UAAEC,OAAO;UAAGC,QAAQP;QAAe;QACnC;UAAEM,OAAO;UAAGC,QAAQL;QAAc;SAEpC;QACEM,QAAQnB,OAAOmB;MACjB,CAAA;IAEJ;AACA,WAAO;EACT,QAAQ;AAEN,WAAO;EACT;AACF;AA/CsBpB;AAiDtB,SAASqB,WAAWC,KAAUC,YAAkB;AAC9C,SAAOD,IAAIC,UAAAA,MAAgB;AAC7B;AAFSF;AAIT,IAAMN,4BAAN,WAAMA;EACIb;EACAqB;EAER,YAAYrB,aAA6CqB,YAAoB;AAC3E,SAAKrB,cAAcA;AACnB,SAAKqB,aAAaA;EACpB;EAEAC,MAAMC,KAAmB;AACvB,UAAMC,OAAO,KAAKxB,YAAYyB,SAAQ;AACtC,QAAI,CAACD,QAAQ,CAACD,OAAOC,KAAKE,UAAUjC,iBAAiB;AACnD;IACF;AAEA,QAAI2B;AACJ,QAAI;AACFA,YAAMO,KAAKC,MAAML,GAAAA;IACnB,SAASM,GAAG;AACV;IACF;AACA,QACET,QAAQ,QACR,OAAOA,QAAQ,YACf,CAACD,WAAWC,KAAK,KAAKC,UAAU,GAChC;AACA;IACF;AAEA,QAAI;AACF,UAAIS,UAAUV,IAAI,KAAKC,UAAU;AACjC,YAAMU,aAAa;QACjB;QACA;QACA,KAAKV;QACL;QACA;QACA;QACA;QACA;;AAEF,UAAI,CAACS,WAAW,UAAUV,OAAO,UAAUA,KAAK;AAE9CU,kBAAUV,IAAIY;AACdD,mBAAWE,KAAK,MAAA;AAChBF,mBAAWE,KAAK,MAAA;MAClB;AACA,YAAMC,WAAOC,yBAAWf,KAAKW,UAAAA;AAC7B,YAAMK,uBAAmBC,4BAAcP,SAASI,IAAAA;AAChD,UAAIE,kBAAkB;AACpBZ,aAAKS,KAAK;UACRK,WAAW,KAAKC,YAAYnB,IAAIoB,IAAI;UACpCxB,OAAOnB,YAAYuB,IAAIJ,KAAK,KAAK;UACjCc,SAASM;QACX,CAAA;MACF;IACF,SAASP,GAAG;IAEZ;EACF;EAEQU,YAAYC,MAAmB;AACrC,QAAI,OAAOA,SAAS,YAAY,CAACC,MAAMD,IAAAA,GAAO;AAC5C,aAAOA,OAAO;IAChB;AACA,WAAOE,KAAKC,IAAG,IAAK;EACtB;AACF,GAnEM9B,wCAAN;","names":["MAX_BUFFER_SIZE","originalStreamSym","Symbol","for","logLevelMap","patchPinoLogger","logger","logsContext","symbols","Object","getOwnPropertySymbols","getPrototypeOf","streamSym","find","sym","toString","messageKeySym","originalStream","pino","captureStream","ApitallyLogCaptureStream","default","multistream","level","stream","levels","filterLogs","obj","messageKey","write","msg","logs","getStore","length","JSON","parse","e","message","ignoreKeys","data","push","rest","removeKeys","formattedMessage","formatMessage","timestamp","convertTime","time","isNaN","Date","now"]}