@superblocksteam/telemetry 2.0.173-next.4 → 2.0.174

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 (304) hide show
  1. package/dist/browser/console-logging.js +7 -2
  2. package/dist/browser/console-logging.js.map +1 -1
  3. package/dist/browser/early-console-buffer.js +14 -12
  4. package/dist/browser/early-console-buffer.js.map +1 -1
  5. package/dist/browser/index.js +41 -12
  6. package/dist/browser/index.js.map +1 -1
  7. package/dist/browser/init.d.ts +1 -1
  8. package/dist/browser/init.d.ts.map +1 -1
  9. package/dist/browser/init.js +52 -42
  10. package/dist/browser/init.js.map +1 -1
  11. package/dist/browser/instrumentations.js +15 -11
  12. package/dist/browser/instrumentations.js.map +1 -1
  13. package/dist/browser/logs.d.ts +1 -1
  14. package/dist/browser/logs.d.ts.map +1 -1
  15. package/dist/browser/logs.js +18 -11
  16. package/dist/browser/logs.js.map +1 -1
  17. package/dist/browser/metrics.js +12 -9
  18. package/dist/browser/metrics.js.map +1 -1
  19. package/dist/browser/resilient-exporter.d.ts +1 -1
  20. package/dist/browser/resilient-exporter.d.ts.map +1 -1
  21. package/dist/browser/resilient-exporter.js +12 -8
  22. package/dist/browser/resilient-exporter.js.map +1 -1
  23. package/dist/browser/sanitizer.js +6 -2
  24. package/dist/browser/sanitizer.js.map +1 -1
  25. package/dist/browser/traced-socket.js +18 -14
  26. package/dist/browser/traced-socket.js.map +1 -1
  27. package/dist/common/contracts/tier2-traces.js +44 -33
  28. package/dist/common/contracts/tier2-traces.js.map +1 -1
  29. package/dist/common/deployment-type.js +8 -5
  30. package/dist/common/deployment-type.js.map +1 -1
  31. package/dist/common/guardrails.js +38 -26
  32. package/dist/common/guardrails.js.map +1 -1
  33. package/dist/common/index.js +24 -8
  34. package/dist/common/index.js.map +1 -1
  35. package/dist/common/log-sanitizer.js +55 -37
  36. package/dist/common/log-sanitizer.js.map +1 -1
  37. package/dist/common/policy-evaluator.d.ts +1 -1
  38. package/dist/common/policy-evaluator.d.ts.map +1 -1
  39. package/dist/common/policy-evaluator.js +9 -5
  40. package/dist/common/policy-evaluator.js.map +1 -1
  41. package/dist/common/resource.js +25 -18
  42. package/dist/common/resource.js.map +1 -1
  43. package/dist/common/tier-hints.js +22 -12
  44. package/dist/common/tier-hints.js.map +1 -1
  45. package/dist/common/trace-sanitizer.js +10 -6
  46. package/dist/common/trace-sanitizer.js.map +1 -1
  47. package/dist/common/traced-socket-types.js +2 -1
  48. package/dist/common/traced-socket-types.js.map +1 -1
  49. package/dist/index.js +38 -6
  50. package/dist/index.js.map +1 -1
  51. package/dist/lint/forbidden-attributes.js +24 -19
  52. package/dist/lint/forbidden-attributes.js.map +1 -1
  53. package/dist/lint/index.js +8 -1
  54. package/dist/lint/index.js.map +1 -1
  55. package/dist/llmobs/index.js +9 -2
  56. package/dist/llmobs/index.js.map +1 -1
  57. package/dist/llmobs/tier1-exporter.js +12 -6
  58. package/dist/llmobs/tier1-exporter.js.map +1 -1
  59. package/dist/llmobs/tier2-summarizer.js +5 -1
  60. package/dist/llmobs/tier2-summarizer.js.map +1 -1
  61. package/dist/node/dynamic-attribute-processor.js +7 -2
  62. package/dist/node/dynamic-attribute-processor.js.map +1 -1
  63. package/dist/node/exporters/resilient-exporter.d.ts +1 -1
  64. package/dist/node/exporters/resilient-exporter.d.ts.map +1 -1
  65. package/dist/node/exporters/resilient-exporter.js +12 -8
  66. package/dist/node/exporters/resilient-exporter.js.map +1 -1
  67. package/dist/node/index.js +26 -7
  68. package/dist/node/index.js.map +1 -1
  69. package/dist/node/init.d.ts +3 -3
  70. package/dist/node/init.d.ts.map +1 -1
  71. package/dist/node/init.js +72 -66
  72. package/dist/node/init.js.map +1 -1
  73. package/dist/node/local-obs-mode.js +4 -1
  74. package/dist/node/local-obs-mode.js.map +1 -1
  75. package/dist/node/log-processor.d.ts +1 -1
  76. package/dist/node/log-processor.d.ts.map +1 -1
  77. package/dist/node/log-processor.js +55 -47
  78. package/dist/node/log-processor.js.map +1 -1
  79. package/dist/node/metrics-client.js +5 -1
  80. package/dist/node/metrics-client.js.map +1 -1
  81. package/dist/node/safe-logger.js +12 -8
  82. package/dist/node/safe-logger.js.map +1 -1
  83. package/dist/node/sanitizing-processor.d.ts +2 -2
  84. package/dist/node/sanitizing-processor.d.ts.map +1 -1
  85. package/dist/node/sanitizing-processor.js +10 -6
  86. package/dist/node/sanitizing-processor.js.map +1 -1
  87. package/dist/node/service-tracers.js +10 -7
  88. package/dist/node/service-tracers.js.map +1 -1
  89. package/dist/node/traced-socket.d.ts +3 -3
  90. package/dist/node/traced-socket.d.ts.map +1 -1
  91. package/dist/node/traced-socket.js +52 -48
  92. package/dist/node/traced-socket.js.map +1 -1
  93. package/dist/npm-registry/emitter.js +47 -34
  94. package/dist/npm-registry/emitter.js.map +1 -1
  95. package/dist/npm-registry/index.js +19 -3
  96. package/dist/npm-registry/index.js.map +1 -1
  97. package/dist/npm-registry/sanitize.js +27 -16
  98. package/dist/npm-registry/sanitize.js.map +1 -1
  99. package/dist/npm-registry/spans.js +12 -7
  100. package/dist/npm-registry/spans.js.map +1 -1
  101. package/dist/testing/in-memory-exporter.d.ts +1 -1
  102. package/dist/testing/in-memory-exporter.d.ts.map +1 -1
  103. package/dist/testing/in-memory-exporter.js +12 -6
  104. package/dist/testing/in-memory-exporter.js.map +1 -1
  105. package/dist/testing/index.js +15 -3
  106. package/dist/testing/index.js.map +1 -1
  107. package/dist/testing/metrics-capture.js +15 -12
  108. package/dist/testing/metrics-capture.js.map +1 -1
  109. package/dist/testing/test-init.js +31 -24
  110. package/dist/testing/test-init.js.map +1 -1
  111. package/dist/types/index.js +17 -1
  112. package/dist/types/index.js.map +1 -1
  113. package/dist/types/policy.js +24 -21
  114. package/dist/types/policy.js.map +1 -1
  115. package/dist-esm/browser/console-logging.d.ts +18 -0
  116. package/dist-esm/browser/console-logging.d.ts.map +1 -0
  117. package/dist-esm/browser/console-logging.js +27 -0
  118. package/dist-esm/browser/console-logging.js.map +1 -0
  119. package/dist-esm/browser/early-console-buffer.d.ts +49 -0
  120. package/dist-esm/browser/early-console-buffer.d.ts.map +1 -0
  121. package/dist-esm/browser/early-console-buffer.js +181 -0
  122. package/dist-esm/browser/early-console-buffer.js.map +1 -0
  123. package/dist-esm/browser/index.d.ts +18 -0
  124. package/dist-esm/browser/index.d.ts.map +1 -0
  125. package/dist-esm/browser/index.js +23 -0
  126. package/dist-esm/browser/index.js.map +1 -0
  127. package/dist-esm/browser/init.d.ts +100 -0
  128. package/dist-esm/browser/init.d.ts.map +1 -0
  129. package/dist-esm/browser/init.js +317 -0
  130. package/dist-esm/browser/init.js.map +1 -0
  131. package/dist-esm/browser/instrumentations.d.ts +67 -0
  132. package/dist-esm/browser/instrumentations.d.ts.map +1 -0
  133. package/dist-esm/browser/instrumentations.js +79 -0
  134. package/dist-esm/browser/instrumentations.js.map +1 -0
  135. package/dist-esm/browser/logs.d.ts +57 -0
  136. package/dist-esm/browser/logs.d.ts.map +1 -0
  137. package/dist-esm/browser/logs.js +80 -0
  138. package/dist-esm/browser/logs.js.map +1 -0
  139. package/dist-esm/browser/metrics.d.ts +29 -0
  140. package/dist-esm/browser/metrics.d.ts.map +1 -0
  141. package/dist-esm/browser/metrics.js +46 -0
  142. package/dist-esm/browser/metrics.js.map +1 -0
  143. package/dist-esm/browser/resilient-exporter.d.ts +43 -0
  144. package/dist-esm/browser/resilient-exporter.d.ts.map +1 -0
  145. package/dist-esm/browser/resilient-exporter.js +84 -0
  146. package/dist-esm/browser/resilient-exporter.js.map +1 -0
  147. package/dist-esm/browser/sanitizer.d.ts +35 -0
  148. package/dist-esm/browser/sanitizer.d.ts.map +1 -0
  149. package/dist-esm/browser/sanitizer.js +207 -0
  150. package/dist-esm/browser/sanitizer.js.map +1 -0
  151. package/dist-esm/browser/traced-socket.d.ts +102 -0
  152. package/dist-esm/browser/traced-socket.d.ts.map +1 -0
  153. package/dist-esm/browser/traced-socket.js +199 -0
  154. package/dist-esm/browser/traced-socket.js.map +1 -0
  155. package/dist-esm/common/contracts/tier2-traces.d.ts +116 -0
  156. package/dist-esm/common/contracts/tier2-traces.d.ts.map +1 -0
  157. package/dist-esm/common/contracts/tier2-traces.js +725 -0
  158. package/dist-esm/common/contracts/tier2-traces.js.map +1 -0
  159. package/dist-esm/common/deployment-type.d.ts +18 -0
  160. package/dist-esm/common/deployment-type.d.ts.map +1 -0
  161. package/dist-esm/common/deployment-type.js +27 -0
  162. package/dist-esm/common/deployment-type.js.map +1 -0
  163. package/dist-esm/common/guardrails.d.ts +132 -0
  164. package/dist-esm/common/guardrails.d.ts.map +1 -0
  165. package/dist-esm/common/guardrails.js +230 -0
  166. package/dist-esm/common/guardrails.js.map +1 -0
  167. package/dist-esm/common/index.d.ts +17 -0
  168. package/dist-esm/common/index.d.ts.map +1 -0
  169. package/dist-esm/common/index.js +17 -0
  170. package/dist-esm/common/index.js.map +1 -0
  171. package/dist-esm/common/log-sanitizer.d.ts +163 -0
  172. package/dist-esm/common/log-sanitizer.d.ts.map +1 -0
  173. package/dist-esm/common/log-sanitizer.js +745 -0
  174. package/dist-esm/common/log-sanitizer.js.map +1 -0
  175. package/dist-esm/common/policy-evaluator.d.ts +103 -0
  176. package/dist-esm/common/policy-evaluator.d.ts.map +1 -0
  177. package/dist-esm/common/policy-evaluator.js +196 -0
  178. package/dist-esm/common/policy-evaluator.js.map +1 -0
  179. package/dist-esm/common/resource.d.ts +79 -0
  180. package/dist-esm/common/resource.d.ts.map +1 -0
  181. package/dist-esm/common/resource.js +121 -0
  182. package/dist-esm/common/resource.js.map +1 -0
  183. package/dist-esm/common/tier-hints.d.ts +182 -0
  184. package/dist-esm/common/tier-hints.d.ts.map +1 -0
  185. package/dist-esm/common/tier-hints.js +199 -0
  186. package/dist-esm/common/tier-hints.js.map +1 -0
  187. package/dist-esm/common/trace-sanitizer.d.ts +82 -0
  188. package/dist-esm/common/trace-sanitizer.d.ts.map +1 -0
  189. package/dist-esm/common/trace-sanitizer.js +230 -0
  190. package/dist-esm/common/trace-sanitizer.js.map +1 -0
  191. package/dist-esm/common/traced-socket-types.d.ts +43 -0
  192. package/dist-esm/common/traced-socket-types.d.ts.map +1 -0
  193. package/dist-esm/common/traced-socket-types.js +16 -0
  194. package/dist-esm/common/traced-socket-types.js.map +1 -0
  195. package/dist-esm/index.d.ts +45 -0
  196. package/dist-esm/index.d.ts.map +1 -0
  197. package/dist-esm/index.js +56 -0
  198. package/dist-esm/index.js.map +1 -0
  199. package/dist-esm/lint/forbidden-attributes.d.ts +149 -0
  200. package/dist-esm/lint/forbidden-attributes.d.ts.map +1 -0
  201. package/dist-esm/lint/forbidden-attributes.js +210 -0
  202. package/dist-esm/lint/forbidden-attributes.js.map +1 -0
  203. package/dist-esm/lint/index.d.ts +9 -0
  204. package/dist-esm/lint/index.d.ts.map +1 -0
  205. package/dist-esm/lint/index.js +9 -0
  206. package/dist-esm/lint/index.js.map +1 -0
  207. package/dist-esm/llmobs/index.d.ts +22 -0
  208. package/dist-esm/llmobs/index.d.ts.map +1 -0
  209. package/dist-esm/llmobs/index.js +22 -0
  210. package/dist-esm/llmobs/index.js.map +1 -0
  211. package/dist-esm/llmobs/tier1-exporter.d.ts +146 -0
  212. package/dist-esm/llmobs/tier1-exporter.d.ts.map +1 -0
  213. package/dist-esm/llmobs/tier1-exporter.js +193 -0
  214. package/dist-esm/llmobs/tier1-exporter.js.map +1 -0
  215. package/dist-esm/llmobs/tier2-summarizer.d.ts +268 -0
  216. package/dist-esm/llmobs/tier2-summarizer.d.ts.map +1 -0
  217. package/dist-esm/llmobs/tier2-summarizer.js +652 -0
  218. package/dist-esm/llmobs/tier2-summarizer.js.map +1 -0
  219. package/dist-esm/node/dynamic-attribute-processor.d.ts +43 -0
  220. package/dist-esm/node/dynamic-attribute-processor.d.ts.map +1 -0
  221. package/dist-esm/node/dynamic-attribute-processor.js +74 -0
  222. package/dist-esm/node/dynamic-attribute-processor.js.map +1 -0
  223. package/dist-esm/node/exporters/resilient-exporter.d.ts +91 -0
  224. package/dist-esm/node/exporters/resilient-exporter.d.ts.map +1 -0
  225. package/dist-esm/node/exporters/resilient-exporter.js +132 -0
  226. package/dist-esm/node/exporters/resilient-exporter.js.map +1 -0
  227. package/dist-esm/node/index.d.ts +13 -0
  228. package/dist-esm/node/index.d.ts.map +1 -0
  229. package/dist-esm/node/index.js +13 -0
  230. package/dist-esm/node/index.js.map +1 -0
  231. package/dist-esm/node/init.d.ts +97 -0
  232. package/dist-esm/node/init.d.ts.map +1 -0
  233. package/dist-esm/node/init.js +359 -0
  234. package/dist-esm/node/init.js.map +1 -0
  235. package/dist-esm/node/local-obs-mode.d.ts +17 -0
  236. package/dist-esm/node/local-obs-mode.d.ts.map +1 -0
  237. package/dist-esm/node/local-obs-mode.js +19 -0
  238. package/dist-esm/node/local-obs-mode.js.map +1 -0
  239. package/dist-esm/node/log-processor.d.ts +132 -0
  240. package/dist-esm/node/log-processor.d.ts.map +1 -0
  241. package/dist-esm/node/log-processor.js +389 -0
  242. package/dist-esm/node/log-processor.js.map +1 -0
  243. package/dist-esm/node/metrics-client.d.ts +88 -0
  244. package/dist-esm/node/metrics-client.d.ts.map +1 -0
  245. package/dist-esm/node/metrics-client.js +205 -0
  246. package/dist-esm/node/metrics-client.js.map +1 -0
  247. package/dist-esm/node/safe-logger.d.ts +55 -0
  248. package/dist-esm/node/safe-logger.d.ts.map +1 -0
  249. package/dist-esm/node/safe-logger.js +154 -0
  250. package/dist-esm/node/safe-logger.js.map +1 -0
  251. package/dist-esm/node/sanitizing-processor.d.ts +67 -0
  252. package/dist-esm/node/sanitizing-processor.d.ts.map +1 -0
  253. package/dist-esm/node/sanitizing-processor.js +163 -0
  254. package/dist-esm/node/sanitizing-processor.js.map +1 -0
  255. package/dist-esm/node/service-tracers.d.ts +52 -0
  256. package/dist-esm/node/service-tracers.d.ts.map +1 -0
  257. package/dist-esm/node/service-tracers.js +78 -0
  258. package/dist-esm/node/service-tracers.js.map +1 -0
  259. package/dist-esm/node/traced-socket.d.ts +120 -0
  260. package/dist-esm/node/traced-socket.d.ts.map +1 -0
  261. package/dist-esm/node/traced-socket.js +334 -0
  262. package/dist-esm/node/traced-socket.js.map +1 -0
  263. package/dist-esm/npm-registry/emitter.d.ts +330 -0
  264. package/dist-esm/npm-registry/emitter.d.ts.map +1 -0
  265. package/dist-esm/npm-registry/emitter.js +546 -0
  266. package/dist-esm/npm-registry/emitter.js.map +1 -0
  267. package/dist-esm/npm-registry/index.d.ts +12 -0
  268. package/dist-esm/npm-registry/index.d.ts.map +1 -0
  269. package/dist-esm/npm-registry/index.js +12 -0
  270. package/dist-esm/npm-registry/index.js.map +1 -0
  271. package/dist-esm/npm-registry/sanitize.d.ts +174 -0
  272. package/dist-esm/npm-registry/sanitize.d.ts.map +1 -0
  273. package/dist-esm/npm-registry/sanitize.js +331 -0
  274. package/dist-esm/npm-registry/sanitize.js.map +1 -0
  275. package/dist-esm/npm-registry/spans.d.ts +61 -0
  276. package/dist-esm/npm-registry/spans.d.ts.map +1 -0
  277. package/dist-esm/npm-registry/spans.js +86 -0
  278. package/dist-esm/npm-registry/spans.js.map +1 -0
  279. package/dist-esm/package.json +1 -0
  280. package/dist-esm/testing/in-memory-exporter.d.ts +179 -0
  281. package/dist-esm/testing/in-memory-exporter.d.ts.map +1 -0
  282. package/dist-esm/testing/in-memory-exporter.js +250 -0
  283. package/dist-esm/testing/in-memory-exporter.js.map +1 -0
  284. package/dist-esm/testing/index.d.ts +9 -0
  285. package/dist-esm/testing/index.d.ts.map +1 -0
  286. package/dist-esm/testing/index.js +9 -0
  287. package/dist-esm/testing/index.js.map +1 -0
  288. package/dist-esm/testing/metrics-capture.d.ts +29 -0
  289. package/dist-esm/testing/metrics-capture.d.ts.map +1 -0
  290. package/dist-esm/testing/metrics-capture.js +71 -0
  291. package/dist-esm/testing/metrics-capture.js.map +1 -0
  292. package/dist-esm/testing/test-init.d.ts +80 -0
  293. package/dist-esm/testing/test-init.d.ts.map +1 -0
  294. package/dist-esm/testing/test-init.js +137 -0
  295. package/dist-esm/testing/test-init.js.map +1 -0
  296. package/dist-esm/types/index.d.ts +84 -0
  297. package/dist-esm/types/index.d.ts.map +1 -0
  298. package/dist-esm/types/index.js +7 -0
  299. package/dist-esm/types/index.js.map +1 -0
  300. package/dist-esm/types/policy.d.ts +92 -0
  301. package/dist-esm/types/policy.d.ts.map +1 -0
  302. package/dist-esm/types/policy.js +122 -0
  303. package/dist-esm/types/policy.js.map +1 -0
  304. package/package.json +17 -11
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Metrics Client for Node.js Telemetry
3
+ *
4
+ * Provides a simple interface for recording metrics via OpenTelemetry.
5
+ * This is the recommended way to record metrics in services using the telemetry package.
6
+ */
7
+ /**
8
+ * Converts Labels to OTEL Attributes.
9
+ */
10
+ function labelsToAttributes(labels) {
11
+ if (!labels)
12
+ return {};
13
+ const attributes = {};
14
+ for (const [key, value] of Object.entries(labels)) {
15
+ attributes[key] = String(value);
16
+ }
17
+ return attributes;
18
+ }
19
+ /**
20
+ * TTL configuration for gauge values.
21
+ */
22
+ const GAUGE_TTL_MS = 5 * 60 * 1000; // 5 minutes
23
+ const GAUGE_MAX_ENTRIES = 10_000; // Max entries per gauge to prevent unbounded growth
24
+ const GAUGE_CLEANUP_INTERVAL_MS = 60 * 1000; // Cleanup every minute
25
+ /**
26
+ * TTL-based map for gauge values with automatic cleanup.
27
+ */
28
+ class TTLGaugeMap {
29
+ ttlMs;
30
+ maxEntries;
31
+ entries = new Map();
32
+ cleanupTimer = null;
33
+ constructor(ttlMs = GAUGE_TTL_MS, maxEntries = GAUGE_MAX_ENTRIES) {
34
+ this.ttlMs = ttlMs;
35
+ this.maxEntries = maxEntries;
36
+ // Start periodic cleanup
37
+ this.cleanupTimer = setInterval(() => this.cleanup(), GAUGE_CLEANUP_INTERVAL_MS);
38
+ // Don't prevent Node.js from exiting
39
+ this.cleanupTimer.unref();
40
+ }
41
+ set(labelsKey, value) {
42
+ // If at max capacity, remove oldest entry
43
+ if (this.entries.size >= this.maxEntries && !this.entries.has(labelsKey)) {
44
+ this.evictOldest();
45
+ }
46
+ this.entries.set(labelsKey, {
47
+ value,
48
+ updatedAt: Date.now(),
49
+ });
50
+ }
51
+ /**
52
+ * Gets all non-expired entries.
53
+ */
54
+ getAll() {
55
+ const now = Date.now();
56
+ const result = new Map();
57
+ for (const [key, entry] of this.entries) {
58
+ if (now - entry.updatedAt <= this.ttlMs) {
59
+ result.set(key, entry.value);
60
+ }
61
+ }
62
+ return result;
63
+ }
64
+ /**
65
+ * Removes expired entries.
66
+ */
67
+ cleanup() {
68
+ const now = Date.now();
69
+ for (const [key, entry] of this.entries) {
70
+ if (now - entry.updatedAt > this.ttlMs) {
71
+ this.entries.delete(key);
72
+ }
73
+ }
74
+ }
75
+ /**
76
+ * Evicts the oldest entry when at max capacity.
77
+ */
78
+ evictOldest() {
79
+ let oldestKey = null;
80
+ let oldestTime = Infinity;
81
+ for (const [key, entry] of this.entries) {
82
+ if (entry.updatedAt < oldestTime) {
83
+ oldestTime = entry.updatedAt;
84
+ oldestKey = key;
85
+ }
86
+ }
87
+ if (oldestKey) {
88
+ this.entries.delete(oldestKey);
89
+ }
90
+ }
91
+ /**
92
+ * Stops the cleanup timer.
93
+ */
94
+ destroy() {
95
+ if (this.cleanupTimer) {
96
+ clearInterval(this.cleanupTimer);
97
+ this.cleanupTimer = null;
98
+ }
99
+ }
100
+ }
101
+ /**
102
+ * Metrics client that provides a unified interface for recording OTEL metrics.
103
+ */
104
+ export class MetricsClient {
105
+ meter;
106
+ counters = new Map();
107
+ histograms = new Map();
108
+ // Gauges use TTL-based maps to prevent unbounded memory growth
109
+ gaugeValues = new Map();
110
+ constructor(meter) {
111
+ this.meter = meter;
112
+ }
113
+ /**
114
+ * Creates or retrieves a counter and returns a handle.
115
+ */
116
+ counter(name, options) {
117
+ if (!this.counters.has(name)) {
118
+ this.counters.set(name, this.meter.createCounter(name, options));
119
+ }
120
+ const counter = this.counters.get(name);
121
+ return {
122
+ inc: (labels, value = 1) => {
123
+ counter.add(value, labelsToAttributes(labels));
124
+ },
125
+ };
126
+ }
127
+ /**
128
+ * Creates or retrieves a gauge and returns a handle.
129
+ * Note: OTEL gauges are async/observable, so we store the value and emit via callback.
130
+ * Values are automatically expired after 5 minutes to prevent unbounded memory growth.
131
+ */
132
+ gauge(name) {
133
+ if (!this.gaugeValues.has(name)) {
134
+ const ttlMap = new TTLGaugeMap();
135
+ this.gaugeValues.set(name, ttlMap);
136
+ // Create an observable gauge that reads from the TTL map
137
+ this.meter.createObservableGauge(name, {}).addCallback((result) => {
138
+ const ttlMapRef = this.gaugeValues.get(name);
139
+ if (ttlMapRef) {
140
+ // getAll() only returns non-expired entries
141
+ for (const [labelsKey, value] of ttlMapRef.getAll()) {
142
+ const labels = JSON.parse(labelsKey);
143
+ result.observe(value, labelsToAttributes(labels));
144
+ }
145
+ }
146
+ });
147
+ }
148
+ return {
149
+ set: (labels, value) => {
150
+ const ttlMap = this.gaugeValues.get(name);
151
+ const labelsKey = JSON.stringify(labels);
152
+ ttlMap.set(labelsKey, value);
153
+ },
154
+ };
155
+ }
156
+ /**
157
+ * Creates or retrieves a histogram and returns a handle.
158
+ */
159
+ histogram(name, options) {
160
+ if (!this.histograms.has(name)) {
161
+ this.histograms.set(name, this.meter.createHistogram(name, options
162
+ ? {
163
+ ...(options.bucketBoundaries
164
+ ? {
165
+ advice: {
166
+ explicitBucketBoundaries: options.bucketBoundaries,
167
+ },
168
+ }
169
+ : {}),
170
+ ...(options.description
171
+ ? { description: options.description }
172
+ : {}),
173
+ ...(options.unit ? { unit: options.unit } : {}),
174
+ }
175
+ : undefined));
176
+ }
177
+ const histogram = this.histograms.get(name);
178
+ return {
179
+ observe: (labels, value) => {
180
+ histogram.record(value, labelsToAttributes(labels));
181
+ },
182
+ };
183
+ }
184
+ /**
185
+ * Increments a counter by name (creates if not exists). `options` is only
186
+ * applied on the instrument's first registration; see `counter`.
187
+ */
188
+ incCounter(name, labels, value = 1, options) {
189
+ this.counter(name, options).inc(labels, value);
190
+ }
191
+ /**
192
+ * Sets a gauge value by name (creates if not exists).
193
+ */
194
+ setGauge(name, labels, value) {
195
+ this.gauge(name).set(labels, value);
196
+ }
197
+ /**
198
+ * Observes a histogram value by name (creates if not exists). `options` is
199
+ * only applied on the instrument's first registration; see `histogram`.
200
+ */
201
+ observeHistogram(name, labels, value, options) {
202
+ this.histogram(name, options).observe(labels, value);
203
+ }
204
+ }
205
+ //# sourceMappingURL=metrics-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics-client.js","sourceRoot":"","sources":["../../src/node/metrics-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH;;GAEG;AACH,SAAS,kBAAkB,CAAC,MAAe;IACzC,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IACvB,MAAM,UAAU,GAAe,EAAE,CAAC;IAClC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,UAAU,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;GAEG;AACH,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,YAAY;AAChD,MAAM,iBAAiB,GAAG,MAAM,CAAC,CAAC,oDAAoD;AACtF,MAAM,yBAAyB,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,uBAAuB;AAUpE;;GAEG;AACH,MAAM,WAAW;IAKI;IACA;IALX,OAAO,GAAG,IAAI,GAAG,EAAsB,CAAC;IACxC,YAAY,GAA0C,IAAI,CAAC;IAEnE,YACmB,QAAgB,YAAY,EAC5B,aAAqB,iBAAiB;QADtC,UAAK,GAAL,KAAK,CAAuB;QAC5B,eAAU,GAAV,UAAU,CAA4B;QAEvD,yBAAyB;QACzB,IAAI,CAAC,YAAY,GAAG,WAAW,CAC7B,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,EACpB,yBAAyB,CAC1B,CAAC;QACF,qCAAqC;QACrC,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;IAC5B,CAAC;IAED,GAAG,CAAC,SAAiB,EAAE,KAAa;QAClC,0CAA0C;QAC1C,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YACzE,IAAI,CAAC,WAAW,EAAE,CAAC;QACrB,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE;YAC1B,KAAK;YACL,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,MAAM;QACJ,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;QAEzC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACxC,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBACxC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACK,OAAO;QACb,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACxC,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;gBACvC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACK,WAAW;QACjB,IAAI,SAAS,GAAkB,IAAI,CAAC;QACpC,IAAI,UAAU,GAAG,QAAQ,CAAC;QAE1B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACxC,IAAI,KAAK,CAAC,SAAS,GAAG,UAAU,EAAE,CAAC;gBACjC,UAAU,GAAG,KAAK,CAAC,SAAS,CAAC;gBAC7B,SAAS,GAAG,GAAG,CAAC;YAClB,CAAC;QACH,CAAC;QAED,IAAI,SAAS,EAAE,CAAC;YACd,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAED;;OAEG;IACH,OAAO;QACL,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YACjC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAC3B,CAAC;IACH,CAAC;CACF;AA6CD;;GAEG;AACH,MAAM,OAAO,aAAa;IAMK;IALrB,QAAQ,GAAG,IAAI,GAAG,EAAmB,CAAC;IACtC,UAAU,GAAG,IAAI,GAAG,EAAqB,CAAC;IAClD,+DAA+D;IACvD,WAAW,GAAG,IAAI,GAAG,EAAuB,CAAC;IAErD,YAA6B,KAAY;QAAZ,UAAK,GAAL,KAAK,CAAO;IAAG,CAAC;IAE7C;;OAEG;IACH,OAAO,CAAC,IAAY,EAAE,OAAwB;QAC5C,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;QACnE,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC;QAEzC,OAAO;YACL,GAAG,EAAE,CAAC,MAAe,EAAE,QAAgB,CAAC,EAAE,EAAE;gBAC1C,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;YACjD,CAAC;SACF,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,IAAY;QAChB,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAChC,MAAM,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;YACjC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAEnC,yDAAyD;YACzD,IAAI,CAAC,KAAK,CAAC,qBAAqB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,MAAM,EAAE,EAAE;gBAChE,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAC7C,IAAI,SAAS,EAAE,CAAC;oBACd,4CAA4C;oBAC5C,KAAK,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC;wBACpD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAW,CAAC;wBAC/C,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;oBACpD,CAAC;gBACH,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;QAED,OAAO;YACL,GAAG,EAAE,CAAC,MAAc,EAAE,KAAa,EAAE,EAAE;gBACrC,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC;gBAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;gBACzC,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;YAC/B,CAAC;SACF,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,SAAS,CAAC,IAAY,EAAE,OAA0B;QAChD,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,UAAU,CAAC,GAAG,CACjB,IAAI,EACJ,IAAI,CAAC,KAAK,CAAC,eAAe,CACxB,IAAI,EACJ,OAAO;gBACL,CAAC,CAAC;oBACE,GAAG,CAAC,OAAO,CAAC,gBAAgB;wBAC1B,CAAC,CAAC;4BACE,MAAM,EAAE;gCACN,wBAAwB,EAAE,OAAO,CAAC,gBAAgB;6BACnD;yBACF;wBACH,CAAC,CAAC,EAAE,CAAC;oBACP,GAAG,CAAC,OAAO,CAAC,WAAW;wBACrB,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE;wBACtC,CAAC,CAAC,EAAE,CAAC;oBACP,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBAChD;gBACH,CAAC,CAAC,SAAS,CACd,CACF,CAAC;QACJ,CAAC;QACD,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC;QAE7C,OAAO;YACL,OAAO,EAAE,CAAC,MAAc,EAAE,KAAa,EAAE,EAAE;gBACzC,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;YACtD,CAAC;SACF,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,UAAU,CACR,IAAY,EACZ,MAAe,EACf,QAAgB,CAAC,EACjB,OAAwB;QAExB,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACjD,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,IAAY,EAAE,MAAc,EAAE,KAAa;QAClD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACtC,CAAC;IAED;;;OAGG;IACH,gBAAgB,CACd,IAAY,EACZ,MAAc,EACd,KAAa,EACb,OAA0B;QAE1B,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACvD,CAAC;CACF"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Policy-Aware Safe Logger (Pino Wrapper)
3
+ *
4
+ * Wraps a Pino logger to redact forbidden fields (e.g. stack, prompt, code)
5
+ * from log call arguments so Tier 1 data is not written to stdout/log export.
6
+ *
7
+ * @see https://github.com/superblocksteam/engineering/blob/main/projects/o11y-refactor/epics/epic-c4-logging-strategy.md
8
+ */
9
+ import { type LoggingPolicyConfig } from "./log-processor.js";
10
+ /**
11
+ * Minimal logger interface compatible with Pino.
12
+ * Use createSafeLogger(pinoLogger, policy) with a Pino logger instance.
13
+ */
14
+ export interface SafeLoggerLike {
15
+ trace(...args: unknown[]): void;
16
+ debug(...args: unknown[]): void;
17
+ info(...args: unknown[]): void;
18
+ warn(...args: unknown[]): void;
19
+ error(...args: unknown[]): void;
20
+ fatal(...args: unknown[]): void;
21
+ child(bindings: Record<string, unknown>): SafeLoggerLike;
22
+ }
23
+ /**
24
+ * Redact and sanitize a single log argument: key-based (forbidden fields) and
25
+ * value-based (stack traces, PII, policy redactPatterns). Error instances are
26
+ * converted to a plain object first. Exported for use by callers (e.g. server
27
+ * RemoteLogger redactRecord) so stdout and OTLP paths share the same rules.
28
+ */
29
+ export declare function redactForbiddenFields(arg: unknown, policy: LoggingPolicyConfig): unknown;
30
+ /**
31
+ * Creates a logger wrapper that redacts policy-forbidden fields from log calls
32
+ * and applies the policy-effective log level (exportMode + envLevel) so that
33
+ * both the root and any child loggers respect exportMode (e.g. ERRORS_ONLY → warn floor).
34
+ *
35
+ * Use when logging in contexts where output may be exported (e.g. cloud-prem).
36
+ * Forbidden fields (stack, prompt, code, filePath, etc.) are replaced with
37
+ * "[REDACTED]" so they never appear in exported logs.
38
+ *
39
+ * @param baseLogger - Underlying Pino (or compatible) logger
40
+ * @param policy - Logging policy (e.g. from getLoggingPolicy(telemetryPolicy))
41
+ * @param envLevel - Optional env-configured level (e.g. SUPERBLOCKS_SERVER_LOG_LEVEL).
42
+ * When provided, base logger level is set from getMinimumPinoLevelFromLoggingPolicy(policy, envLevel)
43
+ * so exportMode (e.g. ERRORS_ONLY) is respected; children inherit this level in .child().
44
+ * @returns A logger that redacts forbidden fields and respects policy level (same interface as baseLogger)
45
+ *
46
+ * @example
47
+ * ```typescript
48
+ * const policy = getLoggingPolicy(telemetryPolicy);
49
+ * const safeLogger = createSafeLogger(logger, policy, envs.get('SUPERBLOCKS_SERVER_LOG_LEVEL'));
50
+ * safeLogger.error({ err, stack: err.stack }, 'Request failed');
51
+ * // Exported logs see stack: "[REDACTED]"
52
+ * ```
53
+ */
54
+ export declare function createSafeLogger<T extends SafeLoggerLike>(baseLogger: T, policy: LoggingPolicyConfig, envLevel?: string): T;
55
+ //# sourceMappingURL=safe-logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-logger.d.ts","sourceRoot":"","sources":["../../src/node/safe-logger.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,oBAAoB,CAAC;AAE5B;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChC,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChC,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC/B,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC/B,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChC,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,cAAc,CAAC;CAC1D;AA+BD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAaT;AAsCD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,cAAc,EACvD,UAAU,EAAE,CAAC,EACb,MAAM,EAAE,mBAAmB,EAC3B,QAAQ,CAAC,EAAE,MAAM,GAChB,CAAC,CA6EH"}
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Policy-Aware Safe Logger (Pino Wrapper)
3
+ *
4
+ * Wraps a Pino logger to redact forbidden fields (e.g. stack, prompt, code)
5
+ * from log call arguments so Tier 1 data is not written to stdout/log export.
6
+ *
7
+ * @see https://github.com/superblocksteam/engineering/blob/main/projects/o11y-refactor/epics/epic-c4-logging-strategy.md
8
+ */
9
+ import { sanitizeLogMessageForExport, sanitizeLogRecordForExport, } from "../common/log-sanitizer.js";
10
+ import { getMinimumPinoLevelFromLoggingPolicy, } from "./log-processor.js";
11
+ /** Log level methods only. "child" is handled separately so returned children are also wrapped with createSafeLogger. */
12
+ const LOG_METHODS = new Set([
13
+ "trace",
14
+ "debug",
15
+ "info",
16
+ "warn",
17
+ "error",
18
+ "fatal",
19
+ ]);
20
+ /**
21
+ * Convert an Error to a plain object so it can be redacted like any other object.
22
+ * Includes name, message, stack, and any own enumerable properties (e.g. code, statusCode).
23
+ */
24
+ function errorToPlainObject(err) {
25
+ const obj = {
26
+ message: err.message,
27
+ name: err.name,
28
+ stack: err.stack,
29
+ };
30
+ const errRecord = err;
31
+ for (const key of Object.keys(err)) {
32
+ if (!Object.prototype.hasOwnProperty.call(obj, key)) {
33
+ obj[key] = errRecord[key];
34
+ }
35
+ }
36
+ return obj;
37
+ }
38
+ /**
39
+ * Redact and sanitize a single log argument: key-based (forbidden fields) and
40
+ * value-based (stack traces, PII, policy redactPatterns). Error instances are
41
+ * converted to a plain object first. Exported for use by callers (e.g. server
42
+ * RemoteLogger redactRecord) so stdout and OTLP paths share the same rules.
43
+ */
44
+ export function redactForbiddenFields(arg, policy) {
45
+ if (arg === null || typeof arg !== "object") {
46
+ return arg;
47
+ }
48
+ if (arg instanceof Error) {
49
+ return redactForbiddenFields(errorToPlainObject(arg), policy);
50
+ }
51
+ return sanitizeLogRecordForExport(arg, policy.forbiddenFields, policy.redactPatterns, policy.sensitivePatterns);
52
+ }
53
+ function redactArg(arg, policy) {
54
+ return redactForbiddenFields(arg, policy);
55
+ }
56
+ /**
57
+ * Redact log call arguments: first arg (merge object) with key+value sanitization,
58
+ * and message string (second arg) with value-based sanitization (patterns, stack, PII).
59
+ */
60
+ function redactArgs(args, policy) {
61
+ if (args.length === 0)
62
+ return args;
63
+ const [first, ...rest] = args;
64
+ const redactedFirst = typeof first === "object" && first !== null
65
+ ? redactArg(first, policy)
66
+ : typeof first === "string"
67
+ ? sanitizeLogMessageForExport(first, policy.redactPatterns, policy.sensitivePatterns)
68
+ : first;
69
+ const redactedRest = rest.map((r, i) => i === 0 && typeof r === "string"
70
+ ? sanitizeLogMessageForExport(r, policy.redactPatterns, policy.sensitivePatterns)
71
+ : r);
72
+ return [redactedFirst, ...redactedRest];
73
+ }
74
+ /**
75
+ * Creates a logger wrapper that redacts policy-forbidden fields from log calls
76
+ * and applies the policy-effective log level (exportMode + envLevel) so that
77
+ * both the root and any child loggers respect exportMode (e.g. ERRORS_ONLY → warn floor).
78
+ *
79
+ * Use when logging in contexts where output may be exported (e.g. cloud-prem).
80
+ * Forbidden fields (stack, prompt, code, filePath, etc.) are replaced with
81
+ * "[REDACTED]" so they never appear in exported logs.
82
+ *
83
+ * @param baseLogger - Underlying Pino (or compatible) logger
84
+ * @param policy - Logging policy (e.g. from getLoggingPolicy(telemetryPolicy))
85
+ * @param envLevel - Optional env-configured level (e.g. SUPERBLOCKS_SERVER_LOG_LEVEL).
86
+ * When provided, base logger level is set from getMinimumPinoLevelFromLoggingPolicy(policy, envLevel)
87
+ * so exportMode (e.g. ERRORS_ONLY) is respected; children inherit this level in .child().
88
+ * @returns A logger that redacts forbidden fields and respects policy level (same interface as baseLogger)
89
+ *
90
+ * @example
91
+ * ```typescript
92
+ * const policy = getLoggingPolicy(telemetryPolicy);
93
+ * const safeLogger = createSafeLogger(logger, policy, envs.get('SUPERBLOCKS_SERVER_LOG_LEVEL'));
94
+ * safeLogger.error({ err, stack: err.stack }, 'Request failed');
95
+ * // Exported logs see stack: "[REDACTED]"
96
+ * ```
97
+ */
98
+ export function createSafeLogger(baseLogger, policy, envLevel) {
99
+ if (envLevel !== undefined) {
100
+ const effectiveLevel = getMinimumPinoLevelFromLoggingPolicy(policy, envLevel);
101
+ baseLogger.level = effectiveLevel;
102
+ }
103
+ return new Proxy(baseLogger, {
104
+ get(target, prop) {
105
+ if (typeof prop === "symbol")
106
+ return Reflect.get(target, prop);
107
+ const value = target[prop];
108
+ if (LOG_METHODS.has(prop) && typeof value === "function") {
109
+ return (...args) => {
110
+ let redacted;
111
+ try {
112
+ redacted = redactArgs(args, policy);
113
+ }
114
+ catch {
115
+ // Redaction can throw (e.g. Proxy with throwing getters, circular refs).
116
+ // Never emit original args — use a safe fallback so PII/Tier 1 is not exported.
117
+ redacted = [
118
+ { "[SafeLogger]": "redaction_failed" },
119
+ "[SafeLogger] Log omitted: redaction failed",
120
+ ];
121
+ target.error("[SafeLogger] Redaction failed; log omitted to avoid leaking data");
122
+ }
123
+ return value.apply(target, redacted);
124
+ };
125
+ }
126
+ if (prop === "child" && typeof value === "function") {
127
+ return (bindings) => {
128
+ // Redact forbidden fields from child bindings so they never appear in log output
129
+ // (e.g. user-email from req.logTags would otherwise be merged into every log line)
130
+ let redactedBindings;
131
+ try {
132
+ redactedBindings = redactArg(bindings, policy);
133
+ }
134
+ catch {
135
+ // Never pass original bindings — use empty so PII/Tier 1 is not exported.
136
+ redactedBindings = {};
137
+ target.error("[SafeLogger] Child bindings omitted: redaction failed");
138
+ }
139
+ const child = value.call(target, redactedBindings);
140
+ // Ensure child respects same level as parent (exportMode / localMaxLevel)
141
+ const parentWithLevel = target;
142
+ const childWithLevel = child;
143
+ if (parentWithLevel.level !== undefined &&
144
+ childWithLevel.level !== undefined) {
145
+ childWithLevel.level = parentWithLevel.level;
146
+ }
147
+ return createSafeLogger(child, policy);
148
+ };
149
+ }
150
+ return value;
151
+ },
152
+ });
153
+ }
154
+ //# sourceMappingURL=safe-logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-logger.js","sourceRoot":"","sources":["../../src/node/safe-logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Sanitizing Span Processor (Tier 2)
3
+ *
4
+ * Sanitizes spans before export per epic-a3-sanitized-traces.
5
+ * - All spans are passed to localProcessor (full fidelity for local/on-prem retention).
6
+ * - Only contract-compliant, sanitized spans are exported to Tier 2.
7
+ * - Fail-closed: when Tier 2 export is disabled, no exporter is attached.
8
+ */
9
+ import type { Context } from "@opentelemetry/api";
10
+ import type { ReadableSpan, Span, SpanExporter, SpanProcessor } from "@opentelemetry/sdk-trace-base";
11
+ import { TelemetryPolicyEvaluator } from "../common/policy-evaluator.js";
12
+ import { TraceSanitizer } from "../common/trace-sanitizer.js";
13
+ /** No-op span processor for the "local" path when only Tier 2 export is used. */
14
+ declare class NoopSpanProcessor implements SpanProcessor {
15
+ onStart(): void;
16
+ onEnd(): void;
17
+ shutdown(): Promise<void>;
18
+ forceFlush(): Promise<void>;
19
+ }
20
+ export declare const noopSpanProcessor: NoopSpanProcessor;
21
+ /** Logger interface for processor messages (e.g. queue full, export failure). */
22
+ interface SanitizingProcessorLogger {
23
+ debug?(obj: object, msg?: string): void;
24
+ debug?(msg: string): void;
25
+ error?(obj: object, msg?: string): void;
26
+ error?(msg: string): void;
27
+ warn(obj: object, msg?: string): void;
28
+ warn(msg: string): void;
29
+ }
30
+ /**
31
+ * Span processor that sanitizes spans before Tier 2 export.
32
+ *
33
+ * CRITICAL: This processor owns the export path. The exporter is internal.
34
+ * For Tier 1: All spans passed to localProcessor (e.g. no-op or local collector).
35
+ * For Tier 2: Only contract-compliant spans, sanitized, then batched and exported.
36
+ *
37
+ * NOTE: The wrapped tier2Exporter must tolerate concurrent export() calls.
38
+ * The periodic timer and the batch-size trigger can both fire flushExports()
39
+ * in the same tick. OTLPTraceExporter is safe; custom exporters should verify.
40
+ */
41
+ export declare class SanitizingSpanProcessor implements SpanProcessor {
42
+ private readonly exportTimeoutMs;
43
+ private readonly sanitizer;
44
+ private readonly localProcessor;
45
+ private readonly tier2Exporter;
46
+ private readonly logger;
47
+ private pendingExports;
48
+ private exportTimer;
49
+ private droppedQueueFull;
50
+ /** Tracks in-flight fire-and-forget flushes so shutdown/forceFlush can await them. */
51
+ private readonly inflight;
52
+ constructor(policyEvaluator: TelemetryPolicyEvaluator, localProcessor: SpanProcessor, tier2Exporter: SpanExporter | null, traceSanitizer: TraceSanitizer, logger: SanitizingProcessorLogger, exportTimeoutMs?: number);
53
+ onStart(span: Span, parentContext: Context): void;
54
+ onEnd(span: ReadableSpan): void;
55
+ /** Fire-and-forget batch flush — tracks the in-flight promise so shutdown/forceFlush can await it. */
56
+ private flushExports;
57
+ /**
58
+ * Awaitable batch flush for drain paths (shutdown, forceFlush).
59
+ * Always resolves — times out after exportTimeoutMs if the exporter
60
+ * never calls its callback (e.g. broken socket, hung downstream).
61
+ */
62
+ private flushExportsAsync;
63
+ shutdown(): Promise<void>;
64
+ forceFlush(): Promise<void>;
65
+ }
66
+ export {};
67
+ //# sourceMappingURL=sanitizing-processor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitizing-processor.d.ts","sourceRoot":"","sources":["../../src/node/sanitizing-processor.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,KAAK,EACV,YAAY,EACZ,IAAI,EACJ,YAAY,EACZ,aAAa,EACd,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAO9D,iFAAiF;AACjF,cAAM,iBAAkB,YAAW,aAAa;IAC9C,OAAO,IAAI,IAAI;IACf,KAAK,IAAI,IAAI;IACP,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IACzB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAClC;AAED,eAAO,MAAM,iBAAiB,mBAA0B,CAAC;AAGzD,iFAAiF;AACjF,UAAU,yBAAyB;IACjC,KAAK,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,KAAK,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,KAAK,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAKD;;;;;;;;;;GAUG;AACH,qBAAa,uBAAwB,YAAW,aAAa;IAiBzD,OAAO,CAAC,QAAQ,CAAC,eAAe;IAhBlC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiB;IAC3C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAgB;IAC/C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAsB;IACpD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;IACnD,OAAO,CAAC,cAAc,CAAsB;IAC5C,OAAO,CAAC,WAAW,CAA+C;IAClE,OAAO,CAAC,gBAAgB,CAAS;IACjC,sFAAsF;IACtF,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4B;gBAGnD,eAAe,EAAE,wBAAwB,EACzC,cAAc,EAAE,aAAa,EAC7B,aAAa,EAAE,YAAY,GAAG,IAAI,EAClC,cAAc,EAAE,cAAc,EAC9B,MAAM,EAAE,yBAAyB,EAChB,eAAe,SAAO;IAoBzC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,GAAG,IAAI;IAIjD,KAAK,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI;IA8B/B,sGAAsG;IACtG,OAAO,CAAC,YAAY;IAOpB;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAoDnB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAezB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAUlC"}
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Sanitizing Span Processor (Tier 2)
3
+ *
4
+ * Sanitizes spans before export per epic-a3-sanitized-traces.
5
+ * - All spans are passed to localProcessor (full fidelity for local/on-prem retention).
6
+ * - Only contract-compliant, sanitized spans are exported to Tier 2.
7
+ * - Fail-closed: when Tier 2 export is disabled, no exporter is attached.
8
+ */
9
+ import { ExportResultCode } from "@opentelemetry/core";
10
+ import { TelemetryTier } from "../types/policy.js";
11
+ const BATCH_SIZE = 512;
12
+ /** Max pending spans before dropping. Aligns with BatchSpanProcessor / resilient-exporter queue limits. */
13
+ const MAX_PENDING_EXPORTS = 2048;
14
+ /** No-op span processor for the "local" path when only Tier 2 export is used. */
15
+ class NoopSpanProcessor {
16
+ onStart() { }
17
+ onEnd() { }
18
+ async shutdown() { }
19
+ async forceFlush() { }
20
+ }
21
+ export const noopSpanProcessor = new NoopSpanProcessor();
22
+ const EXPORT_INTERVAL_MS = 5000;
23
+ /**
24
+ * Span processor that sanitizes spans before Tier 2 export.
25
+ *
26
+ * CRITICAL: This processor owns the export path. The exporter is internal.
27
+ * For Tier 1: All spans passed to localProcessor (e.g. no-op or local collector).
28
+ * For Tier 2: Only contract-compliant spans, sanitized, then batched and exported.
29
+ *
30
+ * NOTE: The wrapped tier2Exporter must tolerate concurrent export() calls.
31
+ * The periodic timer and the batch-size trigger can both fire flushExports()
32
+ * in the same tick. OTLPTraceExporter is safe; custom exporters should verify.
33
+ */
34
+ export class SanitizingSpanProcessor {
35
+ exportTimeoutMs;
36
+ sanitizer;
37
+ localProcessor;
38
+ tier2Exporter;
39
+ logger;
40
+ pendingExports = [];
41
+ exportTimer = null;
42
+ droppedQueueFull = false;
43
+ /** Tracks in-flight fire-and-forget flushes so shutdown/forceFlush can await them. */
44
+ inflight = new Set();
45
+ constructor(policyEvaluator, localProcessor, tier2Exporter, traceSanitizer, logger, exportTimeoutMs = 5000) {
46
+ this.exportTimeoutMs = exportTimeoutMs;
47
+ this.sanitizer = traceSanitizer;
48
+ this.localProcessor = localProcessor;
49
+ this.logger = logger;
50
+ this.tier2Exporter = policyEvaluator.isExportEnabled(TelemetryTier.TIER_2_OPERATIONAL)
51
+ ? tier2Exporter
52
+ : null;
53
+ if (this.tier2Exporter) {
54
+ this.exportTimer = setInterval(() => this.flushExports("periodic"), EXPORT_INTERVAL_MS);
55
+ this.exportTimer.unref();
56
+ }
57
+ }
58
+ onStart(span, parentContext) {
59
+ this.localProcessor.onStart(span, parentContext);
60
+ }
61
+ onEnd(span) {
62
+ this.localProcessor.onEnd(span);
63
+ if (this.tier2Exporter) {
64
+ const sanitized = this.sanitizer.sanitize(span);
65
+ if (sanitized) {
66
+ if (this.pendingExports.length >= MAX_PENDING_EXPORTS) {
67
+ if (!this.droppedQueueFull) {
68
+ this.droppedQueueFull = true;
69
+ const msg = "Tier 2 pending queue full, dropping new spans until next flush";
70
+ const log = this.logger.error ?? this.logger.warn;
71
+ log({
72
+ component: "SanitizingSpanProcessor",
73
+ maxPendingExports: MAX_PENDING_EXPORTS,
74
+ }, msg);
75
+ }
76
+ }
77
+ else {
78
+ this.pendingExports.push(sanitized);
79
+ if (this.pendingExports.length >= BATCH_SIZE) {
80
+ this.flushExports("batch");
81
+ }
82
+ }
83
+ }
84
+ }
85
+ }
86
+ /** Fire-and-forget batch flush — tracks the in-flight promise so shutdown/forceFlush can await it. */
87
+ flushExports(phase) {
88
+ const p = this.flushExportsAsync(phase).finally(() => this.inflight.delete(p));
89
+ this.inflight.add(p);
90
+ }
91
+ /**
92
+ * Awaitable batch flush for drain paths (shutdown, forceFlush).
93
+ * Always resolves — times out after exportTimeoutMs if the exporter
94
+ * never calls its callback (e.g. broken socket, hung downstream).
95
+ */
96
+ flushExportsAsync(phase) {
97
+ if (!this.tier2Exporter || this.pendingExports.length === 0) {
98
+ return Promise.resolve();
99
+ }
100
+ if (this.pendingExports.length < MAX_PENDING_EXPORTS) {
101
+ this.droppedQueueFull = false;
102
+ }
103
+ const batch = this.pendingExports.splice(0, BATCH_SIZE);
104
+ return new Promise((resolve) => {
105
+ const timer = setTimeout(() => {
106
+ this.logger.warn({
107
+ component: "SanitizingSpanProcessor",
108
+ batchSize: batch.length,
109
+ exportTimeoutMs: this.exportTimeoutMs,
110
+ phase,
111
+ }, "Tier 2 span export timed out");
112
+ resolve();
113
+ }, this.exportTimeoutMs).unref();
114
+ try {
115
+ this.tier2Exporter.export(batch, (result) => {
116
+ clearTimeout(timer);
117
+ if (result.code !== ExportResultCode.SUCCESS) {
118
+ this.logger.warn({
119
+ component: "SanitizingSpanProcessor",
120
+ err: result.error,
121
+ batchSize: batch.length,
122
+ }, "Tier 2 span export failed");
123
+ }
124
+ resolve();
125
+ });
126
+ }
127
+ catch (err) {
128
+ clearTimeout(timer);
129
+ this.logger.warn({
130
+ component: "SanitizingSpanProcessor",
131
+ err,
132
+ batchSize: batch.length,
133
+ }, "Tier 2 span export threw synchronously");
134
+ resolve();
135
+ }
136
+ });
137
+ }
138
+ async shutdown() {
139
+ if (this.exportTimer) {
140
+ clearInterval(this.exportTimer);
141
+ this.exportTimer = null;
142
+ }
143
+ while (this.pendingExports.length > 0) {
144
+ await this.flushExportsAsync("shutdown");
145
+ }
146
+ await Promise.allSettled([...this.inflight]);
147
+ await this.localProcessor.shutdown();
148
+ if (this.tier2Exporter) {
149
+ await this.tier2Exporter.shutdown();
150
+ }
151
+ }
152
+ async forceFlush() {
153
+ while (this.pendingExports.length > 0) {
154
+ await this.flushExportsAsync("forceFlush");
155
+ }
156
+ await Promise.allSettled([...this.inflight]);
157
+ await this.localProcessor.forceFlush();
158
+ if (this.tier2Exporter?.forceFlush) {
159
+ await this.tier2Exporter.forceFlush();
160
+ }
161
+ }
162
+ }
163
+ //# sourceMappingURL=sanitizing-processor.js.map