@tanngo11/log 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/CONTRACT.md +1 -1
  3. package/README.md +21 -3
  4. package/dist/bullmq.cjs.map +1 -1
  5. package/dist/bullmq.d.cts +1 -1
  6. package/dist/bullmq.d.ts +1 -1
  7. package/dist/bullmq.js +2 -2
  8. package/dist/{chunk-UXKPPF4G.js → chunk-2WNGXGP7.js} +2 -2
  9. package/dist/{chunk-754Y5TQX.js → chunk-AF4YR4Y4.js} +14 -5
  10. package/dist/chunk-AF4YR4Y4.js.map +1 -0
  11. package/dist/{chunk-7DW57ECW.js → chunk-RVETZAK5.js} +3 -3
  12. package/dist/{chunk-QMC6BWGK.js → chunk-UDS6S22P.js} +28 -4
  13. package/dist/chunk-UDS6S22P.js.map +1 -0
  14. package/dist/{chunk-42ZPVKHN.js → chunk-UOIJCSP5.js} +3 -3
  15. package/dist/{chunk-AL4LJLUZ.js → chunk-URPHVC4Y.js} +19 -7
  16. package/dist/chunk-URPHVC4Y.js.map +1 -0
  17. package/dist/express.cjs +26 -4
  18. package/dist/express.cjs.map +1 -1
  19. package/dist/express.d.cts +2 -2
  20. package/dist/express.d.ts +2 -2
  21. package/dist/express.js +3 -3
  22. package/dist/fastify.cjs +26 -4
  23. package/dist/fastify.cjs.map +1 -1
  24. package/dist/fastify.d.cts +2 -2
  25. package/dist/fastify.d.ts +2 -2
  26. package/dist/fastify.js +3 -3
  27. package/dist/{http-BI6ARZlD.d.ts → http-44ztBSXk.d.ts} +1 -1
  28. package/dist/{http-BXAiU-rN.d.cts → http-BQJkHBwQ.d.cts} +1 -1
  29. package/dist/index.cjs +109 -11
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +46 -5
  32. package/dist/index.d.ts +46 -5
  33. package/dist/index.js +59 -4
  34. package/dist/index.js.map +1 -1
  35. package/dist/{logger-CFMTzjsm.d.cts → logger-3Co9eVJf.d.cts} +4 -1
  36. package/dist/{logger-CFMTzjsm.d.ts → logger-3Co9eVJf.d.ts} +4 -1
  37. package/dist/nest.cjs +26 -4
  38. package/dist/nest.cjs.map +1 -1
  39. package/dist/nest.d.cts +2 -2
  40. package/dist/nest.d.ts +2 -2
  41. package/dist/nest.js +4 -4
  42. package/dist/next.cjs +43 -9
  43. package/dist/next.cjs.map +1 -1
  44. package/dist/next.d.cts +2 -2
  45. package/dist/next.d.ts +2 -2
  46. package/dist/next.js +3 -3
  47. package/dist/prisma.d.cts +1 -1
  48. package/dist/prisma.d.ts +1 -1
  49. package/dist/strapi.cjs +26 -9
  50. package/dist/strapi.cjs.map +1 -1
  51. package/dist/strapi.d.cts +2 -2
  52. package/dist/strapi.d.ts +2 -2
  53. package/dist/strapi.js +3 -7
  54. package/dist/strapi.js.map +1 -1
  55. package/package.json +1 -1
  56. package/dist/chunk-754Y5TQX.js.map +0 -1
  57. package/dist/chunk-AL4LJLUZ.js.map +0 -1
  58. package/dist/chunk-QMC6BWGK.js.map +0 -1
  59. /package/dist/{chunk-UXKPPF4G.js.map → chunk-2WNGXGP7.js.map} +0 -0
  60. /package/dist/{chunk-7DW57ECW.js.map → chunk-RVETZAK5.js.map} +0 -0
  61. /package/dist/{chunk-42ZPVKHN.js.map → chunk-UOIJCSP5.js.map} +0 -0
package/dist/index.cjs CHANGED
@@ -28,7 +28,9 @@ __export(src_exports, {
28
28
  createLogger: () => createLogger,
29
29
  getContext: () => getContext,
30
30
  installProcessHandlers: () => installProcessHandlers,
31
+ isClientDisconnect: () => isClientDisconnect,
31
32
  jobData: () => jobData,
33
+ knexLogging: () => knexLogging,
32
34
  logHttpRequest: () => logHttpRequest,
33
35
  logProcessWarnings: () => logProcessWarnings,
34
36
  logShutdown: () => logShutdown,
@@ -41,6 +43,7 @@ __export(src_exports, {
41
43
  resolveRequestId: () => resolveRequestId,
42
44
  runJob: () => runJob,
43
45
  serializeError: () => serializeError,
46
+ stripSql: () => stripSql,
44
47
  withContext: () => withContext
45
48
  });
46
49
  module.exports = __toCommonJS(src_exports);
@@ -135,8 +138,11 @@ var DEFAULT_REDACT_KEYS = [
135
138
  "bearer"
136
139
  ];
137
140
  var REDACT_PATTERNS = {
138
- /** Vietnamese mobile numbers: 0912345678, +84912345678, 84912345678. */
139
- phoneVN: /(?<![\d+])(?:\+?84|0)[35789]\d{8}(?!\d)/g,
141
+ /**
142
+ * Vietnamese mobile numbers: 0912345678, +84912345678, 84912345678. Letters on either side
143
+ * rule a match out, so hex ids (a UUID segment such as 0912345678e0) are left alone.
144
+ */
145
+ phoneVN: /(?<![\dA-Za-z+])(?:\+?84|0)[35789]\d{8}(?![\dA-Za-z])/g,
140
146
  /** Visa, Mastercard, Amex, Discover-like card numbers, with optional spaces or dashes. */
141
147
  paymentCard: /(?<!\d)(?:4\d{3}|5[1-5]\d{2}|2[2-7]\d{2}|3[47]\d{2}|6(?:011|5\d{2}))(?:[ -]?\d{4}){2}[ -]?\d{1,4}(?!\d)/g,
142
148
  /** IPv4 addresses. */
@@ -198,7 +204,7 @@ function isErrorLike(v) {
198
204
  return typeof v === "object" && v !== null && typeof v.message === "string" && ("stack" in v || "name" in v);
199
205
  }
200
206
  function errorType(e) {
201
- if (e.name && e.name !== "Error") return e.name;
207
+ if (e.name && e.name !== "Error" && e.name !== "error") return e.name;
202
208
  const ctor = e.constructor?.name;
203
209
  return ctor && ctor !== "Object" ? ctor : "Error";
204
210
  }
@@ -210,6 +216,11 @@ function serializeError(err) {
210
216
  const e = err;
211
217
  const out = { err_type: errorType(e), err_message: String(e.message ?? "") };
212
218
  if (e.code !== void 0 && e.code !== null) out.err_code = String(e.code);
219
+ if (isSqlState(out.err_code)) {
220
+ out.err_message = stripSql(out.err_message ?? "");
221
+ if (typeof e.table === "string" && e.table) out.db_table = e.table;
222
+ if (typeof e.constraint === "string" && e.constraint) out.db_constraint = e.constraint;
223
+ }
213
224
  if (typeof e.stack === "string") out.err_stack = e.stack;
214
225
  const causes = [];
215
226
  let cause = e.cause;
@@ -225,6 +236,20 @@ function serializeError(err) {
225
236
  if (causes.length > 0) out.err_cause = causes.join(" <- ");
226
237
  return out;
227
238
  }
239
+ function isSqlState(code) {
240
+ return code !== void 0 && /^[0-9A-Z]{5}$/.test(code);
241
+ }
242
+ var SQL_START_RE = /^\s*(?:select|insert|update|delete|with|create|alter|drop|truncate|lock)\b/i;
243
+ function stripSql(message) {
244
+ if (!SQL_START_RE.test(message)) return message;
245
+ const at = message.lastIndexOf(" - ");
246
+ return at === -1 ? message : message.slice(at + 3);
247
+ }
248
+ function isClientDisconnect(err) {
249
+ const e = err;
250
+ const code = typeof e?.code === "string" ? e.code : "";
251
+ return code === "ECONNRESET" || code === "ECONNABORTED" || code === "EPIPE" || code === "ERR_STREAM_PREMATURE_CLOSE" || code.startsWith("HPE_") || e?.message === "aborted";
252
+ }
228
253
  var logged = globalSingleton("logged", () => /* @__PURE__ */ new WeakSet());
229
254
  function markLogged(err) {
230
255
  if (typeof err === "object" && err !== null) logged.add(err);
@@ -317,8 +342,13 @@ function flattenInto(out, prefix, obj, depth, opts) {
317
342
  }
318
343
  }
319
344
  }
345
+ var ID_VALUE_RE = /^[A-Za-z0-9._:-]{1,128}$/;
346
+ function isIdKey(key) {
347
+ return key === "request_id" || key === "trace_id" || key === "span_id" || key.endsWith("_request_id");
348
+ }
320
349
  function finalize(key, value, opts) {
321
350
  if (typeof value !== "string") return value;
351
+ if (isIdKey(key) && ID_VALUE_RE.test(value)) return value;
322
352
  const v = opts.redactor.scrub(isUrlKey(key) ? stripUrl(value) : value);
323
353
  return truncate(v, key === "err_stack" ? MAX_STACK : MAX_STRING);
324
354
  }
@@ -434,6 +464,56 @@ function createLogger(options = {}) {
434
464
  return make({});
435
465
  }
436
466
 
467
+ // src/knex.ts
468
+ var MAX_PENDING = 1e4;
469
+ var TABLE_RE = /\b(?:from|into|update|join)\s+((?:"[^"]+"|`[^`]+`|[\w$]+)(?:\.(?:"[^"]+"|`[^`]+`|[\w$]+))?)/i;
470
+ function tableOf(sql) {
471
+ const match = sql ? TABLE_RE.exec(sql) : null;
472
+ if (!match?.[1]) return void 0;
473
+ const last = match[1].split(".").pop() ?? "";
474
+ return last.replace(/^["`]|["`]$/g, "") || void 0;
475
+ }
476
+ function operationOf(data) {
477
+ if (data.method && data.method !== "raw") return data.method;
478
+ return /^\s*(\w+)/.exec(data.sql ?? "")?.[1]?.toLowerCase();
479
+ }
480
+ function knexLogging(knex, log, opts = {}) {
481
+ const slowMs = opts.slowMs ?? 500;
482
+ const now = opts.now ?? (() => performance.now());
483
+ const started = /* @__PURE__ */ new Map();
484
+ const finish = (data) => {
485
+ const uid = data?.__knexQueryUid;
486
+ if (!uid) return void 0;
487
+ const start = started.get(uid);
488
+ started.delete(uid);
489
+ return start === void 0 ? void 0 : Math.round(now() - start);
490
+ };
491
+ const base = (data, duration) => ({
492
+ db_system: opts.db_system,
493
+ db_operation: operationOf(data),
494
+ db_table: tableOf(data.sql),
495
+ duration_ms: duration
496
+ });
497
+ knex.on("query", (data) => {
498
+ const uid = data?.__knexQueryUid;
499
+ if (!uid) return;
500
+ if (started.size >= MAX_PENDING) started.clear();
501
+ started.set(uid, now());
502
+ });
503
+ knex.on("query-response", (response, data) => {
504
+ const duration = finish(data);
505
+ if (duration === void 0 || duration < slowMs) return;
506
+ const rows = Array.isArray(response) ? response.length : void 0;
507
+ log.warn("slow query", { ...base(data, duration), event: "db.slow_query", db_rows: rows });
508
+ });
509
+ knex.on("query-error", (err, data) => {
510
+ const duration = finish(data);
511
+ if (!opts.logErrors) return;
512
+ if (err?.code === "25P02") return;
513
+ log.error("database error", { ...base(data ?? {}, duration), event: "db.error", err });
514
+ });
515
+ }
516
+
437
517
  // src/request-id.ts
438
518
  var REQUEST_ID_RE = /^[A-Za-z0-9._-]{1,64}$/;
439
519
  var TRACEPARENT_RE = /^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/;
@@ -491,12 +571,15 @@ function shouldSkip(method, path, skipPaths = DEFAULT_SKIP_PATHS) {
491
571
  }
492
572
  function logHttpRequest(log, info, opts = {}) {
493
573
  if (info.status < 500 && shouldSkip(info.method, info.path, opts.skipPaths)) return;
494
- const level = info.status >= 500 ? "error" : info.status >= 400 ? "warn" : "info";
574
+ const hasErr = info.err !== void 0 && info.err !== null;
575
+ const clientGone = hasErr && isClientDisconnect(info.err);
576
+ const level = info.status >= 500 && !clientGone ? "error" : info.status >= 400 ? "warn" : "info";
495
577
  const path = stripUrl(info.path);
496
578
  const errFields = {};
497
- if (info.err !== void 0 && info.err !== null) {
579
+ if (hasErr) {
498
580
  Object.assign(errFields, serializeError(info.err));
499
- if (info.status < 500) delete errFields.err_stack;
581
+ if (info.status < 500 || clientGone) delete errFields.err_stack;
582
+ if (clientGone) errFields.client_disconnect = true;
500
583
  markLogged(info.err);
501
584
  }
502
585
  const message = info.route ? `${info.method} ${info.route} ${info.status}` : `${info.method} ${info.status}`;
@@ -660,7 +743,7 @@ var warningState = globalSingleton("warnings", () => ({ installed: false }));
660
743
  function raiseStackTraceLimit(limit) {
661
744
  if (Error.stackTraceLimit < limit) Error.stackTraceLimit = limit;
662
745
  }
663
- var MAX_SEEN_WARNINGS = 200;
746
+ var MAX_TRACKED_WARNINGS = 200;
664
747
  function logProcessWarnings(log, opts = {}) {
665
748
  if (warningState.installed || typeof process === "undefined" || typeof process.on !== "function") return;
666
749
  warningState.installed = true;
@@ -668,12 +751,24 @@ function logProcessWarnings(log, opts = {}) {
668
751
  if (opts.replaceDefault ?? true) {
669
752
  for (const l of process.listeners("warning")) if (l.name === "onWarning") process.off("warning", l);
670
753
  }
671
- const seen = /* @__PURE__ */ new Set();
754
+ const windowMs = opts.repeatWindowMs ?? 60 * 60 * 1e3;
755
+ const now = opts.now ?? Date.now;
756
+ const tracked = /* @__PURE__ */ new Map();
672
757
  process.on("warning", (warning) => {
673
758
  const key = `${warning?.name}:${warning?.code ?? ""}:${warning?.message}`;
674
- if (seen.has(key)) return;
675
- if (seen.size < MAX_SEEN_WARNINGS) seen.add(key);
676
- log.warn("process warning", { event: "process.warning", err: warning });
759
+ const t = now();
760
+ const entry = tracked.get(key);
761
+ if (entry && t - entry.loggedAt < windowMs) {
762
+ entry.suppressed += 1;
763
+ return;
764
+ }
765
+ if (entry) tracked.set(key, { loggedAt: t, suppressed: 0 });
766
+ else if (tracked.size < MAX_TRACKED_WARNINGS) tracked.set(key, { loggedAt: t, suppressed: 0 });
767
+ log.warn("process warning", {
768
+ event: "process.warning",
769
+ suppressed_count: entry ? entry.suppressed : void 0,
770
+ err: warning
771
+ });
677
772
  });
678
773
  }
679
774
  // Annotate the CommonJS export names for ESM import in node:
@@ -686,7 +781,9 @@ function logProcessWarnings(log, opts = {}) {
686
781
  createLogger,
687
782
  getContext,
688
783
  installProcessHandlers,
784
+ isClientDisconnect,
689
785
  jobData,
786
+ knexLogging,
690
787
  logHttpRequest,
691
788
  logProcessWarnings,
692
789
  logShutdown,
@@ -699,6 +796,7 @@ function logProcessWarnings(log, opts = {}) {
699
796
  resolveRequestId,
700
797
  runJob,
701
798
  serializeError,
799
+ stripSql,
702
800
  withContext
703
801
  });
704
802
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/context.ts","../src/global.ts","../src/levels.ts","../src/redact.ts","../src/error.ts","../src/normalize.ts","../src/pretty.ts","../src/logger.ts","../src/request-id.ts","../src/http.ts","../src/fetch.ts","../src/job.ts","../src/console.ts","../src/process.ts"],"sourcesContent":["export { createLogger, type Logger, type LoggerOptions } from \"./logger\";\nexport { LEVELS, type Level } from \"./levels\";\nexport type { Fields, RedactHook } from \"./normalize\";\nexport { REDACT_PATTERNS, type KeyPattern } from \"./redact\";\nexport { serializeError } from \"./error\";\nexport { addContext, getContext, recordError, withContext } from \"./context\";\nexport {\n DEFAULT_SKIP_PATHS,\n logHttpRequest,\n parseTraceparent,\n propagationHeaders,\n requestContextFields,\n resolveRequestId,\n type HttpLogOptions,\n type HttpRequestInfo,\n} from \"./http\";\nexport { createFetch, type FetchLogOptions } from \"./fetch\";\nexport { jobData, runJob, type JobInfo } from \"./job\";\nexport { patchConsole, type PatchConsoleOptions } from \"./console\";\nexport { installProcessHandlers, logProcessWarnings, logShutdown, logStartup, type ProcessHandlerOptions } from \"./process\";\n","import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { globalSingleton } from \"./global\";\nimport type { Fields } from \"./normalize\";\n\nexport interface ContextStore {\n fields: Fields;\n error?: unknown;\n /** Route template captured while the router still knew it (Express error path). */\n route?: string;\n parent?: ContextStore;\n}\n\nconst als = globalSingleton(\"als\", () => new AsyncLocalStorage<ContextStore>());\n\nexport const STORE_KEY: symbol = Symbol.for(\"@tanngo11/log.store\");\n\nexport function runWithStore<T>(fields: Fields, fn: (store: ContextStore) => T): T {\n const parent = als.getStore();\n const store: ContextStore = { fields: { ...parent?.fields, ...fields }, parent };\n return als.run(store, () => fn(store));\n}\n\nexport function withContext<T>(fields: Fields, fn: () => T): T {\n return runWithStore(fields, () => fn());\n}\n\nexport function currentStore(): ContextStore | undefined {\n return als.getStore();\n}\n\nexport function getContext(): Fields {\n return als.getStore()?.fields ?? {};\n}\n\n// Applies to the current context and every enclosing one, so a field added inside a nested\n// withContext/runJob still reaches the request's http.request line.\nexport function addContext(fields: Fields): void {\n for (let s = als.getStore(); s; s = s.parent) Object.assign(s.fields, fields);\n}\n\n// Sets the error on the store and on enclosing stores that have none yet.\nexport function recordErrorIn(store: ContextStore, err: unknown): void {\n store.error = err;\n for (let s = store.parent; s; s = s.parent) if (s.error === undefined) s.error = err;\n}\n\n// Marks the error that the current request/job summary line should carry. Does not write a line.\nexport function recordError(err: unknown): void {\n const store = als.getStore();\n if (store) recordErrorIn(store, err);\n}\n\nexport function attachStore(target: object, store: ContextStore): void {\n (target as Record<symbol, ContextStore>)[STORE_KEY] = store;\n}\n\nexport function storeOf(target: unknown): ContextStore | undefined {\n if (typeof target !== \"object\" || target === null) return undefined;\n return (target as Record<symbol, ContextStore | undefined>)[STORE_KEY];\n}\n","// Singletons shared by every copy of this package loaded in the process (ESM and CJS builds,\n// or duplicated installs), so context and dedupe state never split.\nexport function globalSingleton<T>(name: string, make: () => T): T {\n const key = Symbol.for(`@tanngo11/log.${name}`);\n const g = globalThis as unknown as Record<symbol, T | undefined>;\n let value = g[key];\n if (value === undefined) {\n value = make();\n g[key] = value;\n }\n return value;\n}\n","export const LEVELS = [\"trace\", \"debug\", \"info\", \"warn\", \"error\", \"fatal\"] as const;\nexport type Level = (typeof LEVELS)[number];\n\nexport const LEVEL_RANK: Record<Level, number> = {\n trace: 10,\n debug: 20,\n info: 30,\n warn: 40,\n error: 50,\n fatal: 60,\n};\n\nconst ALIASES: Record<string, Level> = { warning: \"warn\", err: \"error\", critical: \"fatal\", panic: \"fatal\" };\n\nexport function parseLevel(value: unknown, fallback: Level = \"info\"): Level {\n if (typeof value !== \"string\") return fallback;\n const v = value.trim().toLowerCase();\n if ((LEVELS as readonly string[]).includes(v)) return v as Level;\n return ALIASES[v] ?? fallback;\n}\n","// Redaction shared by the logger and the error serializer. The collector redacts again,\n// but it cannot see secrets inside JSON-encoded strings, so the app side must catch them.\n\nexport const DEFAULT_REDACT_KEYS = [\n \"password\", \"passwd\", \"pwd\", \"passphrase\", \"secret\", \"client_secret\",\n \"token\", \"access_token\", \"refresh_token\", \"id_token\", \"auth_token\",\n \"api_key\", \"apikey\", \"access_key\", \"secret_key\", \"private_key\",\n \"authorization\", \"cookie\", \"set_cookie\", \"session_id\", \"sessionid\",\n \"credential\", \"credentials\", \"dsn\", \"connection_string\", \"conn_string\", \"jwt\", \"bearer\",\n];\n\n/** Opt-in value patterns for `redactValues`. Not on by default: they can hit ordinary numbers. */\nexport const REDACT_PATTERNS = {\n /** Vietnamese mobile numbers: 0912345678, +84912345678, 84912345678. */\n phoneVN: /(?<![\\d+])(?:\\+?84|0)[35789]\\d{8}(?!\\d)/g,\n /** Visa, Mastercard, Amex, Discover-like card numbers, with optional spaces or dashes. */\n paymentCard: /(?<!\\d)(?:4\\d{3}|5[1-5]\\d{2}|2[2-7]\\d{2}|3[47]\\d{2}|6(?:011|5\\d{2}))(?:[ -]?\\d{4}){2}[ -]?\\d{1,4}(?!\\d)/g,\n /** IPv4 addresses. */\n ipv4: /(?<![\\d.])(?:\\d{1,3}\\.){3}\\d{1,3}(?![\\d.])/g,\n} as const;\n\n// Keys that only describe a secret (count, type, timestamps, flags) stay readable.\nconst SAFE_SUFFIXES = [\"_count\", \"_type\", \"_length\", \"_expires_at\", \"_expires_in\", \"_ttl\", \"_at\", \"_ms\", \"_enabled\"];\n\nexport const REDACTED = \"[REDACTED]\";\n\nexport function toSnakeCase(key: string): string {\n return key\n .replace(/([a-z0-9])([A-Z])/g, \"$1_$2\")\n .replace(/([A-Z]+)([A-Z][a-z])/g, \"$1_$2\")\n .replace(/[^A-Za-z0-9_]+/g, \"_\")\n .toLowerCase();\n}\n\nconst URL_CREDENTIALS_RE = /([a-z][a-z0-9+.-]*:\\/\\/)[^\\s/@:\"']+:[^\\s/@\"']+@/gi;\nconst BEARER_RE = /\\bBearer\\s+[A-Za-z0-9._~+/=-]+/gi;\nconst JWT_RE = /\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+/g;\nconst EMAIL_RE = /[A-Za-z0-9._%+-]+@([A-Za-z0-9-]+(?:\\.[A-Za-z0-9-]+)*\\.[A-Za-z]{2,})/g;\n\nexport type KeyPattern = string | RegExp;\n\nexport interface RedactorOptions {\n /** Extra sensitive keys: names (matched like the defaults) or patterns tested on the snake_case key. */\n keys?: readonly KeyPattern[];\n /** Extra value patterns; every match inside any string becomes [REDACTED]. */\n values?: readonly RegExp[];\n}\n\nexport interface Redactor {\n isSensitive(key: string): boolean;\n /** Masks secrets and emails that appear inside free text. */\n scrub(s: string): string;\n /** JSON.stringify that redacts sensitive keys at any depth and never throws. */\n json(value: unknown): string;\n}\n\nfunction globalize(re: RegExp): RegExp {\n return re.flags.includes(\"g\") ? new RegExp(re.source, re.flags) : new RegExp(re.source, `${re.flags}g`);\n}\n\nexport function createRedactor(opts: RedactorOptions = {}): Redactor {\n const words = [...DEFAULT_REDACT_KEYS];\n const keyPatterns: RegExp[] = [];\n for (const k of opts.keys ?? []) {\n if (typeof k === \"string\") words.push(toSnakeCase(k));\n else keyPatterns.push(new RegExp(k.source, k.flags.replace(\"g\", \"\")));\n }\n const valuePatterns = (opts.values ?? []).map(globalize);\n\n const isSensitive = (key: string): boolean => {\n const k = toSnakeCase(key);\n if (keyPatterns.some((re) => re.test(k))) return true;\n if (!words.includes(k) && SAFE_SUFFIXES.some((s) => k.endsWith(s))) return false;\n return words.some((w) => k === w || k.startsWith(`${w}_`) || k.endsWith(`_${w}`) || k.includes(`_${w}_`));\n };\n\n const scrub = (s: string): string => {\n let out = s\n .replace(URL_CREDENTIALS_RE, `$1${REDACTED}@`)\n .replace(BEARER_RE, `Bearer ${REDACTED}`)\n .replace(JWT_RE, \"[REDACTED_JWT]\")\n .replace(EMAIL_RE, \"***@$1\");\n for (const re of valuePatterns) out = out.replace(re, REDACTED);\n return out;\n };\n\n const json = (value: unknown): string => {\n if (typeof value === \"string\") return value;\n try {\n const text = JSON.stringify(value, (key, val: unknown) => {\n if (key && val !== null && val !== undefined && isSensitive(key)) return REDACTED;\n if (typeof val === \"bigint\") return val.toString();\n if (val instanceof Error) return { name: val.name, message: val.message };\n return val;\n });\n return text ?? String(value);\n } catch {\n return String(value);\n }\n };\n\n return { isSensitive, scrub, json };\n}\n\nexport const defaultRedactor: Redactor = createRedactor();\n","import { globalSingleton } from \"./global\";\nimport { defaultRedactor } from \"./redact\";\n\nexport interface ErrFields {\n err_type?: string;\n err_message?: string;\n err_code?: string;\n err_stack?: string;\n err_cause?: string;\n}\n\nconst MAX_CAUSE_DEPTH = 5;\n\nexport function isErrorLike(v: unknown): v is Error {\n if (v instanceof Error) return true;\n return (\n typeof v === \"object\" &&\n v !== null &&\n typeof (v as { message?: unknown }).message === \"string\" &&\n (\"stack\" in v || \"name\" in v)\n );\n}\n\nfunction errorType(e: Error): string {\n if (e.name && e.name !== \"Error\") return e.name;\n const ctor = (e as { constructor?: { name?: string } }).constructor?.name;\n return ctor && ctor !== \"Object\" ? ctor : \"Error\";\n}\n\nexport function serializeError(err: unknown): ErrFields {\n if (!isErrorLike(err)) {\n if (typeof err === \"string\") return { err_type: \"string\", err_message: err };\n return { err_type: typeof err, err_message: defaultRedactor.json(err) };\n }\n const e = err as Error & { code?: unknown; cause?: unknown };\n const out: ErrFields = { err_type: errorType(e), err_message: String(e.message ?? \"\") };\n if (e.code !== undefined && e.code !== null) out.err_code = String(e.code);\n if (typeof e.stack === \"string\") out.err_stack = e.stack;\n\n const causes: string[] = [];\n let cause = e.cause;\n while (cause !== undefined && cause !== null && causes.length < MAX_CAUSE_DEPTH) {\n if (isErrorLike(cause)) {\n causes.push(`${errorType(cause)}: ${cause.message}`);\n cause = (cause as { cause?: unknown }).cause;\n } else {\n causes.push(defaultRedactor.json(cause));\n cause = undefined;\n }\n }\n if (causes.length > 0) out.err_cause = causes.join(\" <- \");\n return out;\n}\n\nconst logged = globalSingleton(\"logged\", () => new WeakSet<object>());\n\n// Marks an error as already written, so a later boundary (e.g. Next's onRequestError)\n// does not log it a second time.\nexport function markLogged(err: unknown): void {\n if (typeof err === \"object\" && err !== null) logged.add(err);\n}\n\nexport function isLogged(err: unknown): boolean {\n return typeof err === \"object\" && err !== null && logged.has(err);\n}\n","import { isErrorLike, serializeError } from \"./error\";\nimport type { Level } from \"./levels\";\nimport { REDACTED, toSnakeCase, type Redactor } from \"./redact\";\n\nexport { DEFAULT_REDACT_KEYS, toSnakeCase } from \"./redact\";\n\n/** Final per-field hook: return a replacement, or undefined to drop the field. */\nexport type RedactHook = (key: string, value: Primitive) => unknown;\n\nexport type Fields = Record<string, unknown>;\nexport type Primitive = string | number | boolean | null;\nexport type LogRecord = Record<string, Primitive>;\n\nexport interface NormalizeOptions {\n snakeCase: boolean;\n redactor: Redactor;\n hook?: RedactHook;\n}\n\n// Fields the redact hook never sees, so every line keeps its level, message and event.\nconst HOOK_EXEMPT = new Set([\"level\", \"message\", \"event\"]);\n\n// Keys owned by Vector (overwritten or deleted on ingest) or by the logger itself.\nexport const RESERVED_KEYS = new Set([\n \"project\", \"service\", \"vps\", \"version\", \"container_name\", \"container_id\", \"image\", \"stream\",\n \"_timestamp\", \"label\", \"host\", \"source_type\", \"msg\", \"lvl\", \"severity\", \"level\", \"message\",\n]);\n\nexport const MAX_LINE_BYTES = 16000;\nconst MAX_MESSAGE = 500;\nconst MAX_STACK = 4000;\nconst MAX_STRING = 1000;\nconst MAX_DEPTH = 3;\nconst TRUNCATED = \"…[truncated]\";\n\n// Fields kept when a line is too large.\nconst KEEP_ON_SHRINK = new Set([\n \"level\", \"message\", \"event\", \"request_id\", \"trace_id\", \"span_id\", \"job_name\", \"job_id\", \"job_attempt\",\n \"user_id\", \"tenant_id\", \"err_type\", \"err_message\", \"err_code\",\n]);\n\nexport function stripUrl(url: string): string {\n const noQuery = url.split(/[?#]/, 1)[0] ?? \"\";\n return noQuery.replace(/^([a-z][a-z0-9+.-]*:\\/\\/)[^/@\\s]*@/i, \"$1\");\n}\n\nexport function truncate(s: string, max: number): string {\n return s.length > max ? s.slice(0, max - TRUNCATED.length) + TRUNCATED : s;\n}\n\nfunction isPlainObject(v: unknown): v is Fields {\n if (typeof v !== \"object\" || v === null) return false;\n const proto = Object.getPrototypeOf(v);\n return proto === Object.prototype || proto === null;\n}\n\nfunction isUrlKey(key: string): boolean {\n return key === \"http_path\" || key === \"http_url\" || key.endsWith(\"_url\");\n}\n\nfunction flattenInto(out: LogRecord, prefix: string, obj: Fields, depth: number, opts: NormalizeOptions): void {\n for (const [rawKey, value] of Object.entries(obj)) {\n const key = opts.snakeCase ? toSnakeCase(rawKey) : rawKey;\n const full = prefix ? `${prefix}_${key}` : key;\n if (value === undefined || typeof value === \"function\" || typeof value === \"symbol\") continue;\n if (value !== null && (opts.redactor.isSensitive(rawKey) || opts.redactor.isSensitive(full))) {\n out[full] = REDACTED;\n continue;\n }\n if (value === null || typeof value === \"string\" || typeof value === \"boolean\") {\n out[full] = value;\n } else if (typeof value === \"number\") {\n out[full] = Number.isFinite(value) ? value : String(value);\n } else if (typeof value === \"bigint\") {\n out[full] = value.toString();\n } else if (value instanceof Date) {\n out[full] = Number.isNaN(value.getTime()) ? \"Invalid Date\" : value.toISOString();\n } else if (isErrorLike(value)) {\n out[full] = `${value.name}: ${value.message}`;\n } else if (isPlainObject(value) && depth < MAX_DEPTH - 1) {\n flattenInto(out, full, value, depth + 1, opts);\n } else {\n // Arrays, deep objects, class instances: stringified with sensitive keys redacted.\n out[full] = opts.redactor.json(value);\n }\n }\n}\n\nfunction finalize(key: string, value: Primitive, opts: NormalizeOptions): Primitive {\n if (typeof value !== \"string\") return value;\n const v = opts.redactor.scrub(isUrlKey(key) ? stripUrl(value) : value);\n return truncate(v, key === \"err_stack\" ? MAX_STACK : MAX_STRING);\n}\n\nexport function buildRecord(\n level: Level,\n message: unknown,\n sources: (Fields | undefined)[],\n opts: NormalizeOptions,\n): LogRecord {\n const merged: Fields = {};\n for (const source of sources) if (source) Object.assign(merged, source);\n\n let err: unknown;\n if (merged.err !== undefined && merged.err !== null) {\n err = merged.err;\n delete merged.err;\n } else if (isErrorLike(merged.error)) {\n err = merged.error;\n delete merged.error;\n }\n\n const flat: LogRecord = {};\n flattenInto(flat, \"\", merged, 0, opts);\n if (err !== undefined) Object.assign(flat, serializeError(err));\n\n const text = typeof message === \"string\" ? message : opts.redactor.json(message);\n const out: LogRecord = { level, message: truncate(opts.redactor.scrub(text), MAX_MESSAGE) };\n for (const [k, v] of Object.entries(flat)) {\n const key = RESERVED_KEYS.has(k) ? `app_${k}` : k;\n let value = finalize(key, v, opts);\n if (opts.hook && !HOOK_EXEMPT.has(key)) {\n const replaced = opts.hook(key, value);\n if (replaced === undefined) continue;\n value = typeof replaced === \"object\" && replaced !== null ? opts.redactor.json(replaced) : (replaced as Primitive);\n }\n out[key] = value;\n }\n return out;\n}\n\nfunction byteLength(s: string): number {\n // UTF-8 uses at most 3 bytes per UTF-16 code unit: skip encoding short lines.\n if (s.length * 3 <= MAX_LINE_BYTES) return s.length;\n return new TextEncoder().encode(s).length;\n}\n\nexport function serializeRecord(record: LogRecord): string {\n const line = JSON.stringify(record);\n if (byteLength(line) <= MAX_LINE_BYTES) return line;\n const small: LogRecord = {};\n for (const [k, v] of Object.entries(record)) {\n if (KEEP_ON_SHRINK.has(k) || k.startsWith(\"http_\")) small[k] = v;\n }\n small.log_truncated = true;\n return JSON.stringify(small);\n}\n","import type { LogRecord } from \"./normalize\";\n\n// Human-readable line for local development only (LOG_FORMAT=pretty).\nexport function formatPretty(record: LogRecord): string {\n const { level, message, err_stack, ...rest } = record;\n const time = new Date().toISOString().slice(11, 23);\n const extras = Object.entries(rest)\n .map(([k, v]) => `${k}=${typeof v === \"string\" && /\\s/.test(v) ? JSON.stringify(v) : String(v)}`)\n .join(\" \");\n let line = `${time} ${String(level).toUpperCase().padEnd(5)} ${String(message)}${extras ? ` ${extras}` : \"\"}`;\n if (typeof err_stack === \"string\") line += `\\n${err_stack}`;\n return line;\n}\n","import { getContext } from \"./context\";\nimport { LEVEL_RANK, parseLevel, type Level } from \"./levels\";\nimport {\n buildRecord,\n serializeRecord,\n type Fields,\n type NormalizeOptions,\n type RedactHook,\n} from \"./normalize\";\nimport { formatPretty } from \"./pretty\";\nimport { createRedactor, type KeyPattern } from \"./redact\";\n\ntype LogMethod = (message: string, fields?: Fields) => void;\n\nexport interface Logger {\n readonly level: Level;\n trace: LogMethod;\n debug: LogMethod;\n info: LogMethod;\n warn: LogMethod;\n error: LogMethod;\n fatal: LogMethod;\n child(fields: Fields): Logger;\n isLevelEnabled(level: Level): boolean;\n}\n\nexport interface LoggerOptions {\n level?: Level | string;\n format?: \"json\" | \"pretty\";\n base?: Fields;\n /** Extra sensitive keys: names (matched like the defaults) or RegExp tested on the snake_case key. */\n redactKeys?: KeyPattern[];\n /** Extra value patterns masked in every string, e.g. REDACT_PATTERNS.phoneVN. */\n redactValues?: RegExp[];\n /** Final per-field hook: return a replacement, or undefined to drop the field. */\n redact?: RedactHook;\n snakeCase?: boolean;\n write?: (line: string) => void;\n}\n\nfunction env(name: string): string | undefined {\n return typeof process !== \"undefined\" ? process.env?.[name] : undefined;\n}\n\n// Captured before patchConsole can replace it, so the fallback never loops into the logger.\nconst consoleLog = console.log.bind(console);\n\nfunction defaultWrite(line: string): void {\n if (typeof process !== \"undefined\" && typeof process.stdout?.write === \"function\") {\n process.stdout.write(`${line}\\n`);\n } else {\n consoleLog(line);\n }\n}\n\nexport function createLogger(options: LoggerOptions = {}): Logger {\n const level = parseLevel(options.level ?? env(\"LOG_LEVEL\"));\n const format = options.format ?? (env(\"LOG_FORMAT\") === \"pretty\" ? \"pretty\" : \"json\");\n const write = options.write ?? defaultWrite;\n const norm: NormalizeOptions = {\n snakeCase: options.snakeCase ?? true,\n redactor: createRedactor({ keys: options.redactKeys, values: options.redactValues }),\n hook: options.redact,\n };\n\n const make = (bound: Fields): Logger => {\n const emit = (lvl: Level, message: string, fields?: Fields) => {\n if (LEVEL_RANK[lvl] < LEVEL_RANK[level]) return;\n let line: string;\n try {\n const record = buildRecord(lvl, message, [options.base, getContext(), bound, fields], norm);\n line = format === \"pretty\" ? formatPretty(record) : serializeRecord(record);\n } catch (e) {\n line = JSON.stringify({\n level: \"error\",\n message: \"log serialize failed\",\n event: \"log.serialize_failed\",\n err_message: String((e as Error)?.message ?? e).slice(0, 1000),\n original_message: String(message).slice(0, 500),\n });\n }\n try {\n write(line);\n } catch {\n // Logging must never break the app.\n }\n };\n return {\n level,\n trace: (m, f) => emit(\"trace\", m, f),\n debug: (m, f) => emit(\"debug\", m, f),\n info: (m, f) => emit(\"info\", m, f),\n warn: (m, f) => emit(\"warn\", m, f),\n error: (m, f) => emit(\"error\", m, f),\n fatal: (m, f) => emit(\"fatal\", m, f),\n child: (fields) => make({ ...bound, ...fields }),\n isLevelEnabled: (l) => LEVEL_RANK[l] >= LEVEL_RANK[level],\n };\n };\n return make({});\n}\n","// No imports: this module is shared with the edge entry (next-edge).\nexport const REQUEST_ID_RE = /^[A-Za-z0-9._-]{1,64}$/;\nconst TRACEPARENT_RE = /^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/;\n\nexport function newRequestId(): string {\n return globalThis.crypto.randomUUID();\n}\n\nfunction first(header?: string | string[] | null): string | undefined {\n return Array.isArray(header) ? header[0] : (header ?? undefined);\n}\n\nexport function resolveRequestId(header?: string | string[] | null): string {\n const value = first(header);\n return value && REQUEST_ID_RE.test(value) ? value : newRequestId();\n}\n\nexport function parseTraceparent(header?: string | string[] | null): { trace_id: string; span_id: string } | undefined {\n const value = first(header)?.trim().toLowerCase();\n const m = value ? TRACEPARENT_RE.exec(value) : null;\n if (!m) return undefined;\n const [, version, traceId, spanId] = m as unknown as [string, string, string, string];\n if (version === \"ff\" || /^0+$/.test(traceId) || /^0+$/.test(spanId)) return undefined;\n return { trace_id: traceId, span_id: spanId };\n}\n","import { getContext } from \"./context\";\nimport { markLogged, serializeError } from \"./error\";\nimport type { Logger } from \"./logger\";\nimport { stripUrl, type Fields } from \"./normalize\";\nimport { parseTraceparent, resolveRequestId } from \"./request-id\";\n\nexport { newRequestId, parseTraceparent, REQUEST_ID_RE, resolveRequestId } from \"./request-id\";\n\nexport type HeaderSource = Headers | Record<string, string | string[] | undefined>;\n\nfunction header(headers: HeaderSource, name: string): string | string[] | undefined {\n if (typeof (headers as Headers).get === \"function\") return (headers as Headers).get(name) ?? undefined;\n return (headers as Record<string, string | string[] | undefined>)[name];\n}\n\nexport function requestContextFields(headers: HeaderSource): { request_id: string; trace_id?: string; span_id?: string } {\n const out: { request_id: string; trace_id?: string; span_id?: string } = {\n request_id: resolveRequestId(header(headers, \"x-request-id\")),\n };\n const tp = parseTraceparent(header(headers, \"traceparent\"));\n if (tp) Object.assign(out, tp);\n return out;\n}\n\n// Headers to forward to services we own, so their logs share request_id / trace_id.\nexport function propagationHeaders(): Record<string, string> {\n const ctx = getContext();\n const out: Record<string, string> = {};\n if (typeof ctx.request_id === \"string\") out[\"x-request-id\"] = ctx.request_id;\n if (typeof ctx.trace_id === \"string\" && typeof ctx.span_id === \"string\") {\n out.traceparent = `00-${ctx.trace_id}-${ctx.span_id}-01`;\n }\n return out;\n}\n\nexport const DEFAULT_SKIP_PATHS: (string | RegExp)[] = [\n // Also under a prefix such as /api/v1/health.\n /(^|\\/)(health|healthz|ready|readyz|livez)\\/?$/,\n \"/favicon.ico\",\n /^\\/_next\\/static\\//,\n];\n\nexport interface HttpLogOptions {\n skipPaths?: (string | RegExp)[];\n}\n\nexport interface HttpRequestInfo {\n method: string;\n route?: string;\n path: string;\n status: number;\n duration_ms?: number;\n err?: unknown;\n fields?: Fields;\n}\n\nexport function shouldSkip(method: string, path: string, skipPaths: (string | RegExp)[] = DEFAULT_SKIP_PATHS): boolean {\n if (method.toUpperCase() === \"OPTIONS\") return true;\n const p = stripUrl(path);\n return skipPaths.some((s) => (typeof s === \"string\" ? p === s : s.test(p)));\n}\n\n// Writes the one `http.request` summary line for an inbound request. Skipped paths are still\n// logged when they fail with a 5xx, so a failing health check stays visible.\nexport function logHttpRequest(log: Logger, info: HttpRequestInfo, opts: HttpLogOptions = {}): void {\n if (info.status < 500 && shouldSkip(info.method, info.path, opts.skipPaths)) return;\n const level = info.status >= 500 ? \"error\" : info.status >= 400 ? \"warn\" : \"info\";\n const path = stripUrl(info.path);\n const errFields: Fields = {};\n if (info.err !== undefined && info.err !== null) {\n Object.assign(errFields, serializeError(info.err));\n if (info.status < 500) delete errFields.err_stack;\n markLogged(info.err);\n }\n // Route templates keep the message bounded; the raw path would make one message per URL.\n const message = info.route ? `${info.method} ${info.route} ${info.status}` : `${info.method} ${info.status}`;\n log[level](message, {\n ...info.fields,\n event: \"http.request\",\n http_method: info.method,\n http_route: info.route,\n http_path: path,\n http_status: info.status,\n duration_ms: info.duration_ms === undefined ? undefined : Math.round(info.duration_ms),\n ...errFields,\n });\n}\n","import { propagationHeaders } from \"./http\";\nimport type { Logger } from \"./logger\";\n\nexport interface FetchLogOptions {\n peer_service: string;\n /** Forward x-request-id / traceparent. Only for services we own. */\n internal?: boolean;\n slowMs?: number;\n fetch?: typeof fetch;\n}\n\nfunction describeRequest(input: RequestInfo | URL, init?: RequestInit): { method: string; url: string } {\n const method = (init?.method ?? (input instanceof Request ? input.method : \"GET\")).toUpperCase();\n const url = typeof input === \"string\" ? input : input instanceof URL ? input.href : input.url;\n return { method, url };\n}\n\nexport function createFetch(log: Logger, opts: FetchLogOptions): typeof fetch {\n const slowMs = opts.slowMs ?? 1000;\n const wrapped = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const base = opts.fetch ?? globalThis.fetch;\n const { method, url } = describeRequest(input, init);\n let requestInit = init;\n if (opts.internal) {\n const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : undefined));\n for (const [k, v] of Object.entries(propagationHeaders())) if (!headers.has(k)) headers.set(k, v);\n requestInit = { ...init, headers };\n }\n const fields = { event: \"http.outbound\", peer_service: opts.peer_service, http_method: method, http_url: url };\n const start = performance.now();\n try {\n const res = await base(input, requestInit);\n const duration_ms = Math.round(performance.now() - start);\n if (res.status >= 500) {\n log.warn(\"outbound request failed\", { ...fields, http_status: res.status, duration_ms });\n } else if (duration_ms >= slowMs) {\n log.warn(\"outbound request slow\", { ...fields, http_status: res.status, duration_ms });\n }\n return res;\n } catch (err) {\n log.warn(\"outbound request failed\", { ...fields, duration_ms: Math.round(performance.now() - start), err });\n throw err;\n }\n };\n return wrapped as typeof fetch;\n}\n","import { getContext, withContext } from \"./context\";\nimport { markLogged } from \"./error\";\nimport type { Logger } from \"./logger\";\nimport type { Fields } from \"./normalize\";\n\nexport interface JobInfo {\n job_name: string;\n job_id?: string | number;\n job_attempt?: number;\n /** No retries left after this attempt (or decided per error). Defaults to true when unknown. */\n final_attempt?: boolean | ((err: unknown) => boolean);\n request_id?: string;\n fields?: Fields;\n}\n\nexport async function runJob<T>(log: Logger, info: JobInfo, fn: () => T | Promise<T>): Promise<T> {\n const ctx: Fields = { ...info.fields, job_name: info.job_name };\n if (info.job_id !== undefined) ctx.job_id = String(info.job_id);\n if (info.job_attempt !== undefined) ctx.job_attempt = info.job_attempt;\n if (info.request_id !== undefined) ctx.request_id = info.request_id;\n\n return withContext(ctx, async () => {\n const start = performance.now();\n try {\n const result = await fn();\n log.info(\"job completed\", { event: \"job.completed\", duration_ms: Math.round(performance.now() - start) });\n return result;\n } catch (err) {\n const final = typeof info.final_attempt === \"function\" ? info.final_attempt(err) : (info.final_attempt ?? true);\n log[final ? \"error\" : \"warn\"](\"job failed\", {\n event: \"job.failed\",\n duration_ms: Math.round(performance.now() - start),\n err,\n });\n markLogged(err);\n throw err;\n }\n });\n}\n\n/** Adds the current request_id to a job payload, so the job's logs link back to the request. */\nexport function jobData<T extends Record<string, unknown>>(data: T): T & { request_id?: string } {\n const requestId = getContext().request_id;\n if (typeof requestId !== \"string\" || data.request_id !== undefined) return data;\n return { ...data, request_id: requestId };\n}\n","import { isErrorLike, isLogged } from \"./error\";\nimport type { Level } from \"./levels\";\nimport type { Logger } from \"./logger\";\nimport { defaultRedactor } from \"./redact\";\n\nconst METHODS = { log: \"info\", info: \"info\", warn: \"warn\", error: \"error\", debug: \"debug\", trace: \"debug\" } as const;\ntype Method = keyof typeof METHODS;\ntype ConsoleFn = (...args: unknown[]) => void;\n\nexport interface PatchConsoleOptions {\n /** Return true to drop a console call, e.g. errors a framework hook will log anyway. */\n skip?: (args: unknown[]) => boolean;\n}\n\n/**\n * Routes console.log/info/warn/error/debug/trace through the logger, so legacy console calls\n * and framework output (e.g. Next.js errors) become JSON lines with request context.\n * Calls carrying an error that is already on a summary line are dropped.\n * Returns a function that restores the previous console methods.\n */\nexport function patchConsole(log: Logger, opts: PatchConsoleOptions = {}): () => void {\n const target = console as unknown as Record<Method, ConsoleFn>;\n const saved = {} as Record<Method, ConsoleFn>;\n let inside = false;\n\n for (const method of Object.keys(METHODS) as Method[]) {\n const previous = target[method];\n saved[method] = previous;\n const level: Level = METHODS[method];\n target[method] = (...args: unknown[]) => {\n // A write path that itself uses console must not loop back into the logger.\n if (inside) return previous.apply(console, args);\n inside = true;\n try {\n if (args.some((arg) => isErrorLike(arg) && isLogged(arg)) || opts.skip?.(args)) return;\n let err: unknown;\n const parts: string[] = [];\n for (const arg of args) {\n if (isErrorLike(arg)) {\n err ??= arg;\n parts.push(arg.message);\n } else {\n parts.push(typeof arg === \"string\" ? arg : defaultRedactor.json(arg));\n }\n }\n log[level](parts.join(\" \"), { event: \"console\", console_method: method, err });\n } finally {\n inside = false;\n }\n };\n }\n\n return () => {\n for (const method of Object.keys(saved) as Method[]) target[method] = saved[method];\n };\n}\n","import { globalSingleton } from \"./global\";\nimport type { Logger } from \"./logger\";\nimport type { Fields } from \"./normalize\";\n\nexport function logStartup(log: Logger, fields: Fields = {}): void {\n log.info(\"app started\", {\n event: \"app.started\",\n runtime_version: `node ${process.versions.node}`,\n log_level: log.level,\n ...fields,\n });\n}\n\n/** Call at the start of your own shutdown handler (e.g. on SIGTERM). The library never handles signals. */\nexport function logShutdown(log: Logger, fields: Fields = {}): void {\n log.info(\"app stopping\", { event: \"app.stopping\", ...fields });\n}\n\nexport interface ProcessHandlerOptions {\n /** Exit with code 1 after an uncaught error. Next.js keeps serving, so its adapter passes false. */\n exitOnCrash?: boolean;\n /** Time other crash handlers (Sentry, APM) get to flush before exit. Default 1000 ms. */\n exitDelayMs?: number;\n exit?: (code: number) => void;\n}\n\nexport function crashHandlers(log: Logger, opts: ProcessHandlerOptions = {}) {\n const exitOnCrash = opts.exitOnCrash ?? true;\n const exitDelayMs = opts.exitDelayMs ?? 1000;\n const exit = opts.exit ?? ((code: number) => process.exit(code));\n let exiting = false;\n const crash = (source: string, err: unknown) => {\n if (!exitOnCrash) {\n log.error(\"unhandled error\", { event: \"app.unhandled_error\", crash_source: source, err });\n return;\n }\n log.fatal(\"app crashed\", { event: \"app.crashed\", crash_source: source, err });\n if (exiting) return;\n exiting = true;\n if (typeof process !== \"undefined\") process.exitCode = 1;\n // Deferred so listeners registered after ours still run; unref so a process with nothing\n // left to do exits on its own (with exitCode 1) without waiting.\n const timer = setTimeout(() => exit(1), exitDelayMs);\n (timer as { unref?: () => void }).unref?.();\n };\n return {\n onUncaught: (err: unknown) => crash(\"uncaughtException\", err),\n onRejection: (reason: unknown) => crash(\"unhandledRejection\", reason),\n };\n}\n\nconst state = globalSingleton(\"process\", () => ({ installed: false }));\n\n/** Logs uncaught exceptions and unhandled rejections. Does not touch SIGTERM/SIGINT. */\nexport function installProcessHandlers(log: Logger, opts: ProcessHandlerOptions = {}): void {\n if (state.installed || typeof process === \"undefined\" || typeof process.on !== \"function\") return;\n state.installed = true;\n const h = crashHandlers(log, opts);\n process.on(\"uncaughtException\", h.onUncaught);\n process.on(\"unhandledRejection\", h.onRejection);\n}\n\nconst warningState = globalSingleton(\"warnings\", () => ({ installed: false }));\n\n/**\n * Node keeps 10 frames by default; ORM/framework frames (knex, Strapi, Prisma) often use all of\n * them, hiding the app code that triggered a warning or error. Only ever raises the limit.\n */\nexport function raiseStackTraceLimit(limit: number): void {\n if (Error.stackTraceLimit < limit) Error.stackTraceLimit = limit;\n}\n\nexport interface ProcessWarningOptions {\n stackTraceLimit?: number;\n /**\n * Remove Node's own stderr printer, so a warning is one JSON line instead of that line plus\n * \"(node:1) Warning: ...\" and \"(Use `node --trace-deprecation ...`...)\". Default true.\n */\n replaceDefault?: boolean;\n}\n\n// Some libraries (pg) emit the same warning on every occurrence; one line per process is enough.\nconst MAX_SEEN_WARNINGS = 200;\n\n/**\n * Logs Node process warnings (deprecations, MaxListeners...) as `process.warning` lines whose\n * err_stack points at the code that triggered them. Each distinct warning is logged once.\n * Also raises Error.stackTraceLimit (default 30) so the stack reaches past framework frames.\n */\nexport function logProcessWarnings(log: Logger, opts: ProcessWarningOptions = {}): void {\n if (warningState.installed || typeof process === \"undefined\" || typeof process.on !== \"function\") return;\n warningState.installed = true;\n raiseStackTraceLimit(opts.stackTraceLimit ?? 30);\n if (opts.replaceDefault ?? true) {\n for (const l of process.listeners(\"warning\")) if (l.name === \"onWarning\") process.off(\"warning\", l);\n }\n const seen = new Set<string>();\n process.on(\"warning\", (warning: Error) => {\n const key = `${warning?.name}:${(warning as { code?: unknown })?.code ?? \"\"}:${warning?.message}`;\n if (seen.has(key)) return;\n if (seen.size < MAX_SEEN_WARNINGS) seen.add(key);\n log.warn(\"process warning\", { event: \"process.warning\", err: warning });\n });\n}\n"],"mappings":"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","names":["header"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/context.ts","../src/global.ts","../src/levels.ts","../src/redact.ts","../src/error.ts","../src/normalize.ts","../src/pretty.ts","../src/logger.ts","../src/knex.ts","../src/request-id.ts","../src/http.ts","../src/fetch.ts","../src/job.ts","../src/console.ts","../src/process.ts"],"sourcesContent":["export { createLogger, type Logger, type LoggerOptions } from \"./logger\";\nexport { LEVELS, type Level } from \"./levels\";\nexport type { Fields, RedactHook } from \"./normalize\";\nexport { REDACT_PATTERNS, type KeyPattern } from \"./redact\";\nexport { isClientDisconnect, serializeError, stripSql } from \"./error\";\nexport { knexLogging, type KnexLike, type KnexLogOptions } from \"./knex\";\nexport { addContext, getContext, recordError, withContext } from \"./context\";\nexport {\n DEFAULT_SKIP_PATHS,\n logHttpRequest,\n parseTraceparent,\n propagationHeaders,\n requestContextFields,\n resolveRequestId,\n type HttpLogOptions,\n type HttpRequestInfo,\n} from \"./http\";\nexport { createFetch, type FetchLogOptions } from \"./fetch\";\nexport { jobData, runJob, type JobInfo } from \"./job\";\nexport { patchConsole, type PatchConsoleOptions } from \"./console\";\nexport { installProcessHandlers, logProcessWarnings, logShutdown, logStartup, type ProcessHandlerOptions } from \"./process\";\n","import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { globalSingleton } from \"./global\";\nimport type { Fields } from \"./normalize\";\n\nexport interface ContextStore {\n fields: Fields;\n error?: unknown;\n /** Route template captured while the router still knew it (Express error path). */\n route?: string;\n parent?: ContextStore;\n}\n\nconst als = globalSingleton(\"als\", () => new AsyncLocalStorage<ContextStore>());\n\nexport const STORE_KEY: symbol = Symbol.for(\"@tanngo11/log.store\");\n\nexport function runWithStore<T>(fields: Fields, fn: (store: ContextStore) => T): T {\n const parent = als.getStore();\n const store: ContextStore = { fields: { ...parent?.fields, ...fields }, parent };\n return als.run(store, () => fn(store));\n}\n\nexport function withContext<T>(fields: Fields, fn: () => T): T {\n return runWithStore(fields, () => fn());\n}\n\nexport function currentStore(): ContextStore | undefined {\n return als.getStore();\n}\n\nexport function getContext(): Fields {\n return als.getStore()?.fields ?? {};\n}\n\n// Applies to the current context and every enclosing one, so a field added inside a nested\n// withContext/runJob still reaches the request's http.request line.\nexport function addContext(fields: Fields): void {\n for (let s = als.getStore(); s; s = s.parent) Object.assign(s.fields, fields);\n}\n\n// Sets the error on the store and on enclosing stores that have none yet.\nexport function recordErrorIn(store: ContextStore, err: unknown): void {\n store.error = err;\n for (let s = store.parent; s; s = s.parent) if (s.error === undefined) s.error = err;\n}\n\n// Marks the error that the current request/job summary line should carry. Does not write a line.\nexport function recordError(err: unknown): void {\n const store = als.getStore();\n if (store) recordErrorIn(store, err);\n}\n\nexport function attachStore(target: object, store: ContextStore): void {\n (target as Record<symbol, ContextStore>)[STORE_KEY] = store;\n}\n\nexport function storeOf(target: unknown): ContextStore | undefined {\n if (typeof target !== \"object\" || target === null) return undefined;\n return (target as Record<symbol, ContextStore | undefined>)[STORE_KEY];\n}\n","// Singletons shared by every copy of this package loaded in the process (ESM and CJS builds,\n// or duplicated installs), so context and dedupe state never split.\nexport function globalSingleton<T>(name: string, make: () => T): T {\n const key = Symbol.for(`@tanngo11/log.${name}`);\n const g = globalThis as unknown as Record<symbol, T | undefined>;\n let value = g[key];\n if (value === undefined) {\n value = make();\n g[key] = value;\n }\n return value;\n}\n","export const LEVELS = [\"trace\", \"debug\", \"info\", \"warn\", \"error\", \"fatal\"] as const;\nexport type Level = (typeof LEVELS)[number];\n\nexport const LEVEL_RANK: Record<Level, number> = {\n trace: 10,\n debug: 20,\n info: 30,\n warn: 40,\n error: 50,\n fatal: 60,\n};\n\nconst ALIASES: Record<string, Level> = { warning: \"warn\", err: \"error\", critical: \"fatal\", panic: \"fatal\" };\n\nexport function parseLevel(value: unknown, fallback: Level = \"info\"): Level {\n if (typeof value !== \"string\") return fallback;\n const v = value.trim().toLowerCase();\n if ((LEVELS as readonly string[]).includes(v)) return v as Level;\n return ALIASES[v] ?? fallback;\n}\n","// Redaction shared by the logger and the error serializer. The collector redacts again,\n// but it cannot see secrets inside JSON-encoded strings, so the app side must catch them.\n\nexport const DEFAULT_REDACT_KEYS = [\n \"password\", \"passwd\", \"pwd\", \"passphrase\", \"secret\", \"client_secret\",\n \"token\", \"access_token\", \"refresh_token\", \"id_token\", \"auth_token\",\n \"api_key\", \"apikey\", \"access_key\", \"secret_key\", \"private_key\",\n \"authorization\", \"cookie\", \"set_cookie\", \"session_id\", \"sessionid\",\n \"credential\", \"credentials\", \"dsn\", \"connection_string\", \"conn_string\", \"jwt\", \"bearer\",\n];\n\n/** Opt-in value patterns for `redactValues`. Not on by default: they can hit ordinary numbers. */\nexport const REDACT_PATTERNS = {\n /**\n * Vietnamese mobile numbers: 0912345678, +84912345678, 84912345678. Letters on either side\n * rule a match out, so hex ids (a UUID segment such as 0912345678e0) are left alone.\n */\n phoneVN: /(?<![\\dA-Za-z+])(?:\\+?84|0)[35789]\\d{8}(?![\\dA-Za-z])/g,\n /** Visa, Mastercard, Amex, Discover-like card numbers, with optional spaces or dashes. */\n paymentCard: /(?<!\\d)(?:4\\d{3}|5[1-5]\\d{2}|2[2-7]\\d{2}|3[47]\\d{2}|6(?:011|5\\d{2}))(?:[ -]?\\d{4}){2}[ -]?\\d{1,4}(?!\\d)/g,\n /** IPv4 addresses. */\n ipv4: /(?<![\\d.])(?:\\d{1,3}\\.){3}\\d{1,3}(?![\\d.])/g,\n} as const;\n\n// Keys that only describe a secret (count, type, timestamps, flags) stay readable.\nconst SAFE_SUFFIXES = [\"_count\", \"_type\", \"_length\", \"_expires_at\", \"_expires_in\", \"_ttl\", \"_at\", \"_ms\", \"_enabled\"];\n\nexport const REDACTED = \"[REDACTED]\";\n\nexport function toSnakeCase(key: string): string {\n return key\n .replace(/([a-z0-9])([A-Z])/g, \"$1_$2\")\n .replace(/([A-Z]+)([A-Z][a-z])/g, \"$1_$2\")\n .replace(/[^A-Za-z0-9_]+/g, \"_\")\n .toLowerCase();\n}\n\nconst URL_CREDENTIALS_RE = /([a-z][a-z0-9+.-]*:\\/\\/)[^\\s/@:\"']+:[^\\s/@\"']+@/gi;\nconst BEARER_RE = /\\bBearer\\s+[A-Za-z0-9._~+/=-]+/gi;\nconst JWT_RE = /\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+/g;\nconst EMAIL_RE = /[A-Za-z0-9._%+-]+@([A-Za-z0-9-]+(?:\\.[A-Za-z0-9-]+)*\\.[A-Za-z]{2,})/g;\n\nexport type KeyPattern = string | RegExp;\n\nexport interface RedactorOptions {\n /** Extra sensitive keys: names (matched like the defaults) or patterns tested on the snake_case key. */\n keys?: readonly KeyPattern[];\n /** Extra value patterns; every match inside any string becomes [REDACTED]. */\n values?: readonly RegExp[];\n}\n\nexport interface Redactor {\n isSensitive(key: string): boolean;\n /** Masks secrets and emails that appear inside free text. */\n scrub(s: string): string;\n /** JSON.stringify that redacts sensitive keys at any depth and never throws. */\n json(value: unknown): string;\n}\n\nfunction globalize(re: RegExp): RegExp {\n return re.flags.includes(\"g\") ? new RegExp(re.source, re.flags) : new RegExp(re.source, `${re.flags}g`);\n}\n\nexport function createRedactor(opts: RedactorOptions = {}): Redactor {\n const words = [...DEFAULT_REDACT_KEYS];\n const keyPatterns: RegExp[] = [];\n for (const k of opts.keys ?? []) {\n if (typeof k === \"string\") words.push(toSnakeCase(k));\n else keyPatterns.push(new RegExp(k.source, k.flags.replace(\"g\", \"\")));\n }\n const valuePatterns = (opts.values ?? []).map(globalize);\n\n const isSensitive = (key: string): boolean => {\n const k = toSnakeCase(key);\n if (keyPatterns.some((re) => re.test(k))) return true;\n if (!words.includes(k) && SAFE_SUFFIXES.some((s) => k.endsWith(s))) return false;\n return words.some((w) => k === w || k.startsWith(`${w}_`) || k.endsWith(`_${w}`) || k.includes(`_${w}_`));\n };\n\n const scrub = (s: string): string => {\n let out = s\n .replace(URL_CREDENTIALS_RE, `$1${REDACTED}@`)\n .replace(BEARER_RE, `Bearer ${REDACTED}`)\n .replace(JWT_RE, \"[REDACTED_JWT]\")\n .replace(EMAIL_RE, \"***@$1\");\n for (const re of valuePatterns) out = out.replace(re, REDACTED);\n return out;\n };\n\n const json = (value: unknown): string => {\n if (typeof value === \"string\") return value;\n try {\n const text = JSON.stringify(value, (key, val: unknown) => {\n if (key && val !== null && val !== undefined && isSensitive(key)) return REDACTED;\n if (typeof val === \"bigint\") return val.toString();\n if (val instanceof Error) return { name: val.name, message: val.message };\n return val;\n });\n return text ?? String(value);\n } catch {\n return String(value);\n }\n };\n\n return { isSensitive, scrub, json };\n}\n\nexport const defaultRedactor: Redactor = createRedactor();\n","import { globalSingleton } from \"./global\";\nimport { defaultRedactor } from \"./redact\";\n\nexport interface ErrFields {\n err_type?: string;\n err_message?: string;\n err_code?: string;\n err_stack?: string;\n err_cause?: string;\n /** Database errors (pg): the table and constraint the server reported. */\n db_table?: string;\n db_constraint?: string;\n}\n\nconst MAX_CAUSE_DEPTH = 5;\n\nexport function isErrorLike(v: unknown): v is Error {\n if (v instanceof Error) return true;\n return (\n typeof v === \"object\" &&\n v !== null &&\n typeof (v as { message?: unknown }).message === \"string\" &&\n (\"stack\" in v || \"name\" in v)\n );\n}\n\nfunction errorType(e: Error): string {\n // pg's DatabaseError keeps the lowercase name \"error\"; its class name says more.\n if (e.name && e.name !== \"Error\" && e.name !== \"error\") return e.name;\n const ctor = (e as { constructor?: { name?: string } }).constructor?.name;\n return ctor && ctor !== \"Object\" ? ctor : \"Error\";\n}\n\nexport function serializeError(err: unknown): ErrFields {\n if (!isErrorLike(err)) {\n if (typeof err === \"string\") return { err_type: \"string\", err_message: err };\n return { err_type: typeof err, err_message: defaultRedactor.json(err) };\n }\n const e = err as Error & { code?: unknown; cause?: unknown; table?: unknown; constraint?: unknown };\n const out: ErrFields = { err_type: errorType(e), err_message: String(e.message ?? \"\") };\n if (e.code !== undefined && e.code !== null) out.err_code = String(e.code);\n if (isSqlState(out.err_code)) {\n out.err_message = stripSql(out.err_message ?? \"\");\n if (typeof e.table === \"string\" && e.table) out.db_table = e.table;\n if (typeof e.constraint === \"string\" && e.constraint) out.db_constraint = e.constraint;\n }\n if (typeof e.stack === \"string\") out.err_stack = e.stack;\n\n const causes: string[] = [];\n let cause = e.cause;\n while (cause !== undefined && cause !== null && causes.length < MAX_CAUSE_DEPTH) {\n if (isErrorLike(cause)) {\n causes.push(`${errorType(cause)}: ${cause.message}`);\n cause = (cause as { cause?: unknown }).cause;\n } else {\n causes.push(defaultRedactor.json(cause));\n cause = undefined;\n }\n }\n if (causes.length > 0) out.err_cause = causes.join(\" <- \");\n return out;\n}\n\n// Postgres SQLSTATE codes: five digits or uppercase letters (23505, 40P01, 25P02).\nfunction isSqlState(code: string | undefined): boolean {\n return code !== undefined && /^[0-9A-Z]{5}$/.test(code);\n}\n\nconst SQL_START_RE = /^\\s*(?:select|insert|update|delete|with|create|alter|drop|truncate|lock)\\b/i;\n\n/**\n * knex prefixes a failed query's message with the whole statement (\"update ... - deadlock\n * detected\"). A long statement filled err_message and the truncation cut off the server's reason,\n * the only part worth reading. Keeps the reason; the statement never reaches the log.\n */\nexport function stripSql(message: string): string {\n if (!SQL_START_RE.test(message)) return message;\n const at = message.lastIndexOf(\" - \");\n return at === -1 ? message : message.slice(at + 3);\n}\n\n// The client hung up or sent a malformed request: worth a warn, not an error on our side.\nexport function isClientDisconnect(err: unknown): boolean {\n const e = err as { code?: unknown; message?: unknown } | null;\n const code = typeof e?.code === \"string\" ? e.code : \"\";\n return (\n code === \"ECONNRESET\" ||\n code === \"ECONNABORTED\" ||\n code === \"EPIPE\" ||\n code === \"ERR_STREAM_PREMATURE_CLOSE\" ||\n code.startsWith(\"HPE_\") ||\n e?.message === \"aborted\"\n );\n}\n\nconst logged = globalSingleton(\"logged\", () => new WeakSet<object>());\n\n// Marks an error as already written, so a later boundary (e.g. Next's onRequestError)\n// does not log it a second time.\nexport function markLogged(err: unknown): void {\n if (typeof err === \"object\" && err !== null) logged.add(err);\n}\n\nexport function isLogged(err: unknown): boolean {\n return typeof err === \"object\" && err !== null && logged.has(err);\n}\n","import { isErrorLike, serializeError } from \"./error\";\nimport type { Level } from \"./levels\";\nimport { REDACTED, toSnakeCase, type Redactor } from \"./redact\";\n\nexport { DEFAULT_REDACT_KEYS, toSnakeCase } from \"./redact\";\n\n/** Final per-field hook: return a replacement, or undefined to drop the field. */\nexport type RedactHook = (key: string, value: Primitive) => unknown;\n\nexport type Fields = Record<string, unknown>;\nexport type Primitive = string | number | boolean | null;\nexport type LogRecord = Record<string, Primitive>;\n\nexport interface NormalizeOptions {\n snakeCase: boolean;\n redactor: Redactor;\n hook?: RedactHook;\n}\n\n// Fields the redact hook never sees, so every line keeps its level, message and event.\nconst HOOK_EXEMPT = new Set([\"level\", \"message\", \"event\"]);\n\n// Keys owned by Vector (overwritten or deleted on ingest) or by the logger itself.\nexport const RESERVED_KEYS = new Set([\n \"project\", \"service\", \"vps\", \"version\", \"container_name\", \"container_id\", \"image\", \"stream\",\n \"_timestamp\", \"label\", \"host\", \"source_type\", \"msg\", \"lvl\", \"severity\", \"level\", \"message\",\n]);\n\nexport const MAX_LINE_BYTES = 16000;\nconst MAX_MESSAGE = 500;\nconst MAX_STACK = 4000;\nconst MAX_STRING = 1000;\nconst MAX_DEPTH = 3;\nconst TRUNCATED = \"…[truncated]\";\n\n// Fields kept when a line is too large.\nconst KEEP_ON_SHRINK = new Set([\n \"level\", \"message\", \"event\", \"request_id\", \"trace_id\", \"span_id\", \"job_name\", \"job_id\", \"job_attempt\",\n \"user_id\", \"tenant_id\", \"err_type\", \"err_message\", \"err_code\",\n]);\n\nexport function stripUrl(url: string): string {\n const noQuery = url.split(/[?#]/, 1)[0] ?? \"\";\n return noQuery.replace(/^([a-z][a-z0-9+.-]*:\\/\\/)[^/@\\s]*@/i, \"$1\");\n}\n\nexport function truncate(s: string, max: number): string {\n return s.length > max ? s.slice(0, max - TRUNCATED.length) + TRUNCATED : s;\n}\n\nfunction isPlainObject(v: unknown): v is Fields {\n if (typeof v !== \"object\" || v === null) return false;\n const proto = Object.getPrototypeOf(v);\n return proto === Object.prototype || proto === null;\n}\n\nfunction isUrlKey(key: string): boolean {\n return key === \"http_path\" || key === \"http_url\" || key.endsWith(\"_url\");\n}\n\nfunction flattenInto(out: LogRecord, prefix: string, obj: Fields, depth: number, opts: NormalizeOptions): void {\n for (const [rawKey, value] of Object.entries(obj)) {\n const key = opts.snakeCase ? toSnakeCase(rawKey) : rawKey;\n const full = prefix ? `${prefix}_${key}` : key;\n if (value === undefined || typeof value === \"function\" || typeof value === \"symbol\") continue;\n if (value !== null && (opts.redactor.isSensitive(rawKey) || opts.redactor.isSensitive(full))) {\n out[full] = REDACTED;\n continue;\n }\n if (value === null || typeof value === \"string\" || typeof value === \"boolean\") {\n out[full] = value;\n } else if (typeof value === \"number\") {\n out[full] = Number.isFinite(value) ? value : String(value);\n } else if (typeof value === \"bigint\") {\n out[full] = value.toString();\n } else if (value instanceof Date) {\n out[full] = Number.isNaN(value.getTime()) ? \"Invalid Date\" : value.toISOString();\n } else if (isErrorLike(value)) {\n out[full] = `${value.name}: ${value.message}`;\n } else if (isPlainObject(value) && depth < MAX_DEPTH - 1) {\n flattenInto(out, full, value, depth + 1, opts);\n } else {\n // Arrays, deep objects, class instances: stringified with sensitive keys redacted.\n out[full] = opts.redactor.json(value);\n }\n }\n}\n\n// Correlation ids are opaque tokens: value patterns such as phoneVN can match inside a hex\n// segment and break the join between services, so a well-formed id is never scrubbed.\nconst ID_VALUE_RE = /^[A-Za-z0-9._:-]{1,128}$/;\n\nfunction isIdKey(key: string): boolean {\n return key === \"request_id\" || key === \"trace_id\" || key === \"span_id\" || key.endsWith(\"_request_id\");\n}\n\nfunction finalize(key: string, value: Primitive, opts: NormalizeOptions): Primitive {\n if (typeof value !== \"string\") return value;\n if (isIdKey(key) && ID_VALUE_RE.test(value)) return value;\n const v = opts.redactor.scrub(isUrlKey(key) ? stripUrl(value) : value);\n return truncate(v, key === \"err_stack\" ? MAX_STACK : MAX_STRING);\n}\n\nexport function buildRecord(\n level: Level,\n message: unknown,\n sources: (Fields | undefined)[],\n opts: NormalizeOptions,\n): LogRecord {\n const merged: Fields = {};\n for (const source of sources) if (source) Object.assign(merged, source);\n\n let err: unknown;\n if (merged.err !== undefined && merged.err !== null) {\n err = merged.err;\n delete merged.err;\n } else if (isErrorLike(merged.error)) {\n err = merged.error;\n delete merged.error;\n }\n\n const flat: LogRecord = {};\n flattenInto(flat, \"\", merged, 0, opts);\n if (err !== undefined) Object.assign(flat, serializeError(err));\n\n const text = typeof message === \"string\" ? message : opts.redactor.json(message);\n const out: LogRecord = { level, message: truncate(opts.redactor.scrub(text), MAX_MESSAGE) };\n for (const [k, v] of Object.entries(flat)) {\n const key = RESERVED_KEYS.has(k) ? `app_${k}` : k;\n let value = finalize(key, v, opts);\n if (opts.hook && !HOOK_EXEMPT.has(key)) {\n const replaced = opts.hook(key, value);\n if (replaced === undefined) continue;\n value = typeof replaced === \"object\" && replaced !== null ? opts.redactor.json(replaced) : (replaced as Primitive);\n }\n out[key] = value;\n }\n return out;\n}\n\nfunction byteLength(s: string): number {\n // UTF-8 uses at most 3 bytes per UTF-16 code unit: skip encoding short lines.\n if (s.length * 3 <= MAX_LINE_BYTES) return s.length;\n return new TextEncoder().encode(s).length;\n}\n\nexport function serializeRecord(record: LogRecord): string {\n const line = JSON.stringify(record);\n if (byteLength(line) <= MAX_LINE_BYTES) return line;\n const small: LogRecord = {};\n for (const [k, v] of Object.entries(record)) {\n if (KEEP_ON_SHRINK.has(k) || k.startsWith(\"http_\")) small[k] = v;\n }\n small.log_truncated = true;\n return JSON.stringify(small);\n}\n","import type { LogRecord } from \"./normalize\";\n\n// Human-readable line for local development only (LOG_FORMAT=pretty).\nexport function formatPretty(record: LogRecord): string {\n const { level, message, err_stack, ...rest } = record;\n const time = new Date().toISOString().slice(11, 23);\n const extras = Object.entries(rest)\n .map(([k, v]) => `${k}=${typeof v === \"string\" && /\\s/.test(v) ? JSON.stringify(v) : String(v)}`)\n .join(\" \");\n let line = `${time} ${String(level).toUpperCase().padEnd(5)} ${String(message)}${extras ? ` ${extras}` : \"\"}`;\n if (typeof err_stack === \"string\") line += `\\n${err_stack}`;\n return line;\n}\n","import { getContext } from \"./context\";\nimport { LEVEL_RANK, parseLevel, type Level } from \"./levels\";\nimport {\n buildRecord,\n serializeRecord,\n type Fields,\n type NormalizeOptions,\n type RedactHook,\n} from \"./normalize\";\nimport { formatPretty } from \"./pretty\";\nimport { createRedactor, type KeyPattern } from \"./redact\";\n\ntype LogMethod = (message: string, fields?: Fields) => void;\n\nexport interface Logger {\n readonly level: Level;\n trace: LogMethod;\n debug: LogMethod;\n info: LogMethod;\n warn: LogMethod;\n error: LogMethod;\n fatal: LogMethod;\n child(fields: Fields): Logger;\n isLevelEnabled(level: Level): boolean;\n}\n\nexport interface LoggerOptions {\n level?: Level | string;\n format?: \"json\" | \"pretty\";\n base?: Fields;\n /** Extra sensitive keys: names (matched like the defaults) or RegExp tested on the snake_case key. */\n redactKeys?: KeyPattern[];\n /** Extra value patterns masked in every string, e.g. REDACT_PATTERNS.phoneVN. */\n redactValues?: RegExp[];\n /** Final per-field hook: return a replacement, or undefined to drop the field. */\n redact?: RedactHook;\n snakeCase?: boolean;\n write?: (line: string) => void;\n}\n\nfunction env(name: string): string | undefined {\n return typeof process !== \"undefined\" ? process.env?.[name] : undefined;\n}\n\n// Captured before patchConsole can replace it, so the fallback never loops into the logger.\nconst consoleLog = console.log.bind(console);\n\nfunction defaultWrite(line: string): void {\n if (typeof process !== \"undefined\" && typeof process.stdout?.write === \"function\") {\n process.stdout.write(`${line}\\n`);\n } else {\n consoleLog(line);\n }\n}\n\nexport function createLogger(options: LoggerOptions = {}): Logger {\n const level = parseLevel(options.level ?? env(\"LOG_LEVEL\"));\n const format = options.format ?? (env(\"LOG_FORMAT\") === \"pretty\" ? \"pretty\" : \"json\");\n const write = options.write ?? defaultWrite;\n const norm: NormalizeOptions = {\n snakeCase: options.snakeCase ?? true,\n redactor: createRedactor({ keys: options.redactKeys, values: options.redactValues }),\n hook: options.redact,\n };\n\n const make = (bound: Fields): Logger => {\n const emit = (lvl: Level, message: string, fields?: Fields) => {\n if (LEVEL_RANK[lvl] < LEVEL_RANK[level]) return;\n let line: string;\n try {\n const record = buildRecord(lvl, message, [options.base, getContext(), bound, fields], norm);\n line = format === \"pretty\" ? formatPretty(record) : serializeRecord(record);\n } catch (e) {\n line = JSON.stringify({\n level: \"error\",\n message: \"log serialize failed\",\n event: \"log.serialize_failed\",\n err_message: String((e as Error)?.message ?? e).slice(0, 1000),\n original_message: String(message).slice(0, 500),\n });\n }\n try {\n write(line);\n } catch {\n // Logging must never break the app.\n }\n };\n return {\n level,\n trace: (m, f) => emit(\"trace\", m, f),\n debug: (m, f) => emit(\"debug\", m, f),\n info: (m, f) => emit(\"info\", m, f),\n warn: (m, f) => emit(\"warn\", m, f),\n error: (m, f) => emit(\"error\", m, f),\n fatal: (m, f) => emit(\"fatal\", m, f),\n child: (fields) => make({ ...bound, ...fields }),\n isLevelEnabled: (l) => LEVEL_RANK[l] >= LEVEL_RANK[level],\n };\n };\n return make({});\n}\n","import type { Logger } from \"./logger\";\n\nexport interface KnexLogOptions {\n /** Log db.slow_query at or above this duration. Default 500 ms. */\n slowMs?: number;\n /**\n * Also log db.error for failed queries. Off by default: an error that fails the request already\n * reaches its http.request line. Turn it on when the app swallows errors inside transactions:\n * Postgres then answers every later query with 25P02 (\"current transaction is aborted\"), and\n * only this line shows the query that failed first. 25P02 itself is never logged here.\n */\n logErrors?: boolean;\n /** Value for db_system, e.g. \"postgres\". */\n db_system?: string;\n now?: () => number;\n}\n\n/** The part of a knex instance (strapi.db.connection) knexLogging uses. */\nexport interface KnexLike {\n on(event: string, listener: (...args: any[]) => void): unknown;\n}\n\ninterface QueryData {\n __knexQueryUid?: string;\n method?: string;\n sql?: string;\n}\n\n// Max queries in flight we track; a query that never answers must not grow the map forever.\nconst MAX_PENDING = 10_000;\n\nconst TABLE_RE = /\\b(?:from|into|update|join)\\s+((?:\"[^\"]+\"|`[^`]+`|[\\w$]+)(?:\\.(?:\"[^\"]+\"|`[^`]+`|[\\w$]+))?)/i;\n\n/** The first table a statement names, without schema or quotes. The SQL itself is never logged. */\nexport function tableOf(sql: string | undefined): string | undefined {\n const match = sql ? TABLE_RE.exec(sql) : null;\n if (!match?.[1]) return undefined;\n const last = match[1].split(\".\").pop() ?? \"\";\n return last.replace(/^[\"`]|[\"`]$/g, \"\") || undefined;\n}\n\nfunction operationOf(data: QueryData): string | undefined {\n if (data.method && data.method !== \"raw\") return data.method;\n return /^\\s*(\\w+)/.exec(data.sql ?? \"\")?.[1]?.toLowerCase();\n}\n\n/**\n * Query logging for knex (Strapi: `knexLogging(strapi.db.connection, log)` in bootstrap()).\n * Logs db.slow_query (warn) with db_operation, db_table and duration_ms, and optionally db.error.\n * Never logs SQL text or bindings.\n */\nexport function knexLogging(knex: KnexLike, log: Logger, opts: KnexLogOptions = {}): void {\n const slowMs = opts.slowMs ?? 500;\n const now = opts.now ?? (() => performance.now());\n const started = new Map<string, number>();\n\n const finish = (data: QueryData | undefined) => {\n const uid = data?.__knexQueryUid;\n if (!uid) return undefined;\n const start = started.get(uid);\n started.delete(uid);\n return start === undefined ? undefined : Math.round(now() - start);\n };\n const base = (data: QueryData, duration: number | undefined) => ({\n db_system: opts.db_system,\n db_operation: operationOf(data),\n db_table: tableOf(data.sql),\n duration_ms: duration,\n });\n\n knex.on(\"query\", (data: QueryData) => {\n const uid = data?.__knexQueryUid;\n if (!uid) return;\n if (started.size >= MAX_PENDING) started.clear();\n started.set(uid, now());\n });\n\n knex.on(\"query-response\", (response: unknown, data: QueryData) => {\n const duration = finish(data);\n if (duration === undefined || duration < slowMs) return;\n const rows = Array.isArray(response) ? response.length : undefined;\n log.warn(\"slow query\", { ...base(data, duration), event: \"db.slow_query\", db_rows: rows });\n });\n\n knex.on(\"query-error\", (err: unknown, data: QueryData) => {\n const duration = finish(data);\n if (!opts.logErrors) return;\n if ((err as { code?: unknown } | null)?.code === \"25P02\") return;\n // err_message drops the statement knex prefixed (see stripSql in serializeError).\n log.error(\"database error\", { ...base(data ?? {}, duration), event: \"db.error\", err });\n });\n}\n","// No imports: this module is shared with the edge entry (next-edge).\nexport const REQUEST_ID_RE = /^[A-Za-z0-9._-]{1,64}$/;\nconst TRACEPARENT_RE = /^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/;\n\nexport function newRequestId(): string {\n return globalThis.crypto.randomUUID();\n}\n\nfunction first(header?: string | string[] | null): string | undefined {\n return Array.isArray(header) ? header[0] : (header ?? undefined);\n}\n\nexport function resolveRequestId(header?: string | string[] | null): string {\n const value = first(header);\n return value && REQUEST_ID_RE.test(value) ? value : newRequestId();\n}\n\nexport function parseTraceparent(header?: string | string[] | null): { trace_id: string; span_id: string } | undefined {\n const value = first(header)?.trim().toLowerCase();\n const m = value ? TRACEPARENT_RE.exec(value) : null;\n if (!m) return undefined;\n const [, version, traceId, spanId] = m as unknown as [string, string, string, string];\n if (version === \"ff\" || /^0+$/.test(traceId) || /^0+$/.test(spanId)) return undefined;\n return { trace_id: traceId, span_id: spanId };\n}\n","import { getContext } from \"./context\";\nimport { isClientDisconnect, markLogged, serializeError } from \"./error\";\nimport type { Logger } from \"./logger\";\nimport { stripUrl, type Fields } from \"./normalize\";\nimport { parseTraceparent, resolveRequestId } from \"./request-id\";\n\nexport { newRequestId, parseTraceparent, REQUEST_ID_RE, resolveRequestId } from \"./request-id\";\n\nexport type HeaderSource = Headers | Record<string, string | string[] | undefined>;\n\nfunction header(headers: HeaderSource, name: string): string | string[] | undefined {\n if (typeof (headers as Headers).get === \"function\") return (headers as Headers).get(name) ?? undefined;\n return (headers as Record<string, string | string[] | undefined>)[name];\n}\n\nexport function requestContextFields(headers: HeaderSource): { request_id: string; trace_id?: string; span_id?: string } {\n const out: { request_id: string; trace_id?: string; span_id?: string } = {\n request_id: resolveRequestId(header(headers, \"x-request-id\")),\n };\n const tp = parseTraceparent(header(headers, \"traceparent\"));\n if (tp) Object.assign(out, tp);\n return out;\n}\n\n// Headers to forward to services we own, so their logs share request_id / trace_id.\nexport function propagationHeaders(): Record<string, string> {\n const ctx = getContext();\n const out: Record<string, string> = {};\n if (typeof ctx.request_id === \"string\") out[\"x-request-id\"] = ctx.request_id;\n if (typeof ctx.trace_id === \"string\" && typeof ctx.span_id === \"string\") {\n out.traceparent = `00-${ctx.trace_id}-${ctx.span_id}-01`;\n }\n return out;\n}\n\nexport const DEFAULT_SKIP_PATHS: (string | RegExp)[] = [\n // Also under a prefix such as /api/v1/health.\n /(^|\\/)(health|healthz|ready|readyz|livez)\\/?$/,\n \"/favicon.ico\",\n /^\\/_next\\/static\\//,\n];\n\nexport interface HttpLogOptions {\n skipPaths?: (string | RegExp)[];\n}\n\nexport interface HttpRequestInfo {\n method: string;\n route?: string;\n path: string;\n status: number;\n duration_ms?: number;\n err?: unknown;\n fields?: Fields;\n}\n\nexport function shouldSkip(method: string, path: string, skipPaths: (string | RegExp)[] = DEFAULT_SKIP_PATHS): boolean {\n if (method.toUpperCase() === \"OPTIONS\") return true;\n const p = stripUrl(path);\n return skipPaths.some((s) => (typeof s === \"string\" ? p === s : s.test(p)));\n}\n\n// Writes the one `http.request` summary line for an inbound request. Skipped paths are still\n// logged when they fail with a 5xx, so a failing health check stays visible.\nexport function logHttpRequest(log: Logger, info: HttpRequestInfo, opts: HttpLogOptions = {}): void {\n if (info.status < 500 && shouldSkip(info.method, info.path, opts.skipPaths)) return;\n const hasErr = info.err !== undefined && info.err !== null;\n // A client that hung up mid-request is not a server failure, whatever status the app set.\n const clientGone = hasErr && isClientDisconnect(info.err);\n const level = info.status >= 500 && !clientGone ? \"error\" : info.status >= 400 ? \"warn\" : \"info\";\n const path = stripUrl(info.path);\n const errFields: Fields = {};\n if (hasErr) {\n Object.assign(errFields, serializeError(info.err));\n if (info.status < 500 || clientGone) delete errFields.err_stack;\n if (clientGone) errFields.client_disconnect = true;\n markLogged(info.err);\n }\n // Route templates keep the message bounded; the raw path would make one message per URL.\n const message = info.route ? `${info.method} ${info.route} ${info.status}` : `${info.method} ${info.status}`;\n log[level](message, {\n ...info.fields,\n event: \"http.request\",\n http_method: info.method,\n http_route: info.route,\n http_path: path,\n http_status: info.status,\n duration_ms: info.duration_ms === undefined ? undefined : Math.round(info.duration_ms),\n ...errFields,\n });\n}\n","import { propagationHeaders } from \"./http\";\nimport type { Logger } from \"./logger\";\n\nexport interface FetchLogOptions {\n peer_service: string;\n /** Forward x-request-id / traceparent. Only for services we own. */\n internal?: boolean;\n slowMs?: number;\n fetch?: typeof fetch;\n}\n\nfunction describeRequest(input: RequestInfo | URL, init?: RequestInit): { method: string; url: string } {\n const method = (init?.method ?? (input instanceof Request ? input.method : \"GET\")).toUpperCase();\n const url = typeof input === \"string\" ? input : input instanceof URL ? input.href : input.url;\n return { method, url };\n}\n\nexport function createFetch(log: Logger, opts: FetchLogOptions): typeof fetch {\n const slowMs = opts.slowMs ?? 1000;\n const wrapped = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const base = opts.fetch ?? globalThis.fetch;\n const { method, url } = describeRequest(input, init);\n let requestInit = init;\n if (opts.internal) {\n const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : undefined));\n for (const [k, v] of Object.entries(propagationHeaders())) if (!headers.has(k)) headers.set(k, v);\n requestInit = { ...init, headers };\n }\n const fields = { event: \"http.outbound\", peer_service: opts.peer_service, http_method: method, http_url: url };\n const start = performance.now();\n try {\n const res = await base(input, requestInit);\n const duration_ms = Math.round(performance.now() - start);\n if (res.status >= 500) {\n log.warn(\"outbound request failed\", { ...fields, http_status: res.status, duration_ms });\n } else if (duration_ms >= slowMs) {\n log.warn(\"outbound request slow\", { ...fields, http_status: res.status, duration_ms });\n }\n return res;\n } catch (err) {\n log.warn(\"outbound request failed\", { ...fields, duration_ms: Math.round(performance.now() - start), err });\n throw err;\n }\n };\n return wrapped as typeof fetch;\n}\n","import { getContext, withContext } from \"./context\";\nimport { markLogged } from \"./error\";\nimport type { Logger } from \"./logger\";\nimport type { Fields } from \"./normalize\";\n\nexport interface JobInfo {\n job_name: string;\n job_id?: string | number;\n job_attempt?: number;\n /** No retries left after this attempt (or decided per error). Defaults to true when unknown. */\n final_attempt?: boolean | ((err: unknown) => boolean);\n request_id?: string;\n fields?: Fields;\n}\n\nexport async function runJob<T>(log: Logger, info: JobInfo, fn: () => T | Promise<T>): Promise<T> {\n const ctx: Fields = { ...info.fields, job_name: info.job_name };\n if (info.job_id !== undefined) ctx.job_id = String(info.job_id);\n if (info.job_attempt !== undefined) ctx.job_attempt = info.job_attempt;\n if (info.request_id !== undefined) ctx.request_id = info.request_id;\n\n return withContext(ctx, async () => {\n const start = performance.now();\n try {\n const result = await fn();\n log.info(\"job completed\", { event: \"job.completed\", duration_ms: Math.round(performance.now() - start) });\n return result;\n } catch (err) {\n const final = typeof info.final_attempt === \"function\" ? info.final_attempt(err) : (info.final_attempt ?? true);\n log[final ? \"error\" : \"warn\"](\"job failed\", {\n event: \"job.failed\",\n duration_ms: Math.round(performance.now() - start),\n err,\n });\n markLogged(err);\n throw err;\n }\n });\n}\n\n/** Adds the current request_id to a job payload, so the job's logs link back to the request. */\nexport function jobData<T extends Record<string, unknown>>(data: T): T & { request_id?: string } {\n const requestId = getContext().request_id;\n if (typeof requestId !== \"string\" || data.request_id !== undefined) return data;\n return { ...data, request_id: requestId };\n}\n","import { isErrorLike, isLogged } from \"./error\";\nimport type { Level } from \"./levels\";\nimport type { Logger } from \"./logger\";\nimport { defaultRedactor } from \"./redact\";\n\nconst METHODS = { log: \"info\", info: \"info\", warn: \"warn\", error: \"error\", debug: \"debug\", trace: \"debug\" } as const;\ntype Method = keyof typeof METHODS;\ntype ConsoleFn = (...args: unknown[]) => void;\n\nexport interface PatchConsoleOptions {\n /** Return true to drop a console call, e.g. errors a framework hook will log anyway. */\n skip?: (args: unknown[]) => boolean;\n}\n\n/**\n * Routes console.log/info/warn/error/debug/trace through the logger, so legacy console calls\n * and framework output (e.g. Next.js errors) become JSON lines with request context.\n * Calls carrying an error that is already on a summary line are dropped.\n * Returns a function that restores the previous console methods.\n */\nexport function patchConsole(log: Logger, opts: PatchConsoleOptions = {}): () => void {\n const target = console as unknown as Record<Method, ConsoleFn>;\n const saved = {} as Record<Method, ConsoleFn>;\n let inside = false;\n\n for (const method of Object.keys(METHODS) as Method[]) {\n const previous = target[method];\n saved[method] = previous;\n const level: Level = METHODS[method];\n target[method] = (...args: unknown[]) => {\n // A write path that itself uses console must not loop back into the logger.\n if (inside) return previous.apply(console, args);\n inside = true;\n try {\n if (args.some((arg) => isErrorLike(arg) && isLogged(arg)) || opts.skip?.(args)) return;\n let err: unknown;\n const parts: string[] = [];\n for (const arg of args) {\n if (isErrorLike(arg)) {\n err ??= arg;\n parts.push(arg.message);\n } else {\n parts.push(typeof arg === \"string\" ? arg : defaultRedactor.json(arg));\n }\n }\n log[level](parts.join(\" \"), { event: \"console\", console_method: method, err });\n } finally {\n inside = false;\n }\n };\n }\n\n return () => {\n for (const method of Object.keys(saved) as Method[]) target[method] = saved[method];\n };\n}\n","import { globalSingleton } from \"./global\";\nimport type { Logger } from \"./logger\";\nimport type { Fields } from \"./normalize\";\n\nexport function logStartup(log: Logger, fields: Fields = {}): void {\n log.info(\"app started\", {\n event: \"app.started\",\n runtime_version: `node ${process.versions.node}`,\n log_level: log.level,\n ...fields,\n });\n}\n\n/** Call at the start of your own shutdown handler (e.g. on SIGTERM). The library never handles signals. */\nexport function logShutdown(log: Logger, fields: Fields = {}): void {\n log.info(\"app stopping\", { event: \"app.stopping\", ...fields });\n}\n\nexport interface ProcessHandlerOptions {\n /** Exit with code 1 after an uncaught error. Next.js keeps serving, so its adapter passes false. */\n exitOnCrash?: boolean;\n /** Time other crash handlers (Sentry, APM) get to flush before exit. Default 1000 ms. */\n exitDelayMs?: number;\n exit?: (code: number) => void;\n}\n\nexport function crashHandlers(log: Logger, opts: ProcessHandlerOptions = {}) {\n const exitOnCrash = opts.exitOnCrash ?? true;\n const exitDelayMs = opts.exitDelayMs ?? 1000;\n const exit = opts.exit ?? ((code: number) => process.exit(code));\n let exiting = false;\n const crash = (source: string, err: unknown) => {\n if (!exitOnCrash) {\n log.error(\"unhandled error\", { event: \"app.unhandled_error\", crash_source: source, err });\n return;\n }\n log.fatal(\"app crashed\", { event: \"app.crashed\", crash_source: source, err });\n if (exiting) return;\n exiting = true;\n if (typeof process !== \"undefined\") process.exitCode = 1;\n // Deferred so listeners registered after ours still run; unref so a process with nothing\n // left to do exits on its own (with exitCode 1) without waiting.\n const timer = setTimeout(() => exit(1), exitDelayMs);\n (timer as { unref?: () => void }).unref?.();\n };\n return {\n onUncaught: (err: unknown) => crash(\"uncaughtException\", err),\n onRejection: (reason: unknown) => crash(\"unhandledRejection\", reason),\n };\n}\n\nconst state = globalSingleton(\"process\", () => ({ installed: false }));\n\n/** Logs uncaught exceptions and unhandled rejections. Does not touch SIGTERM/SIGINT. */\nexport function installProcessHandlers(log: Logger, opts: ProcessHandlerOptions = {}): void {\n if (state.installed || typeof process === \"undefined\" || typeof process.on !== \"function\") return;\n state.installed = true;\n const h = crashHandlers(log, opts);\n process.on(\"uncaughtException\", h.onUncaught);\n process.on(\"unhandledRejection\", h.onRejection);\n}\n\nconst warningState = globalSingleton(\"warnings\", () => ({ installed: false }));\n\n/**\n * Node keeps 10 frames by default; ORM/framework frames (knex, Strapi, Prisma) often use all of\n * them, hiding the app code that triggered a warning or error. Only ever raises the limit.\n */\nexport function raiseStackTraceLimit(limit: number): void {\n if (Error.stackTraceLimit < limit) Error.stackTraceLimit = limit;\n}\n\nexport interface ProcessWarningOptions {\n stackTraceLimit?: number;\n /**\n * Remove Node's own stderr printer, so a warning is one JSON line instead of that line plus\n * \"(node:1) Warning: ...\" and \"(Use `node --trace-deprecation ...`...)\". Default true.\n */\n replaceDefault?: boolean;\n /**\n * A repeated warning is written at most once per window (default 1 hour). The next line carries\n * `suppressed_count`, the repeats dropped since the previous line, so the frequency stays visible.\n */\n repeatWindowMs?: number;\n now?: () => number;\n}\n\n// Distinct warnings tracked; past this a new kind is logged every time instead of throttled.\nconst MAX_TRACKED_WARNINGS = 200;\n\n/**\n * Logs Node process warnings (deprecations, MaxListeners...) as `process.warning` lines whose\n * err_stack points at the code that triggered them. Repeats are throttled (see repeatWindowMs).\n * Also raises Error.stackTraceLimit (default 30) so the stack reaches past framework frames.\n */\nexport function logProcessWarnings(log: Logger, opts: ProcessWarningOptions = {}): void {\n if (warningState.installed || typeof process === \"undefined\" || typeof process.on !== \"function\") return;\n warningState.installed = true;\n raiseStackTraceLimit(opts.stackTraceLimit ?? 30);\n if (opts.replaceDefault ?? true) {\n for (const l of process.listeners(\"warning\")) if (l.name === \"onWarning\") process.off(\"warning\", l);\n }\n const windowMs = opts.repeatWindowMs ?? 60 * 60 * 1000;\n const now = opts.now ?? Date.now;\n const tracked = new Map<string, { loggedAt: number; suppressed: number }>();\n process.on(\"warning\", (warning: Error) => {\n const key = `${warning?.name}:${(warning as { code?: unknown })?.code ?? \"\"}:${warning?.message}`;\n const t = now();\n const entry = tracked.get(key);\n if (entry && t - entry.loggedAt < windowMs) {\n entry.suppressed += 1;\n return;\n }\n if (entry) tracked.set(key, { loggedAt: t, suppressed: 0 });\n else if (tracked.size < MAX_TRACKED_WARNINGS) tracked.set(key, { loggedAt: t, suppressed: 0 });\n log.warn(\"process warning\", {\n event: \"process.warning\",\n suppressed_count: entry ? entry.suppressed : undefined,\n err: warning,\n });\n });\n}\n"],"mappings":"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","names":["header"]}
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
- import { F as Fields, L as Logger } from './logger-CFMTzjsm.cjs';
2
- export { K as KeyPattern, a as LEVELS, b as Level, c as LoggerOptions, R as REDACT_PATTERNS, d as RedactHook, e as createLogger } from './logger-CFMTzjsm.cjs';
3
- export { D as DEFAULT_SKIP_PATHS, H as HttpLogOptions, a as HttpRequestInfo, l as logHttpRequest, p as propagationHeaders, r as requestContextFields } from './http-BXAiU-rN.cjs';
1
+ import { L as Logger, F as Fields } from './logger-3Co9eVJf.cjs';
2
+ export { K as KeyPattern, a as LEVELS, b as Level, c as LoggerOptions, R as REDACT_PATTERNS, d as RedactHook, e as createLogger } from './logger-3Co9eVJf.cjs';
3
+ export { D as DEFAULT_SKIP_PATHS, H as HttpLogOptions, a as HttpRequestInfo, l as logHttpRequest, p as propagationHeaders, r as requestContextFields } from './http-BQJkHBwQ.cjs';
4
4
 
5
5
  declare function resolveRequestId(header?: string | string[] | null): string;
6
6
  declare function parseTraceparent(header?: string | string[] | null): {
@@ -14,8 +14,43 @@ interface ErrFields {
14
14
  err_code?: string;
15
15
  err_stack?: string;
16
16
  err_cause?: string;
17
+ /** Database errors (pg): the table and constraint the server reported. */
18
+ db_table?: string;
19
+ db_constraint?: string;
17
20
  }
18
21
  declare function serializeError(err: unknown): ErrFields;
22
+ /**
23
+ * knex prefixes a failed query's message with the whole statement ("update ... - deadlock
24
+ * detected"). A long statement filled err_message and the truncation cut off the server's reason,
25
+ * the only part worth reading. Keeps the reason; the statement never reaches the log.
26
+ */
27
+ declare function stripSql(message: string): string;
28
+ declare function isClientDisconnect(err: unknown): boolean;
29
+
30
+ interface KnexLogOptions {
31
+ /** Log db.slow_query at or above this duration. Default 500 ms. */
32
+ slowMs?: number;
33
+ /**
34
+ * Also log db.error for failed queries. Off by default: an error that fails the request already
35
+ * reaches its http.request line. Turn it on when the app swallows errors inside transactions:
36
+ * Postgres then answers every later query with 25P02 ("current transaction is aborted"), and
37
+ * only this line shows the query that failed first. 25P02 itself is never logged here.
38
+ */
39
+ logErrors?: boolean;
40
+ /** Value for db_system, e.g. "postgres". */
41
+ db_system?: string;
42
+ now?: () => number;
43
+ }
44
+ /** The part of a knex instance (strapi.db.connection) knexLogging uses. */
45
+ interface KnexLike {
46
+ on(event: string, listener: (...args: any[]) => void): unknown;
47
+ }
48
+ /**
49
+ * Query logging for knex (Strapi: `knexLogging(strapi.db.connection, log)` in bootstrap()).
50
+ * Logs db.slow_query (warn) with db_operation, db_table and duration_ms, and optionally db.error.
51
+ * Never logs SQL text or bindings.
52
+ */
53
+ declare function knexLogging(knex: KnexLike, log: Logger, opts?: KnexLogOptions): void;
19
54
 
20
55
  declare function withContext<T>(fields: Fields, fn: () => T): T;
21
56
  declare function getContext(): Fields;
@@ -77,12 +112,18 @@ interface ProcessWarningOptions {
77
112
  * "(node:1) Warning: ..." and "(Use `node --trace-deprecation ...`...)". Default true.
78
113
  */
79
114
  replaceDefault?: boolean;
115
+ /**
116
+ * A repeated warning is written at most once per window (default 1 hour). The next line carries
117
+ * `suppressed_count`, the repeats dropped since the previous line, so the frequency stays visible.
118
+ */
119
+ repeatWindowMs?: number;
120
+ now?: () => number;
80
121
  }
81
122
  /**
82
123
  * Logs Node process warnings (deprecations, MaxListeners...) as `process.warning` lines whose
83
- * err_stack points at the code that triggered them. Each distinct warning is logged once.
124
+ * err_stack points at the code that triggered them. Repeats are throttled (see repeatWindowMs).
84
125
  * Also raises Error.stackTraceLimit (default 30) so the stack reaches past framework frames.
85
126
  */
86
127
  declare function logProcessWarnings(log: Logger, opts?: ProcessWarningOptions): void;
87
128
 
88
- export { type FetchLogOptions, Fields, type JobInfo, Logger, type PatchConsoleOptions, type ProcessHandlerOptions, addContext, createFetch, getContext, installProcessHandlers, jobData, logProcessWarnings, logShutdown, logStartup, parseTraceparent, patchConsole, recordError, resolveRequestId, runJob, serializeError, withContext };
129
+ export { type FetchLogOptions, Fields, type JobInfo, type KnexLike, type KnexLogOptions, Logger, type PatchConsoleOptions, type ProcessHandlerOptions, addContext, createFetch, getContext, installProcessHandlers, isClientDisconnect, jobData, knexLogging, logProcessWarnings, logShutdown, logStartup, parseTraceparent, patchConsole, recordError, resolveRequestId, runJob, serializeError, stripSql, withContext };