{"version":3,"sources":["../../src/common/requestLogger.ts","../../src/common/sentry.ts","../../src/common/serverErrorCounter.ts","../../src/common/tempGzipFile.ts"],"sourcesContent":["import AsyncLock from \"async-lock\";\nimport { Buffer } from \"buffer\";\nimport { randomUUID } from \"crypto\";\nimport { unlinkSync, writeFileSync } from \"fs\";\nimport { IncomingHttpHeaders, OutgoingHttpHeaders } from \"http\";\nimport { tmpdir } from \"os\";\nimport { join } from \"path\";\n\nimport { getSentryEventId } from \"./sentry.js\";\nimport {\n  truncateExceptionMessage,\n  truncateExceptionStackTrace,\n} from \"./serverErrorCounter.js\";\nimport TempGzipFile from \"./tempGzipFile.js\";\n\nconst MAX_BODY_SIZE = 50_000; // 50 KB (uncompressed)\nconst MAX_FILE_SIZE = 1_000_000; // 1 MB (compressed)\nconst MAX_FILES = 50;\nconst MAX_PENDING_WRITES = 100;\nconst BODY_TOO_LARGE = Buffer.from(\"<body too large>\");\nconst BODY_MASKED = Buffer.from(\"<masked>\");\nconst MASKED = \"******\";\nconst ALLOWED_CONTENT_TYPES = [\"application/json\", \"text/plain\"];\nconst EXCLUDE_PATH_PATTERNS = [\n  /\\/_?healthz?$/i,\n  /\\/_?health[_-]?checks?$/i,\n  /\\/_?heart[_-]?beats?$/i,\n  /\\/ping$/i,\n  /\\/ready$/i,\n  /\\/live$/i,\n];\nconst EXCLUDE_USER_AGENT_PATTERNS = [\n  /health[-_ ]?check/i,\n  /microsoft-azure-application-lb/i,\n  /googlehc/i,\n  /kube-probe/i,\n];\nconst MASK_QUERY_PARAM_PATTERNS = [\n  /auth/i,\n  /api-?key/i,\n  /secret/i,\n  /token/i,\n  /password/i,\n  /pwd/i,\n];\nconst MASK_HEADER_PATTERNS = [\n  /auth/i,\n  /api-?key/i,\n  /secret/i,\n  /token/i,\n  /cookie/i,\n];\n\nexport type Request = {\n  timestamp: number;\n  method: string;\n  path?: string;\n  url: string;\n  headers: [string, string][];\n  size?: number;\n  consumer?: string;\n  body?: Buffer;\n};\n\nexport type Response = {\n  statusCode: number;\n  responseTime: number;\n  headers: [string, string][];\n  size?: number;\n  body?: Buffer;\n};\n\nexport type RequestLoggingConfig = {\n  enabled: boolean;\n  logQueryParams: boolean;\n  logRequestHeaders: boolean;\n  logRequestBody: boolean;\n  logResponseHeaders: boolean;\n  logResponseBody: boolean;\n  logException: boolean;\n  maskQueryParams: RegExp[];\n  maskHeaders: RegExp[];\n  maskRequestBodyCallback?: (request: Request) => Buffer | null | undefined;\n  maskResponseBodyCallback?: (\n    request: Request,\n    response: Response,\n  ) => Buffer | null | undefined;\n  excludePaths: RegExp[];\n  excludeCallback?: (request: Request, response: Response) => boolean;\n};\n\nconst DEFAULT_CONFIG: RequestLoggingConfig = {\n  enabled: false,\n  logQueryParams: true,\n  logRequestHeaders: false,\n  logRequestBody: false,\n  logResponseHeaders: true,\n  logResponseBody: false,\n  logException: true,\n  maskQueryParams: [],\n  maskHeaders: [],\n  excludePaths: [],\n};\n\nexport default class RequestLogger {\n  public config: RequestLoggingConfig;\n  public enabled: boolean;\n  public suspendUntil: number | null = null;\n  private pendingWrites: string[] = [];\n  private currentFile: TempGzipFile | null = null;\n  private files: TempGzipFile[] = [];\n  private maintainIntervalId?: NodeJS.Timeout;\n  private lock = new AsyncLock();\n\n  constructor(config?: Partial<RequestLoggingConfig>) {\n    this.config = { ...DEFAULT_CONFIG, ...config };\n    this.enabled = this.config.enabled && checkWritableFs();\n\n    if (this.enabled) {\n      this.maintainIntervalId = setInterval(() => {\n        this.maintain();\n      }, 1000);\n    }\n  }\n\n  private shouldExcludePath(urlPath: string) {\n    const patterns = [...this.config.excludePaths, ...EXCLUDE_PATH_PATTERNS];\n    return matchPatterns(urlPath, patterns);\n  }\n\n  private shouldExcludeUserAgent(userAgent?: string) {\n    return userAgent\n      ? matchPatterns(userAgent, EXCLUDE_USER_AGENT_PATTERNS)\n      : false;\n  }\n\n  private shouldMaskQueryParam(name: string) {\n    const patterns = [\n      ...this.config.maskQueryParams,\n      ...MASK_QUERY_PARAM_PATTERNS,\n    ];\n    return matchPatterns(name, patterns);\n  }\n\n  private shouldMaskHeader(name: string) {\n    const patterns = [...this.config.maskHeaders, ...MASK_HEADER_PATTERNS];\n    return matchPatterns(name, patterns);\n  }\n\n  private hasSupportedContentType(headers: [string, string][]) {\n    const contentType = headers.find(\n      ([k]) => k.toLowerCase() === \"content-type\",\n    )?.[1];\n    return this.isSupportedContentType(contentType);\n  }\n\n  public isSupportedContentType(contentType?: string | null) {\n    return (\n      typeof contentType === \"string\" &&\n      ALLOWED_CONTENT_TYPES.some((t) => contentType.startsWith(t))\n    );\n  }\n\n  private maskQueryParams(search: string) {\n    const params = new URLSearchParams(search);\n    for (const [key] of params) {\n      if (this.shouldMaskQueryParam(key)) {\n        params.set(key, MASKED);\n      }\n    }\n    return params.toString();\n  }\n\n  private maskHeaders(headers: [string, string][]): [string, string][] {\n    return headers.map(([k, v]) => [k, this.shouldMaskHeader(k) ? MASKED : v]);\n  }\n\n  logRequest(request: Request, response: Response, error?: Error) {\n    if (!this.enabled || this.suspendUntil !== null) return;\n\n    const url = new URL(request.url);\n    const path = request.path ?? url.pathname;\n    const userAgent = request.headers.find(\n      ([k]) => k.toLowerCase() === \"user-agent\",\n    )?.[1];\n\n    if (\n      this.shouldExcludePath(path) ||\n      this.shouldExcludeUserAgent(userAgent) ||\n      (this.config.excludeCallback?.(request, response) ?? false)\n    ) {\n      return;\n    }\n\n    // Process query params\n    url.search = this.config.logQueryParams\n      ? this.maskQueryParams(url.search)\n      : \"\";\n    request.url = url.toString();\n\n    // Process request body\n    if (\n      !this.config.logRequestBody ||\n      !this.hasSupportedContentType(request.headers)\n    ) {\n      request.body = undefined;\n    } else if (request.body) {\n      if (request.body.length > MAX_BODY_SIZE) {\n        request.body = BODY_TOO_LARGE;\n      } else if (this.config.maskRequestBodyCallback) {\n        try {\n          request.body =\n            this.config.maskRequestBodyCallback(request) ?? BODY_MASKED;\n          if (request.body.length > MAX_BODY_SIZE) {\n            request.body = BODY_TOO_LARGE;\n          }\n        } catch {\n          request.body = undefined;\n        }\n      }\n    }\n\n    // Process response body\n    if (\n      !this.config.logResponseBody ||\n      !this.hasSupportedContentType(response.headers)\n    ) {\n      response.body = undefined;\n    } else if (response.body) {\n      if (response.body.length > MAX_BODY_SIZE) {\n        response.body = BODY_TOO_LARGE;\n      } else if (this.config.maskResponseBodyCallback) {\n        try {\n          response.body =\n            this.config.maskResponseBodyCallback(request, response) ??\n            BODY_MASKED;\n          if (response.body.length > MAX_BODY_SIZE) {\n            response.body = BODY_TOO_LARGE;\n          }\n        } catch {\n          response.body = undefined;\n        }\n      }\n    }\n\n    // Process headers\n    request.headers = this.config.logRequestHeaders\n      ? this.maskHeaders(request.headers)\n      : [];\n    response.headers = this.config.logResponseHeaders\n      ? this.maskHeaders(response.headers)\n      : [];\n\n    const item = {\n      uuid: randomUUID(),\n      request: skipEmptyValues(request),\n      response: skipEmptyValues(response),\n      exception:\n        error && this.config.logException\n          ? {\n              type: error.name,\n              message: truncateExceptionMessage(error.message),\n              stacktrace: truncateExceptionStackTrace(error.stack || \"\"),\n              sentryEventId: getSentryEventId(),\n            }\n          : null,\n    };\n    [item.request.body, item.response.body].forEach((body) => {\n      if (body) {\n        // @ts-expect-error Different return type\n        body.toJSON = function () {\n          return this.toString(\"base64\");\n        };\n      }\n    });\n    this.pendingWrites.push(JSON.stringify(item));\n\n    if (this.pendingWrites.length > MAX_PENDING_WRITES) {\n      this.pendingWrites.shift();\n    }\n  }\n\n  async writeToFile() {\n    if (!this.enabled || this.pendingWrites.length === 0) {\n      return;\n    }\n    return this.lock.acquire(\"file\", async () => {\n      if (!this.currentFile) {\n        this.currentFile = new TempGzipFile();\n      }\n      while (this.pendingWrites.length > 0) {\n        const item = this.pendingWrites.shift();\n        if (item) {\n          await this.currentFile.writeLine(Buffer.from(item));\n        }\n      }\n    });\n  }\n\n  getFile() {\n    return this.files.shift();\n  }\n\n  retryFileLater(file: TempGzipFile) {\n    this.files.unshift(file);\n  }\n\n  async rotateFile() {\n    return this.lock.acquire(\"file\", async () => {\n      if (this.currentFile) {\n        await this.currentFile.close();\n        this.files.push(this.currentFile);\n        this.currentFile = null;\n      }\n    });\n  }\n\n  async maintain() {\n    await this.writeToFile();\n    if (this.currentFile && this.currentFile.size > MAX_FILE_SIZE) {\n      await this.rotateFile();\n    }\n    while (this.files.length > MAX_FILES) {\n      const file = this.files.shift();\n      file?.delete();\n    }\n    if (this.suspendUntil !== null && this.suspendUntil < Date.now()) {\n      this.suspendUntil = null;\n    }\n  }\n\n  async clear() {\n    this.pendingWrites = [];\n    await this.rotateFile();\n    this.files.forEach((file) => {\n      file.delete();\n    });\n    this.files = [];\n  }\n\n  async close() {\n    this.enabled = false;\n    await this.clear();\n    if (this.maintainIntervalId) {\n      clearInterval(this.maintainIntervalId);\n    }\n  }\n}\n\nexport function convertHeaders(\n  headers:\n    | Headers\n    | IncomingHttpHeaders\n    | OutgoingHttpHeaders\n    | Record<string, string | string[] | number | undefined>,\n) {\n  if (headers instanceof Headers) {\n    return Array.from(headers.entries());\n  }\n  return Object.entries(headers).flatMap(([key, value]) => {\n    if (value === undefined) {\n      return [];\n    }\n    if (Array.isArray(value)) {\n      return value.map((v) => [key, v]);\n    }\n    return [[key, value.toString()]];\n  }) as [string, string][];\n}\n\nexport function convertBody(body: any, contentType?: string | null) {\n  if (!body || !contentType) {\n    return;\n  }\n  try {\n    if (contentType.startsWith(\"application/json\")) {\n      if (isValidJsonString(body)) {\n        return Buffer.from(body);\n      } else {\n        return Buffer.from(JSON.stringify(body));\n      }\n    }\n    if (contentType.startsWith(\"text/\") && typeof body === \"string\") {\n      return Buffer.from(body);\n    }\n  } catch (error) {\n    return;\n  }\n}\n\nfunction isValidJsonString(body: any) {\n  if (typeof body !== \"string\") {\n    return false;\n  }\n  try {\n    JSON.parse(body);\n    return true;\n  } catch {\n    return false;\n  }\n}\n\nfunction matchPatterns(value: string, patterns: RegExp[]) {\n  return patterns.some((pattern) => {\n    return pattern.test(value);\n  });\n}\n\nfunction skipEmptyValues<T extends Record<string, any>>(data: T) {\n  return Object.fromEntries(\n    Object.entries(data).filter(([_, v]) => {\n      if (v == null || Number.isNaN(v)) return false;\n      if (Array.isArray(v) || Buffer.isBuffer(v) || typeof v === \"string\") {\n        return v.length > 0;\n      }\n      return true;\n    }),\n  ) as Partial<T>;\n}\n\nfunction checkWritableFs() {\n  try {\n    const testPath = join(tmpdir(), `apitally-${randomUUID()}`);\n    writeFileSync(testPath, \"test\");\n    unlinkSync(testPath);\n    return true;\n  } catch (error) {\n    return false;\n  }\n}\n","import type * as Sentry from \"@sentry/node\";\n\nlet sentry: typeof Sentry | undefined;\n\n// Initialize Sentry when the module is loaded\n(async () => {\n  try {\n    sentry = await import(\"@sentry/node\");\n  } catch (e) {\n    // Sentry SDK is not installed, ignore\n  }\n})();\n\n/**\n * Returns the last Sentry event ID if available\n */\nexport function getSentryEventId(): string | undefined {\n  if (sentry && sentry.lastEventId) {\n    return sentry.lastEventId();\n  }\n  return undefined;\n}\n","import { createHash } from \"crypto\";\n\nimport { getSentryEventId } from \"./sentry.js\";\nimport { ConsumerMethodPath, ServerError, ServerErrorsItem } from \"./types.js\";\n\nconst MAX_MSG_LENGTH = 2048;\nconst MAX_STACKTRACE_LENGTH = 65536;\n\nexport default class ServerErrorCounter {\n  private errorCounts: Map<string, number>;\n  private errorDetails: Map<string, ConsumerMethodPath & ServerError>;\n  private sentryEventIds: Map<string, string>;\n\n  constructor() {\n    this.errorCounts = new Map();\n    this.errorDetails = new Map();\n    this.sentryEventIds = new Map();\n  }\n\n  public addServerError(serverError: ConsumerMethodPath & ServerError) {\n    const key = this.getKey(serverError);\n    if (!this.errorDetails.has(key)) {\n      this.errorDetails.set(key, serverError);\n    }\n    this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);\n\n    const sentryEventId = getSentryEventId();\n    if (sentryEventId) {\n      this.sentryEventIds.set(key, sentryEventId);\n    }\n  }\n\n  public getAndResetServerErrors() {\n    const data: Array<ServerErrorsItem> = [];\n    this.errorCounts.forEach((count, key) => {\n      const serverError = this.errorDetails.get(key);\n      if (serverError) {\n        data.push({\n          consumer: serverError.consumer || null,\n          method: serverError.method,\n          path: serverError.path,\n          type: serverError.type,\n          msg: truncateExceptionMessage(serverError.msg),\n          traceback: truncateExceptionStackTrace(serverError.traceback),\n          sentry_event_id: this.sentryEventIds.get(key) || null,\n          error_count: count,\n        });\n      }\n    });\n    this.errorCounts.clear();\n    this.errorDetails.clear();\n    return data;\n  }\n\n  private getKey(serverError: ConsumerMethodPath & ServerError) {\n    const hashInput = [\n      serverError.consumer || \"\",\n      serverError.method.toUpperCase(),\n      serverError.path,\n      serverError.type,\n      serverError.msg.trim(),\n      serverError.traceback.trim(),\n    ].join(\"|\");\n    return createHash(\"md5\").update(hashInput).digest(\"hex\");\n  }\n}\n\nexport function truncateExceptionMessage(msg: string) {\n  if (msg.length <= MAX_MSG_LENGTH) {\n    return msg;\n  }\n  const suffix = \"... (truncated)\";\n  const cutoff = MAX_MSG_LENGTH - suffix.length;\n  return msg.substring(0, cutoff) + suffix;\n}\n\nexport function truncateExceptionStackTrace(stack: string) {\n  const suffix = \"... (truncated) ...\";\n  const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;\n  const lines = stack.trim().split(\"\\n\");\n  const truncatedLines: string[] = [];\n  let length = 0;\n  for (const line of lines) {\n    if (length + line.length + 1 > cutoff) {\n      truncatedLines.push(suffix);\n      break;\n    }\n    truncatedLines.push(line);\n    length += line.length + 1;\n  }\n  return truncatedLines.join(\"\\n\");\n}\n","import { Buffer } from \"buffer\";\nimport { randomUUID } from \"crypto\";\nimport { createWriteStream, readFile, unlinkSync, WriteStream } from \"fs\";\nimport { tmpdir } from \"os\";\nimport { join } from \"path\";\nimport { createGzip, Gzip } from \"zlib\";\n\nexport default class TempGzipFile {\n  public uuid: string;\n  private filePath: string;\n  private gzip: Gzip;\n  private writeStream: WriteStream;\n  private readyPromise: Promise<void>;\n  private closedPromise: Promise<void>;\n\n  constructor() {\n    this.uuid = randomUUID();\n    this.filePath = join(tmpdir(), `apitally-${this.uuid}.gz`);\n    this.writeStream = createWriteStream(this.filePath);\n    this.readyPromise = new Promise<void>((resolve, reject) => {\n      this.writeStream.once(\"ready\", resolve);\n      this.writeStream.once(\"error\", reject);\n    });\n    this.closedPromise = new Promise<void>((resolve, reject) => {\n      this.writeStream.once(\"close\", resolve);\n      this.writeStream.once(\"error\", reject);\n    });\n    this.gzip = createGzip();\n    this.gzip.pipe(this.writeStream);\n  }\n\n  get size() {\n    return this.writeStream.bytesWritten;\n  }\n\n  async writeLine(data: Buffer) {\n    await this.readyPromise;\n    return new Promise<void>((resolve, reject) => {\n      this.gzip.write(Buffer.concat([data, Buffer.from(\"\\n\")]), (error) => {\n        if (error) {\n          reject(error);\n        } else {\n          resolve();\n        }\n      });\n    });\n  }\n\n  async getContent() {\n    return new Promise<Buffer>((resolve, reject) => {\n      readFile(this.filePath, (error, data) => {\n        if (error) {\n          reject(error);\n        } else {\n          resolve(data);\n        }\n      });\n    });\n  }\n\n  async close() {\n    await new Promise<void>((resolve) => {\n      this.gzip.end(() => {\n        resolve();\n      });\n    });\n    await this.closedPromise;\n  }\n\n  async delete() {\n    await this.close();\n    unlinkSync(this.filePath);\n  }\n}\n"],"mappings":"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","names":["import_buffer","import_crypto","import_fs","import_os","import_path","sentry","e","getSentryEventId","lastEventId","undefined","MAX_MSG_LENGTH","MAX_STACKTRACE_LENGTH","truncateExceptionMessage","msg","length","MAX_MSG_LENGTH","suffix","cutoff","substring","truncateExceptionStackTrace","stack","MAX_STACKTRACE_LENGTH","lines","trim","split","truncatedLines","line","push","join","TempGzipFile","uuid","filePath","gzip","writeStream","readyPromise","closedPromise","constructor","randomUUID","join","tmpdir","createWriteStream","Promise","resolve","reject","once","createGzip","pipe","size","bytesWritten","writeLine","data","write","Buffer","concat","from","error","getContent","readFile","close","end","delete","unlinkSync","MAX_BODY_SIZE","MAX_FILE_SIZE","MAX_FILES","MAX_PENDING_WRITES","BODY_TOO_LARGE","Buffer","from","BODY_MASKED","MASKED","ALLOWED_CONTENT_TYPES","EXCLUDE_PATH_PATTERNS","EXCLUDE_USER_AGENT_PATTERNS","MASK_QUERY_PARAM_PATTERNS","MASK_HEADER_PATTERNS","DEFAULT_CONFIG","enabled","logQueryParams","logRequestHeaders","logRequestBody","logResponseHeaders","logResponseBody","logException","maskQueryParams","maskHeaders","excludePaths","RequestLogger","config","suspendUntil","pendingWrites","currentFile","files","maintainIntervalId","lock","AsyncLock","constructor","checkWritableFs","setInterval","maintain","shouldExcludePath","urlPath","patterns","matchPatterns","shouldExcludeUserAgent","userAgent","shouldMaskQueryParam","name","shouldMaskHeader","hasSupportedContentType","headers","contentType","find","k","toLowerCase","isSupportedContentType","some","t","startsWith","search","params","URLSearchParams","key","set","toString","map","v","logRequest","request","response","error","url","URL","path","pathname","excludeCallback","body","undefined","length","maskRequestBodyCallback","maskResponseBodyCallback","item","uuid","randomUUID","skipEmptyValues","exception","type","message","truncateExceptionMessage","stacktrace","truncateExceptionStackTrace","stack","sentryEventId","getSentryEventId","forEach","toJSON","push","JSON","stringify","shift","writeToFile","acquire","TempGzipFile","writeLine","getFile","retryFileLater","file","unshift","rotateFile","close","size","delete","Date","now","clear","clearInterval","convertHeaders","Headers","Array","entries","Object","flatMap","value","isArray","convertBody","isValidJsonString","parse","pattern","test","data","fromEntries","filter","_","Number","isNaN","isBuffer","testPath","join","tmpdir","writeFileSync","unlinkSync"]}