apitally 1.0.0-beta.2 → 1.0.0-beta.4

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 (74) hide show
  1. package/README.md +7 -25
  2. package/dist/activation.cjs +2 -1
  3. package/dist/activation.cjs.map +1 -1
  4. package/dist/activation.d.cts +1 -0
  5. package/dist/activation.d.ts +1 -0
  6. package/dist/activation.js +2 -1
  7. package/dist/activation.js.map +1 -1
  8. package/dist/consumers.cjs +96 -0
  9. package/dist/consumers.cjs.map +1 -0
  10. package/dist/consumers.d.cts +13 -0
  11. package/dist/consumers.d.ts +13 -0
  12. package/dist/consumers.js +93 -0
  13. package/dist/consumers.js.map +1 -0
  14. package/dist/context.cjs +2 -8
  15. package/dist/context.cjs.map +1 -1
  16. package/dist/context.d.cts +5 -5
  17. package/dist/context.d.ts +5 -5
  18. package/dist/context.js +3 -7
  19. package/dist/context.js.map +1 -1
  20. package/dist/exportWorker.cjs +6 -5
  21. package/dist/exportWorker.cjs.map +1 -1
  22. package/dist/exportWorker.js +6 -5
  23. package/dist/exportWorker.js.map +1 -1
  24. package/dist/index.cjs +2 -2
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.cts +1 -1
  27. package/dist/index.d.ts +1 -1
  28. package/dist/index.js +1 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/metrics.cjs +164 -32
  31. package/dist/metrics.cjs.map +1 -1
  32. package/dist/metrics.d.cts +4 -6
  33. package/dist/metrics.d.ts +4 -6
  34. package/dist/metrics.js +165 -33
  35. package/dist/metrics.js.map +1 -1
  36. package/dist/nestjs/index.cjs +6 -0
  37. package/dist/nestjs/index.cjs.map +1 -1
  38. package/dist/nestjs/index.js +6 -0
  39. package/dist/nestjs/index.js.map +1 -1
  40. package/dist/providers.cjs +0 -8
  41. package/dist/providers.cjs.map +1 -1
  42. package/dist/providers.d.cts +0 -2
  43. package/dist/providers.d.ts +0 -2
  44. package/dist/providers.js +1 -8
  45. package/dist/providers.js.map +1 -1
  46. package/dist/requestObservation.cjs +6 -4
  47. package/dist/requestObservation.cjs.map +1 -1
  48. package/dist/requestObservation.js +7 -5
  49. package/dist/requestObservation.js.map +1 -1
  50. package/dist/serverErrors.cjs +30 -28
  51. package/dist/serverErrors.cjs.map +1 -1
  52. package/dist/serverErrors.js +30 -28
  53. package/dist/serverErrors.js.map +1 -1
  54. package/dist/spanProcessor.cjs +0 -2
  55. package/dist/spanProcessor.cjs.map +1 -1
  56. package/dist/spanProcessor.js +0 -2
  57. package/dist/spanProcessor.js.map +1 -1
  58. package/dist/spool.cjs +5 -0
  59. package/dist/spool.cjs.map +1 -1
  60. package/dist/spool.d.cts +2 -1
  61. package/dist/spool.d.ts +2 -1
  62. package/dist/spool.js +5 -0
  63. package/dist/spool.js.map +1 -1
  64. package/dist/validationErrors.cjs +29 -26
  65. package/dist/validationErrors.cjs.map +1 -1
  66. package/dist/validationErrors.js +29 -26
  67. package/dist/validationErrors.js.map +1 -1
  68. package/package.json +2 -2
  69. package/dist/consumer.cjs +0 -61
  70. package/dist/consumer.cjs.map +0 -1
  71. package/dist/consumer.d.cts +0 -12
  72. package/dist/consumer.d.ts +0 -12
  73. package/dist/consumer.js +0 -59
  74. package/dist/consumer.js.map +0 -1
@@ -2,19 +2,18 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_exceptions = require("./exceptions.cjs");
3
3
  //#region src/serverErrors.ts
4
4
  const SERVER_ERROR_EVENT_NAME = "apitally.request.server_error";
5
- const MAX_GROUPS = 100;
5
+ const MAX_ERRORS = 100;
6
6
  const MAX_CONSUMER_LENGTH = 128;
7
7
  const MAX_PATH_LENGTH = 2e3;
8
8
  const MAX_TYPE_LENGTH = 256;
9
9
  const MAX_MESSAGE_LENGTH = 2048;
10
10
  const MAX_STACKTRACE_LENGTH = 65536;
11
- const MAX_COUNT = 2 ** 32 - 1;
12
11
  const MESSAGE_TRUNCATION_SUFFIX = "... (truncated)";
13
12
  const STACKTRACE_TRUNCATION_SUFFIX = "\n... (truncated) ...";
14
- const SERVER_ERROR_GROUPS_KEY = Symbol.for("apitally.serverErrorGroups");
15
- const serverErrorGroupsHolder = globalThis;
16
- const serverErrorGroups = serverErrorGroupsHolder[SERVER_ERROR_GROUPS_KEY] ?? /* @__PURE__ */ new Map();
17
- serverErrorGroupsHolder[SERVER_ERROR_GROUPS_KEY] = serverErrorGroups;
13
+ const SERVER_ERROR_AGGREGATES_KEY = Symbol.for("apitally.serverErrorAggregates");
14
+ const serverErrorAggregatesHolder = globalThis;
15
+ const serverErrorAggregates = serverErrorAggregatesHolder[SERVER_ERROR_AGGREGATES_KEY] ?? /* @__PURE__ */ new Map();
16
+ serverErrorAggregatesHolder[SERVER_ERROR_AGGREGATES_KEY] = serverErrorAggregates;
18
17
  function addServerError(consumer, method, path, error, sentryEventId) {
19
18
  method = method.toUpperCase();
20
19
  if (method === "OPTIONS" || !path) return;
@@ -24,37 +23,40 @@ function addServerError(consumer, method, path, error, sentryEventId) {
24
23
  message: exception,
25
24
  stack: ""
26
25
  } : exception;
27
- const group = {
26
+ const fields = {
28
27
  method,
29
28
  path: path.slice(0, MAX_PATH_LENGTH),
30
29
  type: String(name ?? "").slice(0, MAX_TYPE_LENGTH),
31
30
  message: formatMessage(message),
32
- stacktrace: formatStacktrace(stack),
33
- count: 1
31
+ stacktrace: formatStacktrace(stack)
34
32
  };
35
- if (consumer !== void 0) group.consumer = consumer.slice(0, MAX_CONSUMER_LENGTH);
36
- if (sentryEventId !== void 0) group.sentry_event_id = sentryEventId;
37
- const key = [
38
- group.consumer ?? "",
39
- group.method,
40
- group.path,
41
- group.type,
42
- group.message,
43
- group.stacktrace
44
- ].join("\0");
45
- const existing = serverErrorGroups.get(key);
46
- if (existing) {
47
- existing.count = Math.min(existing.count + 1, MAX_COUNT);
48
- existing.sentry_event_id = group.sentry_event_id ?? existing.sentry_event_id;
49
- } else if (serverErrorGroups.size < MAX_GROUPS) serverErrorGroups.set(key, group);
33
+ const key = Object.values(fields).join("\0");
34
+ let aggregate = serverErrorAggregates.get(key);
35
+ if (!aggregate) {
36
+ if (serverErrorAggregates.size >= MAX_ERRORS) return;
37
+ aggregate = {
38
+ ...fields,
39
+ counts: /* @__PURE__ */ new Map()
40
+ };
41
+ serverErrorAggregates.set(key, aggregate);
42
+ }
43
+ consumer = consumer?.slice(0, MAX_CONSUMER_LENGTH);
44
+ aggregate.counts.set(consumer, (aggregate.counts.get(consumer) ?? 0) + 1);
45
+ if (sentryEventId !== void 0) aggregate.sentry_event_id = sentryEventId;
50
46
  }
51
47
  function drainServerErrors() {
52
- const groups = [...serverErrorGroups.values()];
53
- serverErrorGroups.clear();
54
- return groups;
48
+ const aggregates = [...serverErrorAggregates.values()];
49
+ serverErrorAggregates.clear();
50
+ return aggregates.map(({ counts, ...fields }) => ({
51
+ ...fields,
52
+ counts: [...counts].map(([consumer, count]) => consumer === void 0 ? { count } : {
53
+ consumer,
54
+ count
55
+ })
56
+ }));
55
57
  }
56
58
  function resetServerErrors() {
57
- serverErrorGroups.clear();
59
+ serverErrorAggregates.clear();
58
60
  }
59
61
  function formatMessage(message) {
60
62
  const text = String(message ?? "").trim();
@@ -1 +1 @@
1
- {"version":3,"file":"serverErrors.cjs","names":["coerceToException"],"sources":["../src/serverErrors.ts"],"sourcesContent":["import type { AnyValueMap } from \"@opentelemetry/api-logs\";\nimport { coerceToException } from \"./exceptions.js\";\n\nexport const SERVER_ERROR_EVENT_NAME = \"apitally.request.server_error\";\n\nconst MAX_GROUPS = 100;\nconst MAX_CONSUMER_LENGTH = 128;\nconst MAX_PATH_LENGTH = 2_000;\nconst MAX_TYPE_LENGTH = 256;\nconst MAX_MESSAGE_LENGTH = 2_048;\nconst MAX_STACKTRACE_LENGTH = 65_536;\nconst MAX_COUNT = 2 ** 32 - 1;\nconst MESSAGE_TRUNCATION_SUFFIX = \"... (truncated)\";\nconst STACKTRACE_TRUNCATION_SUFFIX = \"\\n... (truncated) ...\";\n\ntype ServerErrorGroup = {\n consumer?: string;\n method: string;\n path: string;\n type: string;\n message: string;\n stacktrace: string;\n count: number;\n sentry_event_id?: string;\n};\n\nconst SERVER_ERROR_GROUPS_KEY = Symbol.for(\"apitally.serverErrorGroups\");\nconst serverErrorGroupsHolder = globalThis as Record<\n symbol,\n Map<string, ServerErrorGroup> | undefined\n>;\nconst serverErrorGroups =\n serverErrorGroupsHolder[SERVER_ERROR_GROUPS_KEY] ?? new Map<string, ServerErrorGroup>();\nserverErrorGroupsHolder[SERVER_ERROR_GROUPS_KEY] = serverErrorGroups;\n\nexport function addServerError(\n consumer: string | undefined,\n method: string,\n path: string,\n error: unknown,\n sentryEventId: string | undefined,\n): void {\n method = method.toUpperCase();\n if (method === \"OPTIONS\" || !path) {\n return;\n }\n const exception = coerceToException(error);\n const { name, message, stack } =\n typeof exception === \"string\"\n ? { name: \"\", message: exception, stack: \"\" }\n : (exception as { name?: unknown; message?: unknown; stack?: unknown });\n const group: ServerErrorGroup = {\n method,\n path: path.slice(0, MAX_PATH_LENGTH),\n type: String(name ?? \"\").slice(0, MAX_TYPE_LENGTH),\n message: formatMessage(message),\n stacktrace: formatStacktrace(stack),\n count: 1,\n };\n if (consumer !== undefined) {\n group.consumer = consumer.slice(0, MAX_CONSUMER_LENGTH);\n }\n if (sentryEventId !== undefined) {\n group.sentry_event_id = sentryEventId;\n }\n const key = [\n group.consumer ?? \"\",\n group.method,\n group.path,\n group.type,\n group.message,\n group.stacktrace,\n ].join(\"\\0\");\n const existing = serverErrorGroups.get(key);\n if (existing) {\n existing.count = Math.min(existing.count + 1, MAX_COUNT);\n existing.sentry_event_id = group.sentry_event_id ?? existing.sentry_event_id;\n } else if (serverErrorGroups.size < MAX_GROUPS) {\n serverErrorGroups.set(key, group);\n }\n}\n\nexport function drainServerErrors(): AnyValueMap[] {\n const groups = [...serverErrorGroups.values()];\n serverErrorGroups.clear();\n return groups;\n}\n\nexport function resetServerErrors(): void {\n serverErrorGroups.clear();\n}\n\nfunction formatMessage(message: unknown): string {\n const text = String(message ?? \"\").trim();\n if (text.length <= MAX_MESSAGE_LENGTH) {\n return text;\n }\n return (\n text.slice(0, MAX_MESSAGE_LENGTH - MESSAGE_TRUNCATION_SUFFIX.length) + MESSAGE_TRUNCATION_SUFFIX\n );\n}\n\n// The error line and innermost frames come first in a JS stack, so the head is kept.\nfunction formatStacktrace(stack: unknown): string {\n const text = typeof stack === \"string\" ? stack.trim() : \"\";\n if (text.length <= MAX_STACKTRACE_LENGTH) {\n return text;\n }\n const cutoff = MAX_STACKTRACE_LENGTH - STACKTRACE_TRUNCATION_SUFFIX.length;\n const lines: string[] = [];\n let length = 0;\n for (const line of text.split(\"\\n\")) {\n if (length + line.length + 1 > cutoff) {\n break;\n }\n lines.push(line);\n length += line.length + 1;\n }\n return lines.join(\"\\n\") + STACKTRACE_TRUNCATION_SUFFIX;\n}\n"],"mappings":";;;AAGA,MAAa,0BAA0B;AAEvC,MAAM,aAAa;AACnB,MAAM,sBAAsB;AAC5B,MAAM,kBAAkB;AACxB,MAAM,kBAAkB;AACxB,MAAM,qBAAqB;AAC3B,MAAM,wBAAwB;AAC9B,MAAM,YAAY,KAAK,KAAK;AAC5B,MAAM,4BAA4B;AAClC,MAAM,+BAA+B;AAarC,MAAM,0BAA0B,OAAO,IAAI,4BAA4B;AACvE,MAAM,0BAA0B;AAIhC,MAAM,oBACJ,wBAAwB,4CAA4B,IAAI,IAA8B;AACxF,wBAAwB,2BAA2B;AAEnD,SAAgB,eACd,UACA,QACA,MACA,OACA,eACM;CACN,SAAS,OAAO,YAAY;CAC5B,IAAI,WAAW,aAAa,CAAC,MAC3B;CAEF,MAAM,YAAYA,mBAAAA,kBAAkB,KAAK;CACzC,MAAM,EAAE,MAAM,SAAS,UACrB,OAAO,cAAc,WACjB;EAAE,MAAM;EAAI,SAAS;EAAW,OAAO;CAAG,IACzC;CACP,MAAM,QAA0B;EAC9B;EACA,MAAM,KAAK,MAAM,GAAG,eAAe;EACnC,MAAM,OAAO,QAAQ,EAAE,CAAC,CAAC,MAAM,GAAG,eAAe;EACjD,SAAS,cAAc,OAAO;EAC9B,YAAY,iBAAiB,KAAK;EAClC,OAAO;CACT;CACA,IAAI,aAAa,KAAA,GACf,MAAM,WAAW,SAAS,MAAM,GAAG,mBAAmB;CAExD,IAAI,kBAAkB,KAAA,GACpB,MAAM,kBAAkB;CAE1B,MAAM,MAAM;EACV,MAAM,YAAY;EAClB,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;CACR,CAAC,CAAC,KAAK,IAAI;CACX,MAAM,WAAW,kBAAkB,IAAI,GAAG;CAC1C,IAAI,UAAU;EACZ,SAAS,QAAQ,KAAK,IAAI,SAAS,QAAQ,GAAG,SAAS;EACvD,SAAS,kBAAkB,MAAM,mBAAmB,SAAS;CAC/D,OAAO,IAAI,kBAAkB,OAAO,YAClC,kBAAkB,IAAI,KAAK,KAAK;AAEpC;AAEA,SAAgB,oBAAmC;CACjD,MAAM,SAAS,CAAC,GAAG,kBAAkB,OAAO,CAAC;CAC7C,kBAAkB,MAAM;CACxB,OAAO;AACT;AAEA,SAAgB,oBAA0B;CACxC,kBAAkB,MAAM;AAC1B;AAEA,SAAS,cAAc,SAA0B;CAC/C,MAAM,OAAO,OAAO,WAAW,EAAE,CAAC,CAAC,KAAK;CACxC,IAAI,KAAK,UAAU,oBACjB,OAAO;CAET,OACE,KAAK,MAAM,GAAG,IAAqD,IAAI;AAE3E;AAGA,SAAS,iBAAiB,OAAwB;CAChD,MAAM,OAAO,OAAO,UAAU,WAAW,MAAM,KAAK,IAAI;CACxD,IAAI,KAAK,UAAU,uBACjB,OAAO;CAET,MAAM,SAAS;CACf,MAAM,QAAkB,CAAC;CACzB,IAAI,SAAS;CACb,KAAK,MAAM,QAAQ,KAAK,MAAM,IAAI,GAAG;EACnC,IAAI,SAAS,KAAK,SAAS,IAAI,QAC7B;EAEF,MAAM,KAAK,IAAI;EACf,UAAU,KAAK,SAAS;CAC1B;CACA,OAAO,MAAM,KAAK,IAAI,IAAI;AAC5B"}
1
+ {"version":3,"file":"serverErrors.cjs","names":["coerceToException"],"sources":["../src/serverErrors.ts"],"sourcesContent":["import type { AnyValueMap } from \"@opentelemetry/api-logs\";\nimport { coerceToException } from \"./exceptions.js\";\n\nexport const SERVER_ERROR_EVENT_NAME = \"apitally.request.server_error\";\n\nconst MAX_ERRORS = 100;\nconst MAX_CONSUMER_LENGTH = 128;\nconst MAX_PATH_LENGTH = 2_000;\nconst MAX_TYPE_LENGTH = 256;\nconst MAX_MESSAGE_LENGTH = 2_048;\nconst MAX_STACKTRACE_LENGTH = 65_536;\nconst MESSAGE_TRUNCATION_SUFFIX = \"... (truncated)\";\nconst STACKTRACE_TRUNCATION_SUFFIX = \"\\n... (truncated) ...\";\n\ntype ServerErrorAggregate = {\n method: string;\n path: string;\n type: string;\n message: string;\n stacktrace: string;\n sentry_event_id?: string;\n counts: Map<string | undefined, number>;\n};\n\nconst SERVER_ERROR_AGGREGATES_KEY = Symbol.for(\"apitally.serverErrorAggregates\");\nconst serverErrorAggregatesHolder = globalThis as Record<\n symbol,\n Map<string, ServerErrorAggregate> | undefined\n>;\nconst serverErrorAggregates =\n serverErrorAggregatesHolder[SERVER_ERROR_AGGREGATES_KEY] ??\n new Map<string, ServerErrorAggregate>();\nserverErrorAggregatesHolder[SERVER_ERROR_AGGREGATES_KEY] = serverErrorAggregates;\n\nexport function addServerError(\n consumer: string | undefined,\n method: string,\n path: string,\n error: unknown,\n sentryEventId: string | undefined,\n): void {\n method = method.toUpperCase();\n if (method === \"OPTIONS\" || !path) {\n return;\n }\n const exception = coerceToException(error);\n const { name, message, stack } =\n typeof exception === \"string\"\n ? { name: \"\", message: exception, stack: \"\" }\n : (exception as { name?: unknown; message?: unknown; stack?: unknown });\n const fields = {\n method,\n path: path.slice(0, MAX_PATH_LENGTH),\n type: String(name ?? \"\").slice(0, MAX_TYPE_LENGTH),\n message: formatMessage(message),\n stacktrace: formatStacktrace(stack),\n };\n const key = Object.values(fields).join(\"\\0\");\n let aggregate = serverErrorAggregates.get(key);\n if (!aggregate) {\n if (serverErrorAggregates.size >= MAX_ERRORS) {\n return;\n }\n aggregate = { ...fields, counts: new Map() };\n serverErrorAggregates.set(key, aggregate);\n }\n consumer = consumer?.slice(0, MAX_CONSUMER_LENGTH);\n aggregate.counts.set(consumer, (aggregate.counts.get(consumer) ?? 0) + 1);\n if (sentryEventId !== undefined) {\n aggregate.sentry_event_id = sentryEventId;\n }\n}\n\nexport function drainServerErrors(): AnyValueMap[] {\n const aggregates = [...serverErrorAggregates.values()];\n serverErrorAggregates.clear();\n return aggregates.map(({ counts, ...fields }) => ({\n ...fields,\n counts: [...counts].map(([consumer, count]) =>\n consumer === undefined ? { count } : { consumer, count },\n ),\n }));\n}\n\nexport function resetServerErrors(): void {\n serverErrorAggregates.clear();\n}\n\nfunction formatMessage(message: unknown): string {\n const text = String(message ?? \"\").trim();\n if (text.length <= MAX_MESSAGE_LENGTH) {\n return text;\n }\n return (\n text.slice(0, MAX_MESSAGE_LENGTH - MESSAGE_TRUNCATION_SUFFIX.length) + MESSAGE_TRUNCATION_SUFFIX\n );\n}\n\n// The error line and innermost frames come first in a JS stack, so the head is kept.\nfunction formatStacktrace(stack: unknown): string {\n const text = typeof stack === \"string\" ? stack.trim() : \"\";\n if (text.length <= MAX_STACKTRACE_LENGTH) {\n return text;\n }\n const cutoff = MAX_STACKTRACE_LENGTH - STACKTRACE_TRUNCATION_SUFFIX.length;\n const lines: string[] = [];\n let length = 0;\n for (const line of text.split(\"\\n\")) {\n if (length + line.length + 1 > cutoff) {\n break;\n }\n lines.push(line);\n length += line.length + 1;\n }\n return lines.join(\"\\n\") + STACKTRACE_TRUNCATION_SUFFIX;\n}\n"],"mappings":";;;AAGA,MAAa,0BAA0B;AAEvC,MAAM,aAAa;AACnB,MAAM,sBAAsB;AAC5B,MAAM,kBAAkB;AACxB,MAAM,kBAAkB;AACxB,MAAM,qBAAqB;AAC3B,MAAM,wBAAwB;AAC9B,MAAM,4BAA4B;AAClC,MAAM,+BAA+B;AAYrC,MAAM,8BAA8B,OAAO,IAAI,gCAAgC;AAC/E,MAAM,8BAA8B;AAIpC,MAAM,wBACJ,4BAA4B,gDAC5B,IAAI,IAAkC;AACxC,4BAA4B,+BAA+B;AAE3D,SAAgB,eACd,UACA,QACA,MACA,OACA,eACM;CACN,SAAS,OAAO,YAAY;CAC5B,IAAI,WAAW,aAAa,CAAC,MAC3B;CAEF,MAAM,YAAYA,mBAAAA,kBAAkB,KAAK;CACzC,MAAM,EAAE,MAAM,SAAS,UACrB,OAAO,cAAc,WACjB;EAAE,MAAM;EAAI,SAAS;EAAW,OAAO;CAAG,IACzC;CACP,MAAM,SAAS;EACb;EACA,MAAM,KAAK,MAAM,GAAG,eAAe;EACnC,MAAM,OAAO,QAAQ,EAAE,CAAC,CAAC,MAAM,GAAG,eAAe;EACjD,SAAS,cAAc,OAAO;EAC9B,YAAY,iBAAiB,KAAK;CACpC;CACA,MAAM,MAAM,OAAO,OAAO,MAAM,CAAC,CAAC,KAAK,IAAI;CAC3C,IAAI,YAAY,sBAAsB,IAAI,GAAG;CAC7C,IAAI,CAAC,WAAW;EACd,IAAI,sBAAsB,QAAQ,YAChC;EAEF,YAAY;GAAE,GAAG;GAAQ,wBAAQ,IAAI,IAAI;EAAE;EAC3C,sBAAsB,IAAI,KAAK,SAAS;CAC1C;CACA,WAAW,UAAU,MAAM,GAAG,mBAAmB;CACjD,UAAU,OAAO,IAAI,WAAW,UAAU,OAAO,IAAI,QAAQ,KAAK,KAAK,CAAC;CACxE,IAAI,kBAAkB,KAAA,GACpB,UAAU,kBAAkB;AAEhC;AAEA,SAAgB,oBAAmC;CACjD,MAAM,aAAa,CAAC,GAAG,sBAAsB,OAAO,CAAC;CACrD,sBAAsB,MAAM;CAC5B,OAAO,WAAW,KAAK,EAAE,QAAQ,GAAG,cAAc;EAChD,GAAG;EACH,QAAQ,CAAC,GAAG,MAAM,CAAC,CAAC,KAAK,CAAC,UAAU,WAClC,aAAa,KAAA,IAAY,EAAE,MAAM,IAAI;GAAE;GAAU;EAAM,CACzD;CACF,EAAE;AACJ;AAEA,SAAgB,oBAA0B;CACxC,sBAAsB,MAAM;AAC9B;AAEA,SAAS,cAAc,SAA0B;CAC/C,MAAM,OAAO,OAAO,WAAW,EAAE,CAAC,CAAC,KAAK;CACxC,IAAI,KAAK,UAAU,oBACjB,OAAO;CAET,OACE,KAAK,MAAM,GAAG,IAAqD,IAAI;AAE3E;AAGA,SAAS,iBAAiB,OAAwB;CAChD,MAAM,OAAO,OAAO,UAAU,WAAW,MAAM,KAAK,IAAI;CACxD,IAAI,KAAK,UAAU,uBACjB,OAAO;CAET,MAAM,SAAS;CACf,MAAM,QAAkB,CAAC;CACzB,IAAI,SAAS;CACb,KAAK,MAAM,QAAQ,KAAK,MAAM,IAAI,GAAG;EACnC,IAAI,SAAS,KAAK,SAAS,IAAI,QAC7B;EAEF,MAAM,KAAK,IAAI;EACf,UAAU,KAAK,SAAS;CAC1B;CACA,OAAO,MAAM,KAAK,IAAI,IAAI;AAC5B"}
@@ -1,19 +1,18 @@
1
1
  import { coerceToException } from "./exceptions.js";
2
2
  //#region src/serverErrors.ts
3
3
  const SERVER_ERROR_EVENT_NAME = "apitally.request.server_error";
4
- const MAX_GROUPS = 100;
4
+ const MAX_ERRORS = 100;
5
5
  const MAX_CONSUMER_LENGTH = 128;
6
6
  const MAX_PATH_LENGTH = 2e3;
7
7
  const MAX_TYPE_LENGTH = 256;
8
8
  const MAX_MESSAGE_LENGTH = 2048;
9
9
  const MAX_STACKTRACE_LENGTH = 65536;
10
- const MAX_COUNT = 2 ** 32 - 1;
11
10
  const MESSAGE_TRUNCATION_SUFFIX = "... (truncated)";
12
11
  const STACKTRACE_TRUNCATION_SUFFIX = "\n... (truncated) ...";
13
- const SERVER_ERROR_GROUPS_KEY = Symbol.for("apitally.serverErrorGroups");
14
- const serverErrorGroupsHolder = globalThis;
15
- const serverErrorGroups = serverErrorGroupsHolder[SERVER_ERROR_GROUPS_KEY] ?? /* @__PURE__ */ new Map();
16
- serverErrorGroupsHolder[SERVER_ERROR_GROUPS_KEY] = serverErrorGroups;
12
+ const SERVER_ERROR_AGGREGATES_KEY = Symbol.for("apitally.serverErrorAggregates");
13
+ const serverErrorAggregatesHolder = globalThis;
14
+ const serverErrorAggregates = serverErrorAggregatesHolder[SERVER_ERROR_AGGREGATES_KEY] ?? /* @__PURE__ */ new Map();
15
+ serverErrorAggregatesHolder[SERVER_ERROR_AGGREGATES_KEY] = serverErrorAggregates;
17
16
  function addServerError(consumer, method, path, error, sentryEventId) {
18
17
  method = method.toUpperCase();
19
18
  if (method === "OPTIONS" || !path) return;
@@ -23,37 +22,40 @@ function addServerError(consumer, method, path, error, sentryEventId) {
23
22
  message: exception,
24
23
  stack: ""
25
24
  } : exception;
26
- const group = {
25
+ const fields = {
27
26
  method,
28
27
  path: path.slice(0, MAX_PATH_LENGTH),
29
28
  type: String(name ?? "").slice(0, MAX_TYPE_LENGTH),
30
29
  message: formatMessage(message),
31
- stacktrace: formatStacktrace(stack),
32
- count: 1
30
+ stacktrace: formatStacktrace(stack)
33
31
  };
34
- if (consumer !== void 0) group.consumer = consumer.slice(0, MAX_CONSUMER_LENGTH);
35
- if (sentryEventId !== void 0) group.sentry_event_id = sentryEventId;
36
- const key = [
37
- group.consumer ?? "",
38
- group.method,
39
- group.path,
40
- group.type,
41
- group.message,
42
- group.stacktrace
43
- ].join("\0");
44
- const existing = serverErrorGroups.get(key);
45
- if (existing) {
46
- existing.count = Math.min(existing.count + 1, MAX_COUNT);
47
- existing.sentry_event_id = group.sentry_event_id ?? existing.sentry_event_id;
48
- } else if (serverErrorGroups.size < MAX_GROUPS) serverErrorGroups.set(key, group);
32
+ const key = Object.values(fields).join("\0");
33
+ let aggregate = serverErrorAggregates.get(key);
34
+ if (!aggregate) {
35
+ if (serverErrorAggregates.size >= MAX_ERRORS) return;
36
+ aggregate = {
37
+ ...fields,
38
+ counts: /* @__PURE__ */ new Map()
39
+ };
40
+ serverErrorAggregates.set(key, aggregate);
41
+ }
42
+ consumer = consumer?.slice(0, MAX_CONSUMER_LENGTH);
43
+ aggregate.counts.set(consumer, (aggregate.counts.get(consumer) ?? 0) + 1);
44
+ if (sentryEventId !== void 0) aggregate.sentry_event_id = sentryEventId;
49
45
  }
50
46
  function drainServerErrors() {
51
- const groups = [...serverErrorGroups.values()];
52
- serverErrorGroups.clear();
53
- return groups;
47
+ const aggregates = [...serverErrorAggregates.values()];
48
+ serverErrorAggregates.clear();
49
+ return aggregates.map(({ counts, ...fields }) => ({
50
+ ...fields,
51
+ counts: [...counts].map(([consumer, count]) => consumer === void 0 ? { count } : {
52
+ consumer,
53
+ count
54
+ })
55
+ }));
54
56
  }
55
57
  function resetServerErrors() {
56
- serverErrorGroups.clear();
58
+ serverErrorAggregates.clear();
57
59
  }
58
60
  function formatMessage(message) {
59
61
  const text = String(message ?? "").trim();
@@ -1 +1 @@
1
- {"version":3,"file":"serverErrors.js","names":[],"sources":["../src/serverErrors.ts"],"sourcesContent":["import type { AnyValueMap } from \"@opentelemetry/api-logs\";\nimport { coerceToException } from \"./exceptions.js\";\n\nexport const SERVER_ERROR_EVENT_NAME = \"apitally.request.server_error\";\n\nconst MAX_GROUPS = 100;\nconst MAX_CONSUMER_LENGTH = 128;\nconst MAX_PATH_LENGTH = 2_000;\nconst MAX_TYPE_LENGTH = 256;\nconst MAX_MESSAGE_LENGTH = 2_048;\nconst MAX_STACKTRACE_LENGTH = 65_536;\nconst MAX_COUNT = 2 ** 32 - 1;\nconst MESSAGE_TRUNCATION_SUFFIX = \"... (truncated)\";\nconst STACKTRACE_TRUNCATION_SUFFIX = \"\\n... (truncated) ...\";\n\ntype ServerErrorGroup = {\n consumer?: string;\n method: string;\n path: string;\n type: string;\n message: string;\n stacktrace: string;\n count: number;\n sentry_event_id?: string;\n};\n\nconst SERVER_ERROR_GROUPS_KEY = Symbol.for(\"apitally.serverErrorGroups\");\nconst serverErrorGroupsHolder = globalThis as Record<\n symbol,\n Map<string, ServerErrorGroup> | undefined\n>;\nconst serverErrorGroups =\n serverErrorGroupsHolder[SERVER_ERROR_GROUPS_KEY] ?? new Map<string, ServerErrorGroup>();\nserverErrorGroupsHolder[SERVER_ERROR_GROUPS_KEY] = serverErrorGroups;\n\nexport function addServerError(\n consumer: string | undefined,\n method: string,\n path: string,\n error: unknown,\n sentryEventId: string | undefined,\n): void {\n method = method.toUpperCase();\n if (method === \"OPTIONS\" || !path) {\n return;\n }\n const exception = coerceToException(error);\n const { name, message, stack } =\n typeof exception === \"string\"\n ? { name: \"\", message: exception, stack: \"\" }\n : (exception as { name?: unknown; message?: unknown; stack?: unknown });\n const group: ServerErrorGroup = {\n method,\n path: path.slice(0, MAX_PATH_LENGTH),\n type: String(name ?? \"\").slice(0, MAX_TYPE_LENGTH),\n message: formatMessage(message),\n stacktrace: formatStacktrace(stack),\n count: 1,\n };\n if (consumer !== undefined) {\n group.consumer = consumer.slice(0, MAX_CONSUMER_LENGTH);\n }\n if (sentryEventId !== undefined) {\n group.sentry_event_id = sentryEventId;\n }\n const key = [\n group.consumer ?? \"\",\n group.method,\n group.path,\n group.type,\n group.message,\n group.stacktrace,\n ].join(\"\\0\");\n const existing = serverErrorGroups.get(key);\n if (existing) {\n existing.count = Math.min(existing.count + 1, MAX_COUNT);\n existing.sentry_event_id = group.sentry_event_id ?? existing.sentry_event_id;\n } else if (serverErrorGroups.size < MAX_GROUPS) {\n serverErrorGroups.set(key, group);\n }\n}\n\nexport function drainServerErrors(): AnyValueMap[] {\n const groups = [...serverErrorGroups.values()];\n serverErrorGroups.clear();\n return groups;\n}\n\nexport function resetServerErrors(): void {\n serverErrorGroups.clear();\n}\n\nfunction formatMessage(message: unknown): string {\n const text = String(message ?? \"\").trim();\n if (text.length <= MAX_MESSAGE_LENGTH) {\n return text;\n }\n return (\n text.slice(0, MAX_MESSAGE_LENGTH - MESSAGE_TRUNCATION_SUFFIX.length) + MESSAGE_TRUNCATION_SUFFIX\n );\n}\n\n// The error line and innermost frames come first in a JS stack, so the head is kept.\nfunction formatStacktrace(stack: unknown): string {\n const text = typeof stack === \"string\" ? stack.trim() : \"\";\n if (text.length <= MAX_STACKTRACE_LENGTH) {\n return text;\n }\n const cutoff = MAX_STACKTRACE_LENGTH - STACKTRACE_TRUNCATION_SUFFIX.length;\n const lines: string[] = [];\n let length = 0;\n for (const line of text.split(\"\\n\")) {\n if (length + line.length + 1 > cutoff) {\n break;\n }\n lines.push(line);\n length += line.length + 1;\n }\n return lines.join(\"\\n\") + STACKTRACE_TRUNCATION_SUFFIX;\n}\n"],"mappings":";;AAGA,MAAa,0BAA0B;AAEvC,MAAM,aAAa;AACnB,MAAM,sBAAsB;AAC5B,MAAM,kBAAkB;AACxB,MAAM,kBAAkB;AACxB,MAAM,qBAAqB;AAC3B,MAAM,wBAAwB;AAC9B,MAAM,YAAY,KAAK,KAAK;AAC5B,MAAM,4BAA4B;AAClC,MAAM,+BAA+B;AAarC,MAAM,0BAA0B,OAAO,IAAI,4BAA4B;AACvE,MAAM,0BAA0B;AAIhC,MAAM,oBACJ,wBAAwB,4CAA4B,IAAI,IAA8B;AACxF,wBAAwB,2BAA2B;AAEnD,SAAgB,eACd,UACA,QACA,MACA,OACA,eACM;CACN,SAAS,OAAO,YAAY;CAC5B,IAAI,WAAW,aAAa,CAAC,MAC3B;CAEF,MAAM,YAAY,kBAAkB,KAAK;CACzC,MAAM,EAAE,MAAM,SAAS,UACrB,OAAO,cAAc,WACjB;EAAE,MAAM;EAAI,SAAS;EAAW,OAAO;CAAG,IACzC;CACP,MAAM,QAA0B;EAC9B;EACA,MAAM,KAAK,MAAM,GAAG,eAAe;EACnC,MAAM,OAAO,QAAQ,EAAE,CAAC,CAAC,MAAM,GAAG,eAAe;EACjD,SAAS,cAAc,OAAO;EAC9B,YAAY,iBAAiB,KAAK;EAClC,OAAO;CACT;CACA,IAAI,aAAa,KAAA,GACf,MAAM,WAAW,SAAS,MAAM,GAAG,mBAAmB;CAExD,IAAI,kBAAkB,KAAA,GACpB,MAAM,kBAAkB;CAE1B,MAAM,MAAM;EACV,MAAM,YAAY;EAClB,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;CACR,CAAC,CAAC,KAAK,IAAI;CACX,MAAM,WAAW,kBAAkB,IAAI,GAAG;CAC1C,IAAI,UAAU;EACZ,SAAS,QAAQ,KAAK,IAAI,SAAS,QAAQ,GAAG,SAAS;EACvD,SAAS,kBAAkB,MAAM,mBAAmB,SAAS;CAC/D,OAAO,IAAI,kBAAkB,OAAO,YAClC,kBAAkB,IAAI,KAAK,KAAK;AAEpC;AAEA,SAAgB,oBAAmC;CACjD,MAAM,SAAS,CAAC,GAAG,kBAAkB,OAAO,CAAC;CAC7C,kBAAkB,MAAM;CACxB,OAAO;AACT;AAEA,SAAgB,oBAA0B;CACxC,kBAAkB,MAAM;AAC1B;AAEA,SAAS,cAAc,SAA0B;CAC/C,MAAM,OAAO,OAAO,WAAW,EAAE,CAAC,CAAC,KAAK;CACxC,IAAI,KAAK,UAAU,oBACjB,OAAO;CAET,OACE,KAAK,MAAM,GAAG,IAAqD,IAAI;AAE3E;AAGA,SAAS,iBAAiB,OAAwB;CAChD,MAAM,OAAO,OAAO,UAAU,WAAW,MAAM,KAAK,IAAI;CACxD,IAAI,KAAK,UAAU,uBACjB,OAAO;CAET,MAAM,SAAS;CACf,MAAM,QAAkB,CAAC;CACzB,IAAI,SAAS;CACb,KAAK,MAAM,QAAQ,KAAK,MAAM,IAAI,GAAG;EACnC,IAAI,SAAS,KAAK,SAAS,IAAI,QAC7B;EAEF,MAAM,KAAK,IAAI;EACf,UAAU,KAAK,SAAS;CAC1B;CACA,OAAO,MAAM,KAAK,IAAI,IAAI;AAC5B"}
1
+ {"version":3,"file":"serverErrors.js","names":[],"sources":["../src/serverErrors.ts"],"sourcesContent":["import type { AnyValueMap } from \"@opentelemetry/api-logs\";\nimport { coerceToException } from \"./exceptions.js\";\n\nexport const SERVER_ERROR_EVENT_NAME = \"apitally.request.server_error\";\n\nconst MAX_ERRORS = 100;\nconst MAX_CONSUMER_LENGTH = 128;\nconst MAX_PATH_LENGTH = 2_000;\nconst MAX_TYPE_LENGTH = 256;\nconst MAX_MESSAGE_LENGTH = 2_048;\nconst MAX_STACKTRACE_LENGTH = 65_536;\nconst MESSAGE_TRUNCATION_SUFFIX = \"... (truncated)\";\nconst STACKTRACE_TRUNCATION_SUFFIX = \"\\n... (truncated) ...\";\n\ntype ServerErrorAggregate = {\n method: string;\n path: string;\n type: string;\n message: string;\n stacktrace: string;\n sentry_event_id?: string;\n counts: Map<string | undefined, number>;\n};\n\nconst SERVER_ERROR_AGGREGATES_KEY = Symbol.for(\"apitally.serverErrorAggregates\");\nconst serverErrorAggregatesHolder = globalThis as Record<\n symbol,\n Map<string, ServerErrorAggregate> | undefined\n>;\nconst serverErrorAggregates =\n serverErrorAggregatesHolder[SERVER_ERROR_AGGREGATES_KEY] ??\n new Map<string, ServerErrorAggregate>();\nserverErrorAggregatesHolder[SERVER_ERROR_AGGREGATES_KEY] = serverErrorAggregates;\n\nexport function addServerError(\n consumer: string | undefined,\n method: string,\n path: string,\n error: unknown,\n sentryEventId: string | undefined,\n): void {\n method = method.toUpperCase();\n if (method === \"OPTIONS\" || !path) {\n return;\n }\n const exception = coerceToException(error);\n const { name, message, stack } =\n typeof exception === \"string\"\n ? { name: \"\", message: exception, stack: \"\" }\n : (exception as { name?: unknown; message?: unknown; stack?: unknown });\n const fields = {\n method,\n path: path.slice(0, MAX_PATH_LENGTH),\n type: String(name ?? \"\").slice(0, MAX_TYPE_LENGTH),\n message: formatMessage(message),\n stacktrace: formatStacktrace(stack),\n };\n const key = Object.values(fields).join(\"\\0\");\n let aggregate = serverErrorAggregates.get(key);\n if (!aggregate) {\n if (serverErrorAggregates.size >= MAX_ERRORS) {\n return;\n }\n aggregate = { ...fields, counts: new Map() };\n serverErrorAggregates.set(key, aggregate);\n }\n consumer = consumer?.slice(0, MAX_CONSUMER_LENGTH);\n aggregate.counts.set(consumer, (aggregate.counts.get(consumer) ?? 0) + 1);\n if (sentryEventId !== undefined) {\n aggregate.sentry_event_id = sentryEventId;\n }\n}\n\nexport function drainServerErrors(): AnyValueMap[] {\n const aggregates = [...serverErrorAggregates.values()];\n serverErrorAggregates.clear();\n return aggregates.map(({ counts, ...fields }) => ({\n ...fields,\n counts: [...counts].map(([consumer, count]) =>\n consumer === undefined ? { count } : { consumer, count },\n ),\n }));\n}\n\nexport function resetServerErrors(): void {\n serverErrorAggregates.clear();\n}\n\nfunction formatMessage(message: unknown): string {\n const text = String(message ?? \"\").trim();\n if (text.length <= MAX_MESSAGE_LENGTH) {\n return text;\n }\n return (\n text.slice(0, MAX_MESSAGE_LENGTH - MESSAGE_TRUNCATION_SUFFIX.length) + MESSAGE_TRUNCATION_SUFFIX\n );\n}\n\n// The error line and innermost frames come first in a JS stack, so the head is kept.\nfunction formatStacktrace(stack: unknown): string {\n const text = typeof stack === \"string\" ? stack.trim() : \"\";\n if (text.length <= MAX_STACKTRACE_LENGTH) {\n return text;\n }\n const cutoff = MAX_STACKTRACE_LENGTH - STACKTRACE_TRUNCATION_SUFFIX.length;\n const lines: string[] = [];\n let length = 0;\n for (const line of text.split(\"\\n\")) {\n if (length + line.length + 1 > cutoff) {\n break;\n }\n lines.push(line);\n length += line.length + 1;\n }\n return lines.join(\"\\n\") + STACKTRACE_TRUNCATION_SUFFIX;\n}\n"],"mappings":";;AAGA,MAAa,0BAA0B;AAEvC,MAAM,aAAa;AACnB,MAAM,sBAAsB;AAC5B,MAAM,kBAAkB;AACxB,MAAM,kBAAkB;AACxB,MAAM,qBAAqB;AAC3B,MAAM,wBAAwB;AAC9B,MAAM,4BAA4B;AAClC,MAAM,+BAA+B;AAYrC,MAAM,8BAA8B,OAAO,IAAI,gCAAgC;AAC/E,MAAM,8BAA8B;AAIpC,MAAM,wBACJ,4BAA4B,gDAC5B,IAAI,IAAkC;AACxC,4BAA4B,+BAA+B;AAE3D,SAAgB,eACd,UACA,QACA,MACA,OACA,eACM;CACN,SAAS,OAAO,YAAY;CAC5B,IAAI,WAAW,aAAa,CAAC,MAC3B;CAEF,MAAM,YAAY,kBAAkB,KAAK;CACzC,MAAM,EAAE,MAAM,SAAS,UACrB,OAAO,cAAc,WACjB;EAAE,MAAM;EAAI,SAAS;EAAW,OAAO;CAAG,IACzC;CACP,MAAM,SAAS;EACb;EACA,MAAM,KAAK,MAAM,GAAG,eAAe;EACnC,MAAM,OAAO,QAAQ,EAAE,CAAC,CAAC,MAAM,GAAG,eAAe;EACjD,SAAS,cAAc,OAAO;EAC9B,YAAY,iBAAiB,KAAK;CACpC;CACA,MAAM,MAAM,OAAO,OAAO,MAAM,CAAC,CAAC,KAAK,IAAI;CAC3C,IAAI,YAAY,sBAAsB,IAAI,GAAG;CAC7C,IAAI,CAAC,WAAW;EACd,IAAI,sBAAsB,QAAQ,YAChC;EAEF,YAAY;GAAE,GAAG;GAAQ,wBAAQ,IAAI,IAAI;EAAE;EAC3C,sBAAsB,IAAI,KAAK,SAAS;CAC1C;CACA,WAAW,UAAU,MAAM,GAAG,mBAAmB;CACjD,UAAU,OAAO,IAAI,WAAW,UAAU,OAAO,IAAI,QAAQ,KAAK,KAAK,CAAC;CACxE,IAAI,kBAAkB,KAAA,GACpB,UAAU,kBAAkB;AAEhC;AAEA,SAAgB,oBAAmC;CACjD,MAAM,aAAa,CAAC,GAAG,sBAAsB,OAAO,CAAC;CACrD,sBAAsB,MAAM;CAC5B,OAAO,WAAW,KAAK,EAAE,QAAQ,GAAG,cAAc;EAChD,GAAG;EACH,QAAQ,CAAC,GAAG,MAAM,CAAC,CAAC,KAAK,CAAC,UAAU,WAClC,aAAa,KAAA,IAAY,EAAE,MAAM,IAAI;GAAE;GAAU;EAAM,CACzD;CACF,EAAE;AACJ;AAEA,SAAgB,oBAA0B;CACxC,sBAAsB,MAAM;AAC9B;AAEA,SAAS,cAAc,SAA0B;CAC/C,MAAM,OAAO,OAAO,WAAW,EAAE,CAAC,CAAC,KAAK;CACxC,IAAI,KAAK,UAAU,oBACjB,OAAO;CAET,OACE,KAAK,MAAM,GAAG,IAAqD,IAAI;AAE3E;AAGA,SAAS,iBAAiB,OAAwB;CAChD,MAAM,OAAO,OAAO,UAAU,WAAW,MAAM,KAAK,IAAI;CACxD,IAAI,KAAK,UAAU,uBACjB,OAAO;CAET,MAAM,SAAS;CACf,MAAM,QAAkB,CAAC;CACzB,IAAI,SAAS;CACb,KAAK,MAAM,QAAQ,KAAK,MAAM,IAAI,GAAG;EACnC,IAAI,SAAS,KAAK,SAAS,IAAI,QAC7B;EAEF,MAAM,KAAK,IAAI;EACf,UAAU,KAAK,SAAS;CAC1B;CACA,OAAO,MAAM,KAAK,IAAI,IAAI;AAC5B"}
@@ -2,7 +2,6 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_logger = require("./logger.cjs");
3
3
  const require_config = require("./config.cjs");
4
4
  const require_context = require("./context.cjs");
5
- const require_consumer = require("./consumer.cjs");
6
5
  let _opentelemetry_api = require("@opentelemetry/api");
7
6
  let _opentelemetry_core = require("@opentelemetry/core");
8
7
  //#region src/spanProcessor.ts
@@ -237,7 +236,6 @@ var SpanPipeline = class {
237
236
  if (handle) handle.span = span;
238
237
  const record = parentContext.getValue(require_context.REQUEST_RECORD_KEY);
239
238
  if (record) record.serverSpanId = spanId;
240
- require_consumer.writeConsumerAttributesFromContext(parentContext, span, record);
241
239
  writeUrlAttributesFromFullUrl(span);
242
240
  const dropReason = this.resolveRequestDropReasonBeforeSampling(span.attributes) ?? (this.isRequestSampledIn(span) ? void 0 : "sampled-out");
243
241
  if (dropReason) {
@@ -1 +1 @@
1
- {"version":3,"file":"spanProcessor.cjs","names":["compilePatterns","EXCLUDE_USER_AGENTS","SpanKind","getConfig","DEFAULT_EXCLUDE_PATHS","matchesAny","SPAN_HANDLE_KEY","REQUEST_RECORD_KEY","hrTime","hrTimeDuration"],"sources":["../src/spanProcessor.ts"],"sourcesContent":["import { type Attributes, type Context, SpanKind } from \"@opentelemetry/api\";\nimport { hrTime, hrTimeDuration } from \"@opentelemetry/core\";\nimport type { ReadableSpan, Span, SpanProcessor } from \"@opentelemetry/sdk-trace-base\";\nimport {\n type ApitallyConfig,\n compilePatterns,\n DEFAULT_EXCLUDE_PATHS,\n EXCLUDE_USER_AGENTS,\n getConfig,\n matchesAny,\n type SamplingCallback,\n} from \"./config.js\";\nimport { writeConsumerAttributesFromContext } from \"./consumer.js\";\nimport {\n REQUEST_RECORD_KEY,\n type RequestDropReason,\n type RequestRecord,\n SPAN_HANDLE_KEY,\n type SpanHandle,\n} from \"./context.js\";\nimport { logDebug, logWarning } from \"./logger.js\";\n\nconst MAX_BUFFERED_SPANS = 1_000;\nconst MAX_TRACKED_SPAN_IDS = MAX_BUFFERED_SPANS + 1;\nconst MAX_STASHED_REQUESTS = 2_048;\nconst MAX_KEPT_SPAN_IDS = 10_000;\nconst EXCLUDE_USER_AGENT_PATTERNS = compilePatterns(EXCLUDE_USER_AGENTS);\n\n// Transport-captured headers and bodies are attached only to Apitally's export\n// copy.\nexport interface RequestStash {\n requestHeaders?: Record<string, string | string[]>;\n requestBody?: Buffer;\n requestContentEncoding?: string;\n responseHeaders?: Record<string, string | string[]>;\n responseBody?: Buffer;\n responseContentEncoding?: string;\n}\n\nexport interface ApitallySpanData {\n record?: RequestRecord;\n stash?: RequestStash;\n demoteToInternal?: boolean;\n}\n\n// Mutable ReadableSpan-shaped copy on Apitally's private export path; the span\n// handed to user-attached processors is never mutated.\nexport type SpanCopy = {\n -readonly [Key in keyof ReadableSpan]: ReadableSpan[Key];\n} & { apitallyData?: ApitallySpanData };\n\n// The public processor delegates to the process-global pipeline. Construction\n// only declares that the application owns the tracer provider.\nexport class ApitallySpanProcessor implements SpanProcessor {\n constructor() {\n setApitallySpanProcessorDeclared();\n }\n\n onStart(span: Span, parentContext: Context): void {\n let pipeline = getActiveSpanPipeline();\n if (!pipeline && span.kind === SpanKind.SERVER) {\n getServerSpanActivationCallback()?.();\n pipeline = getActiveSpanPipeline();\n }\n pipeline?.onStart(span, parentContext);\n }\n\n onEnd(span: ReadableSpan): void {\n getActiveSpanPipeline()?.onEnd(span);\n }\n\n // Flush failures resolve instead of rejecting into the user's provider.\n forceFlush(): Promise<void> {\n const pipeline = getActiveSpanPipeline();\n if (!pipeline) {\n return Promise.resolve();\n }\n return pipeline.forceFlush().catch((error: unknown) => {\n logDebug(`Error flushing spans: ${String(error)}`);\n });\n }\n\n // A user provider's shutdown only flushes released requests; SDK shutdown owns\n // teardown.\n shutdown(): Promise<void> {\n return this.forceFlush();\n }\n}\n\ntype ServerSpanActivationCallback = () => void;\n\n// Symbol.for keys let ESM and CJS builds share processor coordination.\nconst ACTIVE_SPAN_PIPELINE_KEY = Symbol.for(\"apitally.activeSpanPipeline\");\nconst APITALLY_SPAN_PROCESSOR_DECLARED_KEY = Symbol.for(\"apitally.spanProcessorDeclared\");\nconst SERVER_SPAN_ACTIVATION_CALLBACK_KEY = Symbol.for(\"apitally.serverSpanActivationCallback\");\n\nexport function setActiveSpanPipeline(pipeline: SpanPipeline | undefined): void {\n (globalThis as Record<symbol, SpanPipeline | undefined>)[ACTIVE_SPAN_PIPELINE_KEY] = pipeline;\n}\n\nexport function getActiveSpanPipeline(): SpanPipeline | undefined {\n return (globalThis as Record<symbol, SpanPipeline | undefined>)[ACTIVE_SPAN_PIPELINE_KEY];\n}\n\nexport function setServerSpanActivationCallback(callback: ServerSpanActivationCallback): void {\n const holder = globalThis as Record<symbol, ServerSpanActivationCallback | undefined>;\n holder[SERVER_SPAN_ACTIVATION_CALLBACK_KEY] ??= callback;\n}\n\nexport function isApitallySpanProcessorDeclared(): boolean {\n return (\n (globalThis as Record<symbol, boolean | undefined>)[APITALLY_SPAN_PROCESSOR_DECLARED_KEY] ===\n true\n );\n}\n\nexport function resetSpanProcessorState(): void {\n const holder = globalThis as Record<symbol, unknown>;\n delete holder[ACTIVE_SPAN_PIPELINE_KEY];\n delete holder[APITALLY_SPAN_PROCESSOR_DECLARED_KEY];\n delete holder[SERVER_SPAN_ACTIVATION_CALLBACK_KEY];\n}\n\nfunction setApitallySpanProcessorDeclared(): void {\n (globalThis as Record<symbol, boolean>)[APITALLY_SPAN_PROCESSOR_DECLARED_KEY] = true;\n}\n\nfunction getServerSpanActivationCallback(): ServerSpanActivationCallback | undefined {\n return (globalThis as Record<symbol, ServerSpanActivationCallback | undefined>)[\n SERVER_SPAN_ACTIVATION_CALLBACK_KEY\n ];\n}\n\ninterface RequestEntry {\n readonly serverSpanId: string;\n readonly serverSpan: Span;\n readonly spanIds: Set<string>;\n record?: RequestRecord;\n buffered: ReadableSpan[];\n endedServerSpan?: ReadableSpan;\n transportCompleted: boolean;\n released: boolean;\n}\n\ninterface KeptSpanEntry {\n readonly serverSpanId: string;\n // Carries the demotion decision across release for spans that end late.\n readonly demoted: boolean;\n}\n\n// Requests remain buffered until the SERVER span and transport complete, then\n// one keep/drop decision releases them once.\nexport class SpanPipeline implements SpanProcessor {\n // Callbacks are optional because metrics and log pipelines start at activation.\n metricsRecorder?: (record: RequestRecord) => void;\n onRequestFinished?: (serverSpanId: string, kept: boolean) => void;\n private readonly downstream: SpanProcessor;\n private readonly config: ApitallyConfig;\n private readonly sampleRateBound: bigint;\n private readonly excludePathPatterns: RegExp[];\n // Every span ID remains mapped to one request until completion so late logs\n // resolve. A miss means dropped, completed, or non-request telemetry.\n private readonly requests = new Map<string, RequestEntry>();\n private readonly stash = new Map<string, RequestStash>();\n private readonly demotedSpanIds = new Set<string>();\n // Kept span IDs remain resolvable after release for late spans and logs; the\n // oldest are evicted at the cap.\n private readonly keptSpanIds = new Map<string, KeptSpanEntry>();\n\n constructor(\n downstream: SpanProcessor,\n private readonly flushExporter?: () => Promise<void>,\n ) {\n this.downstream = downstream;\n this.config = getConfig();\n this.sampleRateBound = boundForSampleRate(this.config.sampleRate);\n this.excludePathPatterns = compilePatterns(DEFAULT_EXCLUDE_PATHS, this.config.excludePaths);\n }\n\n onStart(span: Span, parentContext: Context): void {\n try {\n if (isContribPerMessageSpan(span)) {\n return;\n }\n const parent = span.parentSpanContext;\n if (!parent || parent.isRemote) {\n if (span.kind === SpanKind.SERVER) {\n this.startRequest(span, parentContext);\n }\n return;\n }\n const entry = this.requests.get(parent.spanId);\n const spanId = span.spanContext().spanId;\n if (!entry) {\n // A span started under a request already released as kept exports at\n // its end, like the released request's other late telemetry.\n const kept = this.keptSpanIds.get(parent.spanId);\n if (kept) {\n this.addKeptSpanId(spanId, {\n serverSpanId: kept.serverSpanId,\n demoted: false,\n });\n }\n return;\n }\n if (entry.spanIds.size >= MAX_TRACKED_SPAN_IDS) {\n logDebug(\"Apitally span tracking cap reached, dropping the span\");\n return;\n }\n if (span.kind === SpanKind.SERVER) {\n // A second middleware produced a SERVER span for this request. Apitally\n // demotes its copy, but user exporters retain the duplicate.\n this.demotedSpanIds.add(spanId);\n logWarning(\n `Detected a duplicate SERVER span produced by the instrumentation scope \"${span.instrumentationScope?.name ?? \"unknown\"}\" inside an active request. Apitally exports it as an INTERNAL span, but your own OpenTelemetry exporters still receive the duplicate. To resolve this, remove the middleware that produces it.`,\n );\n }\n this.requests.set(spanId, entry);\n entry.spanIds.add(spanId);\n } catch (error) {\n logWarning(`Error in the Apitally span processor: ${String(error)}`);\n }\n }\n\n onEnd(span: ReadableSpan): void {\n try {\n const spanId = span.spanContext().spanId;\n const isDemoted = this.demotedSpanIds.delete(spanId);\n const entry = this.requests.get(spanId);\n if (!entry) {\n const kept = this.keptSpanIds.get(spanId);\n if (kept) {\n let exportSpan = span;\n if (kept.demoted) {\n const copy = copySpan(span);\n copy.apitallyData = { demoteToInternal: true };\n exportSpan = copy;\n }\n this.downstream.onEnd(exportSpan);\n }\n return;\n }\n if (spanId === entry.serverSpanId) {\n if (!entry.record) {\n this.removeCompletedRequestSpanIds(entry);\n this.stash.delete(entry.serverSpanId);\n this.onRequestFinished?.(entry.serverSpanId, false);\n return;\n }\n entry.endedServerSpan = span;\n this.releaseIfComplete(entry);\n return;\n }\n // The span id stays mapped so log records emitted after this span ended\n // still resolve to the request until it completes.\n let exportSpan = span;\n if (isDemoted) {\n const copy = copySpan(span);\n copy.apitallyData = { demoteToInternal: true };\n exportSpan = copy;\n }\n if (entry.buffered.length < MAX_BUFFERED_SPANS) {\n entry.buffered.push(exportSpan);\n } else {\n logDebug(\"Apitally span buffer cap reached, dropping the span\");\n }\n } catch (error) {\n logWarning(`Error in the Apitally span processor: ${String(error)}`);\n }\n }\n\n attachRequestRecord(serverSpanId: string, record: RequestRecord): void {\n const entry = this.requests.get(serverSpanId);\n if (entry) {\n entry.record ??= record;\n }\n }\n\n // Transport completion triggers response sampling and metrics independently\n // of span-end timing. Map misses still record metrics and discard other data.\n handleTransportCompletion(record: RequestRecord): void {\n try {\n record.dropReason = resolveTransportDropReason(record.attributes) ?? record.dropReason;\n const entry =\n record.serverSpanId !== undefined ? this.requests.get(record.serverSpanId) : undefined;\n if (entry && !entry.transportCompleted && !entry.released) {\n entry.record ??= record;\n entry.transportCompleted = true;\n if (!this.isResponseSampledIn(entry)) {\n this.dropRequestOnResponse(entry, record);\n }\n }\n this.metricsRecorder?.(record);\n if (entry) {\n this.releaseIfComplete(entry);\n }\n } catch (error) {\n logWarning(`Error in the Apitally span processor: ${String(error)}`);\n }\n }\n\n // Holds captured headers and bodies until the exporter attaches them to the\n // exported SERVER span copy. Fields already stashed are kept unless replaced.\n updateStash(serverSpanId: string, update: RequestStash): void {\n try {\n // A request without an in-flight map entry can never release, so its\n // stash entry would sit unconsumed until the cap evicts it.\n if (!this.requests.has(serverSpanId)) {\n return;\n }\n let entry = this.stash.get(serverSpanId);\n if (!entry) {\n if (this.stash.size >= MAX_STASHED_REQUESTS) {\n const oldestKey = this.stash.keys().next().value;\n if (oldestKey !== undefined) {\n this.stash.delete(oldestKey);\n logDebug(\"Apitally payload stash cap reached, dropping the oldest entry\");\n }\n }\n entry = {};\n this.stash.set(serverSpanId, entry);\n }\n if (update.requestHeaders !== undefined) {\n entry.requestHeaders = update.requestHeaders;\n }\n if (update.requestBody !== undefined) {\n entry.requestBody = update.requestBody;\n }\n if (update.requestContentEncoding !== undefined) {\n entry.requestContentEncoding = update.requestContentEncoding;\n }\n if (update.responseHeaders !== undefined) {\n entry.responseHeaders = update.responseHeaders;\n }\n if (update.responseBody !== undefined) {\n entry.responseBody = update.responseBody;\n }\n if (update.responseContentEncoding !== undefined) {\n entry.responseContentEncoding = update.responseContentEncoding;\n }\n } catch (error) {\n logDebug(`Error updating the request stash: ${String(error)}`);\n }\n }\n\n // Kept requests remain resolvable after release so late logs retain their\n // request association.\n resolveServerSpanId(spanId: string): string | undefined {\n return this.requests.get(spanId)?.serverSpanId ?? this.keptSpanIds.get(spanId)?.serverSpanId;\n }\n\n isRequestInFlight(serverSpanId: string): boolean {\n return this.requests.has(serverSpanId);\n }\n\n // Exclusion answers \"never wanted\" and runs strictly before sampling; an\n // excluded request never invokes a user sampling callback.\n resolveRequestDropReasonBeforeSampling(attributes: Attributes): RequestDropReason | undefined {\n const transportDropReason = resolveTransportDropReason(attributes);\n if (transportDropReason !== undefined) {\n return transportDropReason;\n }\n const path = attributes[\"url.path\"] ?? attributes[\"http.target\"];\n if (typeof path === \"string\" && matchesAny(this.excludePathPatterns, path.split(\"?\")[0])) {\n return \"excluded\";\n }\n const userAgent = attributes[\"user_agent.original\"] ?? attributes[\"http.user_agent\"];\n if (typeof userAgent === \"string\" && matchesAny(EXCLUDE_USER_AGENT_PATTERNS, userAgent)) {\n return \"excluded\";\n }\n return undefined;\n }\n\n async forceFlush(): Promise<void> {\n await this.downstream.forceFlush();\n // OTel flushes queued batches but does not await already-running exports.\n await this.flushExporter?.();\n }\n\n // Shutdown releases requests with completed transport observation once and\n // discards incomplete requests, which cannot complete afterward.\n async shutdown(): Promise<void> {\n try {\n for (const entry of new Set(this.requests.values())) {\n if (!entry.released && entry.transportCompleted) {\n this.releaseRequest(entry, entry.endedServerSpan ?? entry.serverSpan);\n }\n }\n this.requests.clear();\n this.stash.clear();\n this.demotedSpanIds.clear();\n this.keptSpanIds.clear();\n } catch (error) {\n logWarning(`Error in the Apitally span processor: ${String(error)}`);\n }\n await this.downstream.shutdown();\n }\n\n private startRequest(span: Span, parentContext: Context): void {\n const spanId = span.spanContext().spanId;\n // The handle is filled for every local-root SERVER span, independent of the\n // keep decision, so runtime writes always reach the current request's span.\n const handle = parentContext.getValue(SPAN_HANDLE_KEY) as SpanHandle | undefined;\n if (handle) {\n handle.span = span;\n }\n const record = parentContext.getValue(REQUEST_RECORD_KEY) as RequestRecord | undefined;\n if (record) {\n record.serverSpanId = spanId;\n }\n writeConsumerAttributesFromContext(parentContext, span, record);\n writeUrlAttributesFromFullUrl(span);\n const dropReason =\n this.resolveRequestDropReasonBeforeSampling(span.attributes) ??\n (this.isRequestSampledIn(span) ? undefined : \"sampled-out\");\n if (dropReason) {\n if (record) {\n record.dropReason = dropReason;\n }\n return;\n }\n this.requests.set(spanId, {\n serverSpanId: spanId,\n serverSpan: span,\n spanIds: new Set([spanId]),\n record,\n buffered: [],\n transportCompleted: false,\n released: false,\n });\n }\n\n private isRequestSampledIn(span: Span): boolean {\n const callback = this.config.sampleOnRequest;\n const rate = callback\n ? resolveCallbackSampleRate(callback, span, \"sampleOnRequest\")\n : undefined;\n const bound = rate === undefined ? this.sampleRateBound : boundForSampleRate(rate);\n return isTraceSampledIn(span.spanContext().traceId, bound);\n }\n\n // Abstention leaves the request-stage decision standing; it never re-tests the\n // static sample rate.\n private isResponseSampledIn(entry: RequestEntry): boolean {\n const callback = this.config.sampleOnResponse;\n if (!callback) {\n return true;\n }\n const serverSpan = entry.endedServerSpan ?? entry.serverSpan;\n let snapshot: ReadableSpan = serverSpan;\n if (entry.record && Object.keys(entry.record.attributes).length > 0) {\n // The callback sees transport-observed values even when they were learned\n // after the span ended (final route, response size).\n const copy = copySpan(serverSpan);\n copy.attributes = {\n ...serverSpan.attributes,\n ...entry.record.attributes,\n };\n snapshot = copy;\n }\n const rate = resolveCallbackSampleRate(callback, snapshot, \"sampleOnResponse\");\n if (rate === undefined) {\n return true;\n }\n return isTraceSampledIn(serverSpan.spanContext().traceId, boundForSampleRate(rate));\n }\n\n private dropRequestOnResponse(entry: RequestEntry, record: RequestRecord): void {\n // Removing every span id sends the dropped request's late telemetry to the\n // lookup-miss rule, so it is discarded locally.\n entry.released = true;\n entry.buffered = [];\n record.dropReason = \"sampled-out\";\n if (entry.record) {\n entry.record.dropReason = \"sampled-out\";\n }\n this.removeCompletedRequestSpanIds(entry);\n this.stash.delete(entry.serverSpanId);\n this.onRequestFinished?.(entry.serverSpanId, false);\n }\n\n private releaseIfComplete(entry: RequestEntry): void {\n if (entry.released || !entry.transportCompleted || !entry.endedServerSpan) {\n return;\n }\n this.releaseRequest(entry, entry.endedServerSpan);\n }\n\n // Descendants, the SERVER span, and logs enter downstream processing once, in\n // that order. The exporter applies the request record and stash later.\n private releaseRequest(entry: RequestEntry, serverSpan: ReadableSpan): void {\n entry.released = true;\n for (const spanId of entry.spanIds) {\n this.requests.delete(spanId);\n this.addKeptSpanId(spanId, {\n serverSpanId: entry.serverSpanId,\n demoted: this.demotedSpanIds.delete(spanId),\n });\n }\n for (const bufferedSpan of entry.buffered) {\n this.downstream.onEnd(bufferedSpan);\n }\n entry.buffered = [];\n const stash = this.stash.get(entry.serverSpanId);\n this.stash.delete(entry.serverSpanId);\n let exportSpan = serverSpan;\n if (entry.record || stash || !serverSpan.ended) {\n const copy = copySpan(serverSpan);\n if (!serverSpan.ended) {\n // A SERVER span released during shutdown uses shutdown as its end time.\n copy.endTime = hrTime();\n copy.duration = hrTimeDuration(copy.startTime, copy.endTime);\n copy.ended = true;\n }\n copy.apitallyData = { record: entry.record, stash };\n exportSpan = copy;\n }\n this.downstream.onEnd(exportSpan);\n this.onRequestFinished?.(entry.serverSpanId, true);\n }\n\n private removeCompletedRequestSpanIds(entry: RequestEntry): void {\n for (const spanId of entry.spanIds) {\n this.requests.delete(spanId);\n this.demotedSpanIds.delete(spanId);\n }\n }\n\n private addKeptSpanId(spanId: string, kept: KeptSpanEntry): void {\n if (this.keptSpanIds.size >= MAX_KEPT_SPAN_IDS) {\n const oldestId = this.keptSpanIds.keys().next().value;\n if (oldestId !== undefined) {\n this.keptSpanIds.delete(oldestId);\n }\n }\n this.keptSpanIds.set(spanId, kept);\n }\n}\n\nexport function copySpan(span: ReadableSpan): SpanCopy {\n const spanContext = span.spanContext();\n return {\n name: span.name,\n kind: span.kind,\n spanContext: () => spanContext,\n parentSpanContext: span.parentSpanContext,\n startTime: span.startTime,\n endTime: span.endTime,\n status: span.status,\n attributes: span.attributes,\n links: span.links,\n events: span.events,\n duration: span.duration,\n ended: span.ended,\n resource: span.resource,\n instrumentationScope: span.instrumentationScope,\n droppedAttributesCount: span.droppedAttributesCount,\n droppedEventsCount: span.droppedEventsCount,\n droppedLinksCount: span.droppedLinksCount,\n };\n}\n\nfunction resolveTransportDropReason(attributes: Attributes): RequestDropReason | undefined {\n const method = attributes[\"http.request.method\"] ?? attributes[\"http.method\"];\n if (method === \"OPTIONS\") {\n return \"method\";\n }\n const scheme = attributes[\"url.scheme\"] ?? attributes[\"http.scheme\"];\n return scheme === \"ws\" || scheme === \"wss\" ? \"scheme\" : undefined;\n}\n\n// Missing path, query, and target attributes are derived from the full URL\n// because exclusion, display, and redaction require them.\nfunction writeUrlAttributesFromFullUrl(span: Span): void {\n const attributes = span.attributes;\n if (attributes[\"url.path\"] !== undefined || attributes[\"http.target\"] !== undefined) {\n return;\n }\n const url = attributes[\"url.full\"] ?? attributes[\"http.url\"];\n if (typeof url !== \"string\") {\n return;\n }\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return;\n }\n const query = parsed.search.replace(/^\\?/, \"\");\n span.setAttribute(\"url.path\", parsed.pathname);\n if (query) {\n span.setAttribute(\"url.query\", query);\n }\n span.setAttribute(\"http.target\", query ? `${parsed.pathname}?${query}` : parsed.pathname);\n}\n\nconst TRACE_ID_LOW_64_BITS_MASK = (1n << 64n) - 1n;\n\nfunction boundForSampleRate(rate: number): bigint {\n return BigInt(Math.round(rate * 2 ** 64));\n}\n\n// Low 64-bit ratio sampling is deterministic per trace. Comparing the same\n// value at both stages makes the lower rate decisive.\nfunction isTraceSampledIn(traceId: string, bound: bigint): boolean {\n return (BigInt(`0x${traceId}`) & TRACE_ID_LOW_64_BITS_MASK) < bound;\n}\n\n// A throwing or invalid-returning callback resolves to keep: a user bug must\n// never lose data without a warning. Undefined means the callback abstained.\nfunction resolveCallbackSampleRate(\n callback: SamplingCallback,\n span: ReadableSpan,\n optionName: string,\n): number | undefined {\n let result: unknown;\n try {\n result = callback(span);\n } catch {\n logWarning(`The Apitally ${optionName} callback threw an error, so the request was captured`);\n return 1;\n }\n if (result === undefined || result === null) {\n return undefined;\n }\n if (typeof result === \"boolean\") {\n return result ? 1 : 0;\n }\n if (typeof result === \"number\" && result >= 0 && result <= 1) {\n return result;\n }\n logWarning(\n `The Apitally ${optionName} callback returned an invalid value, so the request was captured. Sampling callbacks must synchronously return a number between 0 and 1, a boolean, or undefined.`,\n );\n return 1;\n}\n\nfunction isContribPerMessageSpan(span: Span): boolean {\n const scopeName = span.instrumentationScope?.name ?? \"\";\n return (\n span.kind === SpanKind.INTERNAL &&\n [\" http send\", \" http receive\", \" websocket send\", \" websocket receive\"].some((suffix) =>\n span.name.endsWith(suffix),\n ) &&\n (scopeName.startsWith(\"@opentelemetry/instrumentation\") ||\n scopeName.startsWith(\"opentelemetry.instrumentation.\"))\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"spanProcessor.cjs","names":["compilePatterns","EXCLUDE_USER_AGENTS","SpanKind","getConfig","DEFAULT_EXCLUDE_PATHS","matchesAny","SPAN_HANDLE_KEY","REQUEST_RECORD_KEY","hrTime","hrTimeDuration"],"sources":["../src/spanProcessor.ts"],"sourcesContent":["import { type Attributes, type Context, SpanKind } from \"@opentelemetry/api\";\nimport { hrTime, hrTimeDuration } from \"@opentelemetry/core\";\nimport type { ReadableSpan, Span, SpanProcessor } from \"@opentelemetry/sdk-trace-base\";\nimport {\n type ApitallyConfig,\n compilePatterns,\n DEFAULT_EXCLUDE_PATHS,\n EXCLUDE_USER_AGENTS,\n getConfig,\n matchesAny,\n type SamplingCallback,\n} from \"./config.js\";\nimport {\n REQUEST_RECORD_KEY,\n type RequestDropReason,\n type RequestRecord,\n SPAN_HANDLE_KEY,\n type SpanHandle,\n} from \"./context.js\";\nimport { logDebug, logWarning } from \"./logger.js\";\n\nconst MAX_BUFFERED_SPANS = 1_000;\nconst MAX_TRACKED_SPAN_IDS = MAX_BUFFERED_SPANS + 1;\nconst MAX_STASHED_REQUESTS = 2_048;\nconst MAX_KEPT_SPAN_IDS = 10_000;\nconst EXCLUDE_USER_AGENT_PATTERNS = compilePatterns(EXCLUDE_USER_AGENTS);\n\n// Transport-captured headers and bodies are attached only to Apitally's export\n// copy.\nexport interface RequestStash {\n requestHeaders?: Record<string, string | string[]>;\n requestBody?: Buffer;\n requestContentEncoding?: string;\n responseHeaders?: Record<string, string | string[]>;\n responseBody?: Buffer;\n responseContentEncoding?: string;\n}\n\nexport interface ApitallySpanData {\n record?: RequestRecord;\n stash?: RequestStash;\n demoteToInternal?: boolean;\n}\n\n// Mutable ReadableSpan-shaped copy on Apitally's private export path; the span\n// handed to user-attached processors is never mutated.\nexport type SpanCopy = {\n -readonly [Key in keyof ReadableSpan]: ReadableSpan[Key];\n} & { apitallyData?: ApitallySpanData };\n\n// The public processor delegates to the process-global pipeline. Construction\n// only declares that the application owns the tracer provider.\nexport class ApitallySpanProcessor implements SpanProcessor {\n constructor() {\n setApitallySpanProcessorDeclared();\n }\n\n onStart(span: Span, parentContext: Context): void {\n let pipeline = getActiveSpanPipeline();\n if (!pipeline && span.kind === SpanKind.SERVER) {\n getServerSpanActivationCallback()?.();\n pipeline = getActiveSpanPipeline();\n }\n pipeline?.onStart(span, parentContext);\n }\n\n onEnd(span: ReadableSpan): void {\n getActiveSpanPipeline()?.onEnd(span);\n }\n\n // Flush failures resolve instead of rejecting into the user's provider.\n forceFlush(): Promise<void> {\n const pipeline = getActiveSpanPipeline();\n if (!pipeline) {\n return Promise.resolve();\n }\n return pipeline.forceFlush().catch((error: unknown) => {\n logDebug(`Error flushing spans: ${String(error)}`);\n });\n }\n\n // A user provider's shutdown only flushes released requests; SDK shutdown owns\n // teardown.\n shutdown(): Promise<void> {\n return this.forceFlush();\n }\n}\n\ntype ServerSpanActivationCallback = () => void;\n\n// Symbol.for keys let ESM and CJS builds share processor coordination.\nconst ACTIVE_SPAN_PIPELINE_KEY = Symbol.for(\"apitally.activeSpanPipeline\");\nconst APITALLY_SPAN_PROCESSOR_DECLARED_KEY = Symbol.for(\"apitally.spanProcessorDeclared\");\nconst SERVER_SPAN_ACTIVATION_CALLBACK_KEY = Symbol.for(\"apitally.serverSpanActivationCallback\");\n\nexport function setActiveSpanPipeline(pipeline: SpanPipeline | undefined): void {\n (globalThis as Record<symbol, SpanPipeline | undefined>)[ACTIVE_SPAN_PIPELINE_KEY] = pipeline;\n}\n\nexport function getActiveSpanPipeline(): SpanPipeline | undefined {\n return (globalThis as Record<symbol, SpanPipeline | undefined>)[ACTIVE_SPAN_PIPELINE_KEY];\n}\n\nexport function setServerSpanActivationCallback(callback: ServerSpanActivationCallback): void {\n const holder = globalThis as Record<symbol, ServerSpanActivationCallback | undefined>;\n holder[SERVER_SPAN_ACTIVATION_CALLBACK_KEY] ??= callback;\n}\n\nexport function isApitallySpanProcessorDeclared(): boolean {\n return (\n (globalThis as Record<symbol, boolean | undefined>)[APITALLY_SPAN_PROCESSOR_DECLARED_KEY] ===\n true\n );\n}\n\nexport function resetSpanProcessorState(): void {\n const holder = globalThis as Record<symbol, unknown>;\n delete holder[ACTIVE_SPAN_PIPELINE_KEY];\n delete holder[APITALLY_SPAN_PROCESSOR_DECLARED_KEY];\n delete holder[SERVER_SPAN_ACTIVATION_CALLBACK_KEY];\n}\n\nfunction setApitallySpanProcessorDeclared(): void {\n (globalThis as Record<symbol, boolean>)[APITALLY_SPAN_PROCESSOR_DECLARED_KEY] = true;\n}\n\nfunction getServerSpanActivationCallback(): ServerSpanActivationCallback | undefined {\n return (globalThis as Record<symbol, ServerSpanActivationCallback | undefined>)[\n SERVER_SPAN_ACTIVATION_CALLBACK_KEY\n ];\n}\n\ninterface RequestEntry {\n readonly serverSpanId: string;\n readonly serverSpan: Span;\n readonly spanIds: Set<string>;\n record?: RequestRecord;\n buffered: ReadableSpan[];\n endedServerSpan?: ReadableSpan;\n transportCompleted: boolean;\n released: boolean;\n}\n\ninterface KeptSpanEntry {\n readonly serverSpanId: string;\n // Carries the demotion decision across release for spans that end late.\n readonly demoted: boolean;\n}\n\n// Requests remain buffered until the SERVER span and transport complete, then\n// one keep/drop decision releases them once.\nexport class SpanPipeline implements SpanProcessor {\n // Callbacks are optional because metrics and log pipelines start at activation.\n metricsRecorder?: (record: RequestRecord) => void;\n onRequestFinished?: (serverSpanId: string, kept: boolean) => void;\n private readonly downstream: SpanProcessor;\n private readonly config: ApitallyConfig;\n private readonly sampleRateBound: bigint;\n private readonly excludePathPatterns: RegExp[];\n // Every span ID remains mapped to one request until completion so late logs\n // resolve. A miss means dropped, completed, or non-request telemetry.\n private readonly requests = new Map<string, RequestEntry>();\n private readonly stash = new Map<string, RequestStash>();\n private readonly demotedSpanIds = new Set<string>();\n // Kept span IDs remain resolvable after release for late spans and logs; the\n // oldest are evicted at the cap.\n private readonly keptSpanIds = new Map<string, KeptSpanEntry>();\n\n constructor(\n downstream: SpanProcessor,\n private readonly flushExporter?: () => Promise<void>,\n ) {\n this.downstream = downstream;\n this.config = getConfig();\n this.sampleRateBound = boundForSampleRate(this.config.sampleRate);\n this.excludePathPatterns = compilePatterns(DEFAULT_EXCLUDE_PATHS, this.config.excludePaths);\n }\n\n onStart(span: Span, parentContext: Context): void {\n try {\n if (isContribPerMessageSpan(span)) {\n return;\n }\n const parent = span.parentSpanContext;\n if (!parent || parent.isRemote) {\n if (span.kind === SpanKind.SERVER) {\n this.startRequest(span, parentContext);\n }\n return;\n }\n const entry = this.requests.get(parent.spanId);\n const spanId = span.spanContext().spanId;\n if (!entry) {\n // A span started under a request already released as kept exports at\n // its end, like the released request's other late telemetry.\n const kept = this.keptSpanIds.get(parent.spanId);\n if (kept) {\n this.addKeptSpanId(spanId, {\n serverSpanId: kept.serverSpanId,\n demoted: false,\n });\n }\n return;\n }\n if (entry.spanIds.size >= MAX_TRACKED_SPAN_IDS) {\n logDebug(\"Apitally span tracking cap reached, dropping the span\");\n return;\n }\n if (span.kind === SpanKind.SERVER) {\n // A second middleware produced a SERVER span for this request. Apitally\n // demotes its copy, but user exporters retain the duplicate.\n this.demotedSpanIds.add(spanId);\n logWarning(\n `Detected a duplicate SERVER span produced by the instrumentation scope \"${span.instrumentationScope?.name ?? \"unknown\"}\" inside an active request. Apitally exports it as an INTERNAL span, but your own OpenTelemetry exporters still receive the duplicate. To resolve this, remove the middleware that produces it.`,\n );\n }\n this.requests.set(spanId, entry);\n entry.spanIds.add(spanId);\n } catch (error) {\n logWarning(`Error in the Apitally span processor: ${String(error)}`);\n }\n }\n\n onEnd(span: ReadableSpan): void {\n try {\n const spanId = span.spanContext().spanId;\n const isDemoted = this.demotedSpanIds.delete(spanId);\n const entry = this.requests.get(spanId);\n if (!entry) {\n const kept = this.keptSpanIds.get(spanId);\n if (kept) {\n let exportSpan = span;\n if (kept.demoted) {\n const copy = copySpan(span);\n copy.apitallyData = { demoteToInternal: true };\n exportSpan = copy;\n }\n this.downstream.onEnd(exportSpan);\n }\n return;\n }\n if (spanId === entry.serverSpanId) {\n if (!entry.record) {\n this.removeCompletedRequestSpanIds(entry);\n this.stash.delete(entry.serverSpanId);\n this.onRequestFinished?.(entry.serverSpanId, false);\n return;\n }\n entry.endedServerSpan = span;\n this.releaseIfComplete(entry);\n return;\n }\n // The span id stays mapped so log records emitted after this span ended\n // still resolve to the request until it completes.\n let exportSpan = span;\n if (isDemoted) {\n const copy = copySpan(span);\n copy.apitallyData = { demoteToInternal: true };\n exportSpan = copy;\n }\n if (entry.buffered.length < MAX_BUFFERED_SPANS) {\n entry.buffered.push(exportSpan);\n } else {\n logDebug(\"Apitally span buffer cap reached, dropping the span\");\n }\n } catch (error) {\n logWarning(`Error in the Apitally span processor: ${String(error)}`);\n }\n }\n\n attachRequestRecord(serverSpanId: string, record: RequestRecord): void {\n const entry = this.requests.get(serverSpanId);\n if (entry) {\n entry.record ??= record;\n }\n }\n\n // Transport completion triggers response sampling and metrics independently\n // of span-end timing. Map misses still record metrics and discard other data.\n handleTransportCompletion(record: RequestRecord): void {\n try {\n record.dropReason = resolveTransportDropReason(record.attributes) ?? record.dropReason;\n const entry =\n record.serverSpanId !== undefined ? this.requests.get(record.serverSpanId) : undefined;\n if (entry && !entry.transportCompleted && !entry.released) {\n entry.record ??= record;\n entry.transportCompleted = true;\n if (!this.isResponseSampledIn(entry)) {\n this.dropRequestOnResponse(entry, record);\n }\n }\n this.metricsRecorder?.(record);\n if (entry) {\n this.releaseIfComplete(entry);\n }\n } catch (error) {\n logWarning(`Error in the Apitally span processor: ${String(error)}`);\n }\n }\n\n // Holds captured headers and bodies until the exporter attaches them to the\n // exported SERVER span copy. Fields already stashed are kept unless replaced.\n updateStash(serverSpanId: string, update: RequestStash): void {\n try {\n // A request without an in-flight map entry can never release, so its\n // stash entry would sit unconsumed until the cap evicts it.\n if (!this.requests.has(serverSpanId)) {\n return;\n }\n let entry = this.stash.get(serverSpanId);\n if (!entry) {\n if (this.stash.size >= MAX_STASHED_REQUESTS) {\n const oldestKey = this.stash.keys().next().value;\n if (oldestKey !== undefined) {\n this.stash.delete(oldestKey);\n logDebug(\"Apitally payload stash cap reached, dropping the oldest entry\");\n }\n }\n entry = {};\n this.stash.set(serverSpanId, entry);\n }\n if (update.requestHeaders !== undefined) {\n entry.requestHeaders = update.requestHeaders;\n }\n if (update.requestBody !== undefined) {\n entry.requestBody = update.requestBody;\n }\n if (update.requestContentEncoding !== undefined) {\n entry.requestContentEncoding = update.requestContentEncoding;\n }\n if (update.responseHeaders !== undefined) {\n entry.responseHeaders = update.responseHeaders;\n }\n if (update.responseBody !== undefined) {\n entry.responseBody = update.responseBody;\n }\n if (update.responseContentEncoding !== undefined) {\n entry.responseContentEncoding = update.responseContentEncoding;\n }\n } catch (error) {\n logDebug(`Error updating the request stash: ${String(error)}`);\n }\n }\n\n // Kept requests remain resolvable after release so late logs retain their\n // request association.\n resolveServerSpanId(spanId: string): string | undefined {\n return this.requests.get(spanId)?.serverSpanId ?? this.keptSpanIds.get(spanId)?.serverSpanId;\n }\n\n isRequestInFlight(serverSpanId: string): boolean {\n return this.requests.has(serverSpanId);\n }\n\n // Exclusion answers \"never wanted\" and runs strictly before sampling; an\n // excluded request never invokes a user sampling callback.\n resolveRequestDropReasonBeforeSampling(attributes: Attributes): RequestDropReason | undefined {\n const transportDropReason = resolveTransportDropReason(attributes);\n if (transportDropReason !== undefined) {\n return transportDropReason;\n }\n const path = attributes[\"url.path\"] ?? attributes[\"http.target\"];\n if (typeof path === \"string\" && matchesAny(this.excludePathPatterns, path.split(\"?\")[0])) {\n return \"excluded\";\n }\n const userAgent = attributes[\"user_agent.original\"] ?? attributes[\"http.user_agent\"];\n if (typeof userAgent === \"string\" && matchesAny(EXCLUDE_USER_AGENT_PATTERNS, userAgent)) {\n return \"excluded\";\n }\n return undefined;\n }\n\n async forceFlush(): Promise<void> {\n await this.downstream.forceFlush();\n // OTel flushes queued batches but does not await already-running exports.\n await this.flushExporter?.();\n }\n\n // Shutdown releases requests with completed transport observation once and\n // discards incomplete requests, which cannot complete afterward.\n async shutdown(): Promise<void> {\n try {\n for (const entry of new Set(this.requests.values())) {\n if (!entry.released && entry.transportCompleted) {\n this.releaseRequest(entry, entry.endedServerSpan ?? entry.serverSpan);\n }\n }\n this.requests.clear();\n this.stash.clear();\n this.demotedSpanIds.clear();\n this.keptSpanIds.clear();\n } catch (error) {\n logWarning(`Error in the Apitally span processor: ${String(error)}`);\n }\n await this.downstream.shutdown();\n }\n\n private startRequest(span: Span, parentContext: Context): void {\n const spanId = span.spanContext().spanId;\n // The handle is filled for every local-root SERVER span, independent of the\n // keep decision, so runtime writes always reach the current request's span.\n const handle = parentContext.getValue(SPAN_HANDLE_KEY) as SpanHandle | undefined;\n if (handle) {\n handle.span = span;\n }\n const record = parentContext.getValue(REQUEST_RECORD_KEY) as RequestRecord | undefined;\n if (record) {\n record.serverSpanId = spanId;\n }\n writeUrlAttributesFromFullUrl(span);\n const dropReason =\n this.resolveRequestDropReasonBeforeSampling(span.attributes) ??\n (this.isRequestSampledIn(span) ? undefined : \"sampled-out\");\n if (dropReason) {\n if (record) {\n record.dropReason = dropReason;\n }\n return;\n }\n this.requests.set(spanId, {\n serverSpanId: spanId,\n serverSpan: span,\n spanIds: new Set([spanId]),\n record,\n buffered: [],\n transportCompleted: false,\n released: false,\n });\n }\n\n private isRequestSampledIn(span: Span): boolean {\n const callback = this.config.sampleOnRequest;\n const rate = callback\n ? resolveCallbackSampleRate(callback, span, \"sampleOnRequest\")\n : undefined;\n const bound = rate === undefined ? this.sampleRateBound : boundForSampleRate(rate);\n return isTraceSampledIn(span.spanContext().traceId, bound);\n }\n\n // Abstention leaves the request-stage decision standing; it never re-tests the\n // static sample rate.\n private isResponseSampledIn(entry: RequestEntry): boolean {\n const callback = this.config.sampleOnResponse;\n if (!callback) {\n return true;\n }\n const serverSpan = entry.endedServerSpan ?? entry.serverSpan;\n let snapshot: ReadableSpan = serverSpan;\n if (entry.record && Object.keys(entry.record.attributes).length > 0) {\n // The callback sees transport-observed values even when they were learned\n // after the span ended (final route, response size).\n const copy = copySpan(serverSpan);\n copy.attributes = {\n ...serverSpan.attributes,\n ...entry.record.attributes,\n };\n snapshot = copy;\n }\n const rate = resolveCallbackSampleRate(callback, snapshot, \"sampleOnResponse\");\n if (rate === undefined) {\n return true;\n }\n return isTraceSampledIn(serverSpan.spanContext().traceId, boundForSampleRate(rate));\n }\n\n private dropRequestOnResponse(entry: RequestEntry, record: RequestRecord): void {\n // Removing every span id sends the dropped request's late telemetry to the\n // lookup-miss rule, so it is discarded locally.\n entry.released = true;\n entry.buffered = [];\n record.dropReason = \"sampled-out\";\n if (entry.record) {\n entry.record.dropReason = \"sampled-out\";\n }\n this.removeCompletedRequestSpanIds(entry);\n this.stash.delete(entry.serverSpanId);\n this.onRequestFinished?.(entry.serverSpanId, false);\n }\n\n private releaseIfComplete(entry: RequestEntry): void {\n if (entry.released || !entry.transportCompleted || !entry.endedServerSpan) {\n return;\n }\n this.releaseRequest(entry, entry.endedServerSpan);\n }\n\n // Descendants, the SERVER span, and logs enter downstream processing once, in\n // that order. The exporter applies the request record and stash later.\n private releaseRequest(entry: RequestEntry, serverSpan: ReadableSpan): void {\n entry.released = true;\n for (const spanId of entry.spanIds) {\n this.requests.delete(spanId);\n this.addKeptSpanId(spanId, {\n serverSpanId: entry.serverSpanId,\n demoted: this.demotedSpanIds.delete(spanId),\n });\n }\n for (const bufferedSpan of entry.buffered) {\n this.downstream.onEnd(bufferedSpan);\n }\n entry.buffered = [];\n const stash = this.stash.get(entry.serverSpanId);\n this.stash.delete(entry.serverSpanId);\n let exportSpan = serverSpan;\n if (entry.record || stash || !serverSpan.ended) {\n const copy = copySpan(serverSpan);\n if (!serverSpan.ended) {\n // A SERVER span released during shutdown uses shutdown as its end time.\n copy.endTime = hrTime();\n copy.duration = hrTimeDuration(copy.startTime, copy.endTime);\n copy.ended = true;\n }\n copy.apitallyData = { record: entry.record, stash };\n exportSpan = copy;\n }\n this.downstream.onEnd(exportSpan);\n this.onRequestFinished?.(entry.serverSpanId, true);\n }\n\n private removeCompletedRequestSpanIds(entry: RequestEntry): void {\n for (const spanId of entry.spanIds) {\n this.requests.delete(spanId);\n this.demotedSpanIds.delete(spanId);\n }\n }\n\n private addKeptSpanId(spanId: string, kept: KeptSpanEntry): void {\n if (this.keptSpanIds.size >= MAX_KEPT_SPAN_IDS) {\n const oldestId = this.keptSpanIds.keys().next().value;\n if (oldestId !== undefined) {\n this.keptSpanIds.delete(oldestId);\n }\n }\n this.keptSpanIds.set(spanId, kept);\n }\n}\n\nexport function copySpan(span: ReadableSpan): SpanCopy {\n const spanContext = span.spanContext();\n return {\n name: span.name,\n kind: span.kind,\n spanContext: () => spanContext,\n parentSpanContext: span.parentSpanContext,\n startTime: span.startTime,\n endTime: span.endTime,\n status: span.status,\n attributes: span.attributes,\n links: span.links,\n events: span.events,\n duration: span.duration,\n ended: span.ended,\n resource: span.resource,\n instrumentationScope: span.instrumentationScope,\n droppedAttributesCount: span.droppedAttributesCount,\n droppedEventsCount: span.droppedEventsCount,\n droppedLinksCount: span.droppedLinksCount,\n };\n}\n\nfunction resolveTransportDropReason(attributes: Attributes): RequestDropReason | undefined {\n const method = attributes[\"http.request.method\"] ?? attributes[\"http.method\"];\n if (method === \"OPTIONS\") {\n return \"method\";\n }\n const scheme = attributes[\"url.scheme\"] ?? attributes[\"http.scheme\"];\n return scheme === \"ws\" || scheme === \"wss\" ? \"scheme\" : undefined;\n}\n\n// Missing path, query, and target attributes are derived from the full URL\n// because exclusion, display, and redaction require them.\nfunction writeUrlAttributesFromFullUrl(span: Span): void {\n const attributes = span.attributes;\n if (attributes[\"url.path\"] !== undefined || attributes[\"http.target\"] !== undefined) {\n return;\n }\n const url = attributes[\"url.full\"] ?? attributes[\"http.url\"];\n if (typeof url !== \"string\") {\n return;\n }\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return;\n }\n const query = parsed.search.replace(/^\\?/, \"\");\n span.setAttribute(\"url.path\", parsed.pathname);\n if (query) {\n span.setAttribute(\"url.query\", query);\n }\n span.setAttribute(\"http.target\", query ? `${parsed.pathname}?${query}` : parsed.pathname);\n}\n\nconst TRACE_ID_LOW_64_BITS_MASK = (1n << 64n) - 1n;\n\nfunction boundForSampleRate(rate: number): bigint {\n return BigInt(Math.round(rate * 2 ** 64));\n}\n\n// Low 64-bit ratio sampling is deterministic per trace. Comparing the same\n// value at both stages makes the lower rate decisive.\nfunction isTraceSampledIn(traceId: string, bound: bigint): boolean {\n return (BigInt(`0x${traceId}`) & TRACE_ID_LOW_64_BITS_MASK) < bound;\n}\n\n// A throwing or invalid-returning callback resolves to keep: a user bug must\n// never lose data without a warning. Undefined means the callback abstained.\nfunction resolveCallbackSampleRate(\n callback: SamplingCallback,\n span: ReadableSpan,\n optionName: string,\n): number | undefined {\n let result: unknown;\n try {\n result = callback(span);\n } catch {\n logWarning(`The Apitally ${optionName} callback threw an error, so the request was captured`);\n return 1;\n }\n if (result === undefined || result === null) {\n return undefined;\n }\n if (typeof result === \"boolean\") {\n return result ? 1 : 0;\n }\n if (typeof result === \"number\" && result >= 0 && result <= 1) {\n return result;\n }\n logWarning(\n `The Apitally ${optionName} callback returned an invalid value, so the request was captured. Sampling callbacks must synchronously return a number between 0 and 1, a boolean, or undefined.`,\n );\n return 1;\n}\n\nfunction isContribPerMessageSpan(span: Span): boolean {\n const scopeName = span.instrumentationScope?.name ?? \"\";\n return (\n span.kind === SpanKind.INTERNAL &&\n [\" http send\", \" http receive\", \" websocket send\", \" websocket receive\"].some((suffix) =>\n span.name.endsWith(suffix),\n ) &&\n (scopeName.startsWith(\"@opentelemetry/instrumentation\") ||\n scopeName.startsWith(\"opentelemetry.instrumentation.\"))\n );\n}\n"],"mappings":"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"}
@@ -1,7 +1,6 @@
1
1
  import { logDebug, logWarning } from "./logger.js";
2
2
  import { DEFAULT_EXCLUDE_PATHS, EXCLUDE_USER_AGENTS, compilePatterns, getConfig, matchesAny } from "./config.js";
3
3
  import { REQUEST_RECORD_KEY, SPAN_HANDLE_KEY } from "./context.js";
4
- import { writeConsumerAttributesFromContext } from "./consumer.js";
5
4
  import { SpanKind } from "@opentelemetry/api";
6
5
  import { hrTime, hrTimeDuration } from "@opentelemetry/core";
7
6
  //#region src/spanProcessor.ts
@@ -236,7 +235,6 @@ var SpanPipeline = class {
236
235
  if (handle) handle.span = span;
237
236
  const record = parentContext.getValue(REQUEST_RECORD_KEY);
238
237
  if (record) record.serverSpanId = spanId;
239
- writeConsumerAttributesFromContext(parentContext, span, record);
240
238
  writeUrlAttributesFromFullUrl(span);
241
239
  const dropReason = this.resolveRequestDropReasonBeforeSampling(span.attributes) ?? (this.isRequestSampledIn(span) ? void 0 : "sampled-out");
242
240
  if (dropReason) {