@dxos/observability 0.8.3 → 0.8.4-main.1068cf700f

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 (348) hide show
  1. package/dist/lib/browser/chunk-J5LGTIGS.mjs +10 -0
  2. package/dist/lib/browser/chunk-K4VFBKST.mjs +13 -0
  3. package/dist/lib/browser/chunk-K4VFBKST.mjs.map +7 -0
  4. package/dist/lib/browser/index.mjs +1066 -34
  5. package/dist/lib/browser/index.mjs.map +4 -4
  6. package/dist/lib/browser/log-processor-FDLTDQEM.mjs +45 -0
  7. package/dist/lib/browser/log-processor-FDLTDQEM.mjs.map +7 -0
  8. package/dist/lib/browser/logs-ATTRIUTL.mjs +113 -0
  9. package/dist/lib/browser/logs-ATTRIUTL.mjs.map +7 -0
  10. package/dist/lib/browser/meta.json +1 -1
  11. package/dist/lib/browser/metrics-PKTV6IGF.mjs +130 -0
  12. package/dist/lib/browser/metrics-PKTV6IGF.mjs.map +7 -0
  13. package/dist/lib/browser/traces-browser-XYXBF5ZX.mjs +62 -0
  14. package/dist/lib/browser/traces-browser-XYXBF5ZX.mjs.map +7 -0
  15. package/dist/lib/node-esm/chunk-FEVP3MK4.mjs +15 -0
  16. package/dist/lib/node-esm/chunk-FEVP3MK4.mjs.map +7 -0
  17. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
  18. package/dist/lib/node-esm/index.mjs +1070 -34
  19. package/dist/lib/node-esm/index.mjs.map +4 -4
  20. package/dist/lib/node-esm/log-processor-TKJVJJSJ.mjs +46 -0
  21. package/dist/lib/node-esm/log-processor-TKJVJJSJ.mjs.map +7 -0
  22. package/dist/lib/node-esm/logs-7J45KLM7.mjs +114 -0
  23. package/dist/lib/node-esm/logs-7J45KLM7.mjs.map +7 -0
  24. package/dist/lib/node-esm/meta.json +1 -1
  25. package/dist/lib/node-esm/metrics-H7DDLYSG.mjs +131 -0
  26. package/dist/lib/node-esm/metrics-H7DDLYSG.mjs.map +7 -0
  27. package/dist/lib/node-esm/traces-KMTHMYFX.mjs +44 -0
  28. package/dist/lib/node-esm/traces-KMTHMYFX.mjs.map +7 -0
  29. package/dist/types/src/cli-observability-secrets.json +3 -4
  30. package/dist/types/src/extensions/index.d.ts +3 -0
  31. package/dist/types/src/extensions/index.d.ts.map +1 -0
  32. package/dist/types/src/extensions/index.js +6 -0
  33. package/dist/types/src/extensions/index.js.map +1 -0
  34. package/dist/types/src/extensions/otel/extension.d.ts +23 -0
  35. package/dist/types/src/extensions/otel/extension.d.ts.map +1 -0
  36. package/dist/types/src/extensions/otel/extension.js +124 -0
  37. package/dist/types/src/extensions/otel/extension.js.map +1 -0
  38. package/dist/types/src/extensions/otel/index.d.ts +2 -0
  39. package/dist/types/src/extensions/otel/index.d.ts.map +1 -0
  40. package/dist/types/src/extensions/otel/index.js +5 -0
  41. package/dist/types/src/extensions/otel/index.js.map +1 -0
  42. package/dist/types/src/{otel → extensions/otel}/logs.d.ts +4 -3
  43. package/dist/types/src/extensions/otel/logs.d.ts.map +1 -0
  44. package/dist/types/src/extensions/otel/logs.js +104 -0
  45. package/dist/types/src/extensions/otel/logs.js.map +1 -0
  46. package/dist/types/src/{otel → extensions/otel}/metrics.d.ts +0 -1
  47. package/dist/types/src/extensions/otel/metrics.d.ts.map +1 -0
  48. package/dist/types/src/{otel → extensions/otel}/metrics.js +6 -12
  49. package/dist/types/src/extensions/otel/metrics.js.map +1 -0
  50. package/dist/types/src/{otel → extensions/otel}/otel.d.ts +3 -3
  51. package/dist/types/src/extensions/otel/otel.d.ts.map +1 -0
  52. package/dist/types/src/{otel → extensions/otel}/otel.js +1 -1
  53. package/dist/types/src/extensions/otel/otel.js.map +1 -0
  54. package/dist/types/src/extensions/otel/traces-browser.d.ts.map +1 -0
  55. package/dist/types/src/extensions/otel/traces-browser.js +44 -0
  56. package/dist/types/src/extensions/otel/traces-browser.js.map +1 -0
  57. package/dist/types/src/extensions/otel/traces.d.ts.map +1 -0
  58. package/dist/types/src/extensions/otel/traces.js +38 -0
  59. package/dist/types/src/extensions/otel/traces.js.map +1 -0
  60. package/dist/types/src/extensions/posthog/extension.d.ts +15 -0
  61. package/dist/types/src/extensions/posthog/extension.d.ts.map +1 -0
  62. package/dist/types/src/extensions/posthog/extension.js +143 -0
  63. package/dist/types/src/extensions/posthog/extension.js.map +1 -0
  64. package/dist/types/src/extensions/posthog/index.d.ts +2 -0
  65. package/dist/types/src/extensions/posthog/index.d.ts.map +1 -0
  66. package/dist/types/src/extensions/posthog/index.js +5 -0
  67. package/dist/types/src/extensions/posthog/index.js.map +1 -0
  68. package/dist/types/src/extensions/posthog/log-processor.d.ts +3 -0
  69. package/dist/types/src/extensions/posthog/log-processor.d.ts.map +1 -0
  70. package/dist/types/src/extensions/posthog/log-processor.js +45 -0
  71. package/dist/types/src/extensions/posthog/log-processor.js.map +1 -0
  72. package/dist/types/src/extensions/posthog/log-processor.test.d.ts +2 -0
  73. package/dist/types/src/extensions/posthog/log-processor.test.d.ts.map +1 -0
  74. package/dist/types/src/extensions/posthog/log-processor.test.js +146 -0
  75. package/dist/types/src/extensions/posthog/log-processor.test.js.map +1 -0
  76. package/dist/types/src/extensions/stub.d.ts +3 -0
  77. package/dist/types/src/extensions/stub.d.ts.map +1 -0
  78. package/dist/types/src/extensions/stub.js +16 -0
  79. package/dist/types/src/extensions/stub.js.map +1 -0
  80. package/dist/types/src/index.d.ts +4 -2
  81. package/dist/types/src/index.d.ts.map +1 -1
  82. package/dist/types/src/index.js +5 -3
  83. package/dist/types/src/index.js.map +1 -1
  84. package/dist/types/src/log-buffer.d.ts +34 -0
  85. package/dist/types/src/log-buffer.d.ts.map +1 -0
  86. package/dist/types/src/log-buffer.js +70 -0
  87. package/dist/types/src/log-buffer.js.map +1 -0
  88. package/dist/types/src/log-buffer.test.d.ts +2 -0
  89. package/dist/types/src/log-buffer.test.d.ts.map +1 -0
  90. package/dist/types/src/log-buffer.test.js +107 -0
  91. package/dist/types/src/log-buffer.test.js.map +1 -0
  92. package/dist/types/src/observability-extension.d.ts +74 -0
  93. package/dist/types/src/observability-extension.d.ts.map +1 -0
  94. package/dist/types/src/observability-extension.js +5 -0
  95. package/dist/types/src/observability-extension.js.map +1 -0
  96. package/dist/types/src/observability.d.ts +32 -110
  97. package/dist/types/src/observability.d.ts.map +1 -1
  98. package/dist/types/src/observability.js +176 -455
  99. package/dist/types/src/observability.js.map +1 -1
  100. package/dist/types/src/observability.test.d.ts +2 -0
  101. package/dist/types/src/observability.test.d.ts.map +1 -0
  102. package/dist/types/src/observability.test.js +312 -0
  103. package/dist/types/src/observability.test.js.map +1 -0
  104. package/dist/types/src/providers/client-observability.d.ts +11 -0
  105. package/dist/types/src/providers/client-observability.d.ts.map +1 -0
  106. package/dist/types/src/providers/client-observability.js +200 -0
  107. package/dist/types/src/providers/client-observability.js.map +1 -0
  108. package/dist/types/src/providers/index.d.ts +4 -0
  109. package/dist/types/src/providers/index.d.ts.map +1 -0
  110. package/dist/types/src/providers/index.js +7 -0
  111. package/dist/types/src/providers/index.js.map +1 -0
  112. package/dist/types/src/providers/ip-data.d.ts +5 -0
  113. package/dist/types/src/providers/ip-data.d.ts.map +1 -0
  114. package/dist/types/src/providers/ip-data.js +55 -0
  115. package/dist/types/src/providers/ip-data.js.map +1 -0
  116. package/dist/types/src/providers/storage.d.ts +3 -0
  117. package/dist/types/src/providers/storage.d.ts.map +1 -0
  118. package/dist/types/src/providers/storage.js +19 -0
  119. package/dist/types/src/providers/storage.js.map +1 -0
  120. package/dist/types/src/storage/browser.d.ts +19 -0
  121. package/dist/types/src/storage/browser.d.ts.map +1 -0
  122. package/dist/types/src/storage/browser.js +58 -0
  123. package/dist/types/src/storage/browser.js.map +1 -0
  124. package/dist/types/src/storage/index.d.ts +2 -0
  125. package/dist/types/src/storage/index.d.ts.map +1 -0
  126. package/{src/segment/index.ts → dist/types/src/storage/index.js} +1 -2
  127. package/dist/types/src/storage/index.js.map +1 -0
  128. package/dist/types/src/storage/node.d.ts +26 -0
  129. package/dist/types/src/storage/node.d.ts.map +1 -0
  130. package/dist/types/src/storage/node.js +92 -0
  131. package/dist/types/src/storage/node.js.map +1 -0
  132. package/dist/types/src/storage/node.test.d.ts +2 -0
  133. package/dist/types/src/storage/node.test.d.ts.map +1 -0
  134. package/dist/types/src/storage/node.test.js +103 -0
  135. package/dist/types/src/storage/node.test.js.map +1 -0
  136. package/dist/types/tsconfig.tsbuildinfo +1 -1
  137. package/package.json +42 -63
  138. package/src/cli-observability-secrets.json +3 -4
  139. package/src/extensions/index.ts +6 -0
  140. package/src/extensions/otel/extension.ts +178 -0
  141. package/src/extensions/otel/index.ts +5 -0
  142. package/src/extensions/otel/logs.ts +134 -0
  143. package/src/{otel → extensions/otel}/metrics.ts +4 -21
  144. package/src/{otel → extensions/otel}/otel.ts +4 -4
  145. package/src/extensions/otel/traces-browser.ts +57 -0
  146. package/src/extensions/otel/traces.ts +49 -0
  147. package/src/extensions/posthog/extension.ts +172 -0
  148. package/src/extensions/posthog/index.ts +5 -0
  149. package/src/extensions/posthog/log-processor.test.ts +185 -0
  150. package/src/extensions/posthog/log-processor.ts +54 -0
  151. package/src/extensions/stub.ts +19 -0
  152. package/src/index.ts +5 -3
  153. package/src/log-buffer.test.ts +134 -0
  154. package/src/log-buffer.ts +101 -0
  155. package/src/observability-extension.ts +94 -0
  156. package/src/observability.test.ts +531 -0
  157. package/src/observability.ts +236 -577
  158. package/src/providers/client-observability.ts +253 -0
  159. package/src/providers/index.ts +7 -0
  160. package/src/providers/ip-data.ts +88 -0
  161. package/src/providers/storage.ts +23 -0
  162. package/src/storage/browser.ts +61 -0
  163. package/src/{sentry → storage}/index.ts +0 -1
  164. package/src/storage/node.test.ts +130 -0
  165. package/src/{helpers/node-observability.ts → storage/node.ts} +42 -70
  166. package/dist/lib/browser/chunk-G6EE7HFV.mjs +0 -147
  167. package/dist/lib/browser/chunk-G6EE7HFV.mjs.map +0 -7
  168. package/dist/lib/browser/chunk-JA5VJRKF.mjs +0 -164
  169. package/dist/lib/browser/chunk-JA5VJRKF.mjs.map +0 -7
  170. package/dist/lib/browser/chunk-KDP3SESE.mjs +0 -1
  171. package/dist/lib/browser/chunk-YQJELTRP.mjs +0 -996
  172. package/dist/lib/browser/chunk-YQJELTRP.mjs.map +0 -7
  173. package/dist/lib/browser/observability-HDE3I7TA.mjs +0 -10
  174. package/dist/lib/browser/otel-LHAFLNBQ.mjs +0 -277
  175. package/dist/lib/browser/otel-LHAFLNBQ.mjs.map +0 -7
  176. package/dist/lib/browser/segment/index.mjs +0 -11
  177. package/dist/lib/browser/segment/index.mjs.map +0 -7
  178. package/dist/lib/browser/sentry/index.mjs +0 -24
  179. package/dist/lib/browser/sentry/index.mjs.map +0 -7
  180. package/dist/lib/browser/sentry-log-processor-625AISXI.mjs +0 -146
  181. package/dist/lib/browser/sentry-log-processor-625AISXI.mjs.map +0 -7
  182. package/dist/lib/node/chunk-325GAGFA.cjs +0 -213
  183. package/dist/lib/node/chunk-325GAGFA.cjs.map +0 -7
  184. package/dist/lib/node/chunk-BZHVFSLF.cjs +0 -1025
  185. package/dist/lib/node/chunk-BZHVFSLF.cjs.map +0 -7
  186. package/dist/lib/node/chunk-GIYJMZEQ.cjs +0 -2
  187. package/dist/lib/node/chunk-GIYJMZEQ.cjs.map +0 -7
  188. package/dist/lib/node/chunk-MZ3PMDTP.cjs +0 -163
  189. package/dist/lib/node/chunk-MZ3PMDTP.cjs.map +0 -7
  190. package/dist/lib/node/index.cjs +0 -60
  191. package/dist/lib/node/index.cjs.map +0 -7
  192. package/dist/lib/node/meta.json +0 -1
  193. package/dist/lib/node/observability-E2NGRIEN.cjs +0 -32
  194. package/dist/lib/node/observability-E2NGRIEN.cjs.map +0 -7
  195. package/dist/lib/node/otel-VF5YNCR3.cjs +0 -278
  196. package/dist/lib/node/otel-VF5YNCR3.cjs.map +0 -7
  197. package/dist/lib/node/segment/index.cjs +0 -33
  198. package/dist/lib/node/segment/index.cjs.map +0 -7
  199. package/dist/lib/node/sentry/index.cjs +0 -46
  200. package/dist/lib/node/sentry/index.cjs.map +0 -7
  201. package/dist/lib/node/sentry-log-processor-CCV4RL7N.cjs +0 -164
  202. package/dist/lib/node/sentry-log-processor-CCV4RL7N.cjs.map +0 -7
  203. package/dist/lib/node-esm/chunk-AZMSBUWR.mjs +0 -202
  204. package/dist/lib/node-esm/chunk-AZMSBUWR.mjs.map +0 -7
  205. package/dist/lib/node-esm/chunk-H7Y2DDUN.mjs +0 -135
  206. package/dist/lib/node-esm/chunk-H7Y2DDUN.mjs.map +0 -7
  207. package/dist/lib/node-esm/chunk-M7QJLFGR.mjs +0 -997
  208. package/dist/lib/node-esm/chunk-M7QJLFGR.mjs.map +0 -7
  209. package/dist/lib/node-esm/chunk-YJ4KVBWC.mjs +0 -2
  210. package/dist/lib/node-esm/chunk-YJ4KVBWC.mjs.map +0 -7
  211. package/dist/lib/node-esm/observability-7BTI46NM.mjs +0 -11
  212. package/dist/lib/node-esm/observability-7BTI46NM.mjs.map +0 -7
  213. package/dist/lib/node-esm/otel-AF5TSABC.mjs +0 -260
  214. package/dist/lib/node-esm/otel-AF5TSABC.mjs.map +0 -7
  215. package/dist/lib/node-esm/segment/index.mjs +0 -12
  216. package/dist/lib/node-esm/segment/index.mjs.map +0 -7
  217. package/dist/lib/node-esm/sentry/index.mjs +0 -25
  218. package/dist/lib/node-esm/sentry/index.mjs.map +0 -7
  219. package/dist/lib/node-esm/sentry-log-processor-HPUPCMRG.mjs +0 -147
  220. package/dist/lib/node-esm/sentry-log-processor-HPUPCMRG.mjs.map +0 -7
  221. package/dist/types/src/helpers/browser-observability.d.ts +0 -17
  222. package/dist/types/src/helpers/browser-observability.d.ts.map +0 -1
  223. package/dist/types/src/helpers/browser-observability.js +0 -140
  224. package/dist/types/src/helpers/browser-observability.js.map +0 -1
  225. package/dist/types/src/helpers/common.d.ts +0 -12
  226. package/dist/types/src/helpers/common.d.ts.map +0 -1
  227. package/dist/types/src/helpers/common.js +0 -23
  228. package/dist/types/src/helpers/common.js.map +0 -1
  229. package/dist/types/src/helpers/index.d.ts +0 -6
  230. package/dist/types/src/helpers/index.d.ts.map +0 -1
  231. package/dist/types/src/helpers/index.js +0 -9
  232. package/dist/types/src/helpers/index.js.map +0 -1
  233. package/dist/types/src/helpers/map-spaces.d.ts +0 -18
  234. package/dist/types/src/helpers/map-spaces.d.ts.map +0 -1
  235. package/dist/types/src/helpers/map-spaces.js +0 -37
  236. package/dist/types/src/helpers/map-spaces.js.map +0 -1
  237. package/dist/types/src/helpers/node-observability.d.ts +0 -24
  238. package/dist/types/src/helpers/node-observability.d.ts.map +0 -1
  239. package/dist/types/src/helpers/node-observability.js +0 -101
  240. package/dist/types/src/helpers/node-observability.js.map +0 -1
  241. package/dist/types/src/helpers/setup-telemetry-listeners.d.ts +0 -4
  242. package/dist/types/src/helpers/setup-telemetry-listeners.d.ts.map +0 -1
  243. package/dist/types/src/helpers/setup-telemetry-listeners.js +0 -97
  244. package/dist/types/src/helpers/setup-telemetry-listeners.js.map +0 -1
  245. package/dist/types/src/otel/index.d.ts +0 -5
  246. package/dist/types/src/otel/index.d.ts.map +0 -1
  247. package/dist/types/src/otel/index.js +0 -8
  248. package/dist/types/src/otel/index.js.map +0 -1
  249. package/dist/types/src/otel/logs.d.ts.map +0 -1
  250. package/dist/types/src/otel/logs.js +0 -71
  251. package/dist/types/src/otel/logs.js.map +0 -1
  252. package/dist/types/src/otel/metrics.d.ts.map +0 -1
  253. package/dist/types/src/otel/metrics.js.map +0 -1
  254. package/dist/types/src/otel/otel.d.ts.map +0 -1
  255. package/dist/types/src/otel/otel.js.map +0 -1
  256. package/dist/types/src/otel/traces-browser.d.ts.map +0 -1
  257. package/dist/types/src/otel/traces-browser.js +0 -47
  258. package/dist/types/src/otel/traces-browser.js.map +0 -1
  259. package/dist/types/src/otel/traces.d.ts.map +0 -1
  260. package/dist/types/src/otel/traces.js +0 -40
  261. package/dist/types/src/otel/traces.js.map +0 -1
  262. package/dist/types/src/segment/base.d.ts +0 -15
  263. package/dist/types/src/segment/base.d.ts.map +0 -1
  264. package/dist/types/src/segment/base.js +0 -50
  265. package/dist/types/src/segment/base.js.map +0 -1
  266. package/dist/types/src/segment/browser.d.ts +0 -15
  267. package/dist/types/src/segment/browser.d.ts.map +0 -1
  268. package/dist/types/src/segment/browser.js +0 -67
  269. package/dist/types/src/segment/browser.js.map +0 -1
  270. package/dist/types/src/segment/index.d.ts +0 -3
  271. package/dist/types/src/segment/index.d.ts.map +0 -1
  272. package/dist/types/src/segment/index.js +0 -6
  273. package/dist/types/src/segment/index.js.map +0 -1
  274. package/dist/types/src/segment/node.d.ts +0 -16
  275. package/dist/types/src/segment/node.d.ts.map +0 -1
  276. package/dist/types/src/segment/node.js +0 -83
  277. package/dist/types/src/segment/node.js.map +0 -1
  278. package/dist/types/src/segment/types.d.ts +0 -52
  279. package/dist/types/src/segment/types.d.ts.map +0 -1
  280. package/dist/types/src/segment/types.js +0 -18
  281. package/dist/types/src/segment/types.js.map +0 -1
  282. package/dist/types/src/sentry/browser.d.ts +0 -32
  283. package/dist/types/src/sentry/browser.d.ts.map +0 -1
  284. package/dist/types/src/sentry/browser.js +0 -112
  285. package/dist/types/src/sentry/browser.js.map +0 -1
  286. package/dist/types/src/sentry/index.d.ts +0 -3
  287. package/dist/types/src/sentry/index.d.ts.map +0 -1
  288. package/dist/types/src/sentry/index.js +0 -6
  289. package/dist/types/src/sentry/index.js.map +0 -1
  290. package/dist/types/src/sentry/node.d.ts +0 -32
  291. package/dist/types/src/sentry/node.d.ts.map +0 -1
  292. package/dist/types/src/sentry/node.js +0 -111
  293. package/dist/types/src/sentry/node.js.map +0 -1
  294. package/dist/types/src/sentry/node.node.test.d.ts +0 -2
  295. package/dist/types/src/sentry/node.node.test.d.ts.map +0 -1
  296. package/dist/types/src/sentry/node.node.test.js +0 -34
  297. package/dist/types/src/sentry/node.node.test.js.map +0 -1
  298. package/dist/types/src/sentry/sentry-log-processor.d.ts +0 -9
  299. package/dist/types/src/sentry/sentry-log-processor.d.ts.map +0 -1
  300. package/dist/types/src/sentry/sentry-log-processor.js +0 -149
  301. package/dist/types/src/sentry/sentry-log-processor.js.map +0 -1
  302. package/dist/types/src/sentry/sentry.node.test.d.ts +0 -2
  303. package/dist/types/src/sentry/sentry.node.test.d.ts.map +0 -1
  304. package/dist/types/src/sentry/sentry.node.test.js +0 -28
  305. package/dist/types/src/sentry/sentry.node.test.js.map +0 -1
  306. package/dist/types/src/sentry/types.d.ts +0 -18
  307. package/dist/types/src/sentry/types.d.ts.map +0 -1
  308. package/dist/types/src/sentry/types.js +0 -4
  309. package/dist/types/src/sentry/types.js.map +0 -1
  310. package/dist/types/src/testing/index.d.ts +0 -2
  311. package/dist/types/src/testing/index.d.ts.map +0 -1
  312. package/dist/types/src/testing/index.js +0 -5
  313. package/dist/types/src/testing/index.js.map +0 -1
  314. package/dist/types/src/testing/testkit/browser.d.ts +0 -2
  315. package/dist/types/src/testing/testkit/browser.d.ts.map +0 -1
  316. package/dist/types/src/testing/testkit/browser.js +0 -7
  317. package/dist/types/src/testing/testkit/browser.js.map +0 -1
  318. package/dist/types/src/testing/testkit/index.d.ts +0 -2
  319. package/dist/types/src/testing/testkit/index.d.ts.map +0 -1
  320. package/dist/types/src/testing/testkit/index.js +0 -6
  321. package/dist/types/src/testing/testkit/index.js.map +0 -1
  322. package/src/helpers/browser-observability.ts +0 -177
  323. package/src/helpers/common.ts +0 -38
  324. package/src/helpers/index.ts +0 -9
  325. package/src/helpers/map-spaces.ts +0 -48
  326. package/src/helpers/setup-telemetry-listeners.ts +0 -108
  327. package/src/otel/index.ts +0 -8
  328. package/src/otel/logs.ts +0 -100
  329. package/src/otel/traces-browser.ts +0 -59
  330. package/src/otel/traces.ts +0 -57
  331. package/src/segment/base.ts +0 -69
  332. package/src/segment/browser.ts +0 -68
  333. package/src/segment/node.ts +0 -94
  334. package/src/segment/types.ts +0 -57
  335. package/src/sentry/browser.ts +0 -133
  336. package/src/sentry/node.node.test.ts +0 -39
  337. package/src/sentry/node.ts +0 -126
  338. package/src/sentry/sentry-log-processor.ts +0 -166
  339. package/src/sentry/sentry.node.test.ts +0 -34
  340. package/src/sentry/types.ts +0 -22
  341. package/src/testing/index.ts +0 -5
  342. package/src/testing/testkit/browser.ts +0 -8
  343. package/src/testing/testkit/index.ts +0 -7
  344. package/src/testing/testkit/shims.d.ts +0 -5
  345. /package/dist/lib/browser/{chunk-KDP3SESE.mjs.map → chunk-J5LGTIGS.mjs.map} +0 -0
  346. /package/dist/lib/{browser/observability-HDE3I7TA.mjs.map → node-esm/chunk-HSLMI22Q.mjs.map} +0 -0
  347. /package/dist/types/src/{otel → extensions/otel}/traces-browser.d.ts +0 -0
  348. /package/dist/types/src/{otel → extensions/otel}/traces.d.ts +0 -0
@@ -0,0 +1,172 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+ import { type PostHogConfig } from 'posthog-js';
7
+
8
+ import { type Config } from '@dxos/config';
9
+ import { log } from '@dxos/log';
10
+
11
+ import { LogBuffer } from '../../log-buffer';
12
+ import { type Extension } from '../../observability-extension';
13
+ import { stubExtension } from '../stub';
14
+
15
+ export type ExtensionsOptions = {
16
+ config: Config;
17
+ /** Release identifier, e.g. `composer@0.8.3`. */
18
+ release?: string;
19
+ /** Deployment environment, e.g. `production` or `staging`. */
20
+ environment?: string;
21
+ posthog?: Partial<PostHogConfig>;
22
+ };
23
+
24
+ /** Upload serialized logs to the feedback-logs endpoint. Returns the R2 key on success. */
25
+ const uploadLogs = async (body: string): Promise<string | undefined> => {
26
+ try {
27
+ const response = await fetch('/api/feedback-logs', {
28
+ method: 'POST',
29
+ headers: { 'Content-Type': 'application/x-ndjson' },
30
+ body,
31
+ });
32
+ if (!response.ok) {
33
+ log.warn('feedback log upload failed', { status: response.status });
34
+ return undefined;
35
+ }
36
+ const { key } = await response.json();
37
+ return key;
38
+ } catch (err) {
39
+ log.warn('feedback log upload error', { error: err });
40
+ return undefined;
41
+ }
42
+ };
43
+
44
+ /** Create a PostHog-backed observability extension for events, errors, and feedback. */
45
+ export const extensions: (options: ExtensionsOptions) => Effect.Effect<Extension> = Effect.fn(function* ({
46
+ config,
47
+ release,
48
+ environment,
49
+ posthog: posthogConfig,
50
+ }) {
51
+ if (typeof window === 'undefined') {
52
+ log('PostHog is being stubbed because it is running in a worker.');
53
+ return stubExtension;
54
+ }
55
+
56
+ const feedbackSurveyId = config.get('runtime.app.env.DX_POSTHOG_FEEDBACK_SURVEY_ID');
57
+ const apiKey = config.get('runtime.app.env.DX_POSTHOG_API_KEY');
58
+ const api_host = config.get('runtime.app.env.DX_POSTHOG_API_HOST');
59
+ if (!apiKey || !api_host) {
60
+ log.info('Missing POSTHOG_API_KEY or POSTHOG_API_HOST');
61
+ return stubExtension;
62
+ }
63
+
64
+ const { default: posthog } = yield* Effect.promise(() => import('posthog-js'));
65
+ const { logProcessor } = yield* Effect.promise(() => import('./log-processor'));
66
+ const logBuffer = new LogBuffer();
67
+ let feedbackSurveyAvailable: boolean | null = null;
68
+
69
+ const checkFeedbackSurveyAvailable = (): Effect.Effect<boolean> =>
70
+ feedbackSurveyId
71
+ ? Effect.promise(() => {
72
+ if (feedbackSurveyAvailable !== null) {
73
+ return Promise.resolve(feedbackSurveyAvailable);
74
+ }
75
+ return new Promise<boolean>((resolve) => {
76
+ posthog.getSurveys((surveys) => {
77
+ const found = surveys.some((s) => s.id === feedbackSurveyId);
78
+ feedbackSurveyAvailable = found;
79
+ resolve(found);
80
+ });
81
+ });
82
+ })
83
+ : Effect.succeed(false);
84
+
85
+ return {
86
+ initialize: () =>
87
+ Effect.sync(() => {
88
+ // https://posthog.com/docs/libraries/js/config
89
+ posthog.init(apiKey, {
90
+ api_host,
91
+ mask_all_text: true,
92
+ capture_exceptions: true,
93
+ ...posthogConfig,
94
+ });
95
+ if (release || environment) {
96
+ posthog.register({
97
+ ...(release ? { release } : {}),
98
+ ...(environment ? { environment } : {}),
99
+ });
100
+ }
101
+ log.runtimeConfig.processors.push(logProcessor);
102
+ log.runtimeConfig.processors.push(logBuffer.logProcessor);
103
+ }),
104
+ close: () =>
105
+ Effect.sync(() => {
106
+ for (const processor of [logProcessor, logBuffer.logProcessor]) {
107
+ const index = log.runtimeConfig.processors.indexOf(processor);
108
+ if (index !== -1) {
109
+ log.runtimeConfig.processors.splice(index, 1);
110
+ }
111
+ }
112
+ }),
113
+ enable: () => Effect.sync(() => posthog.opt_in_capturing()),
114
+ disable: () => Effect.sync(() => posthog.opt_out_capturing()),
115
+ identify: (distinctId, attributes, setOnceAttributes) => {
116
+ posthog.identify(distinctId, attributes, setOnceAttributes);
117
+ },
118
+ alias: (distinctId, previousId) => {
119
+ posthog.alias(distinctId, previousId);
120
+ },
121
+ setTags: (tags) => {
122
+ posthog.register_for_session(tags);
123
+ },
124
+ get enabled(): boolean {
125
+ return posthog.is_capturing();
126
+ },
127
+ apis: [
128
+ {
129
+ kind: 'events',
130
+ isAvailable: () => Effect.succeed(true),
131
+ captureEvent: (event, attributes) => {
132
+ posthog.capture(event, attributes);
133
+ },
134
+ },
135
+ {
136
+ kind: 'errors',
137
+ isAvailable: () => Effect.succeed(true),
138
+ captureException: (error, attributes) => {
139
+ posthog.captureException(error, attributes);
140
+ },
141
+ },
142
+ {
143
+ kind: 'feedback',
144
+ // TODO(wittjosiah): Support custom surveys.
145
+ captureUserFeedback: (form) => {
146
+ posthog.getSurveys(async (surveys) => {
147
+ const survey = surveys.find((survey) => survey.id === feedbackSurveyId);
148
+ if (!survey || survey.questions.length === 0) {
149
+ log.error('Missing feedback survey or survey has no questions', { feedbackSurveyId });
150
+ return;
151
+ }
152
+
153
+ let debugLogDumpKey: string | undefined;
154
+ if (form.includeLogs !== false && logBuffer.size > 0) {
155
+ debugLogDumpKey = await uploadLogs(logBuffer.serialize());
156
+ }
157
+
158
+ // https://posthog.com/docs/surveys/implementing-custom-surveys
159
+ const question = survey.questions[0];
160
+ posthog.capture('survey sent', {
161
+ $survey_id: survey.id,
162
+ $survey_questions: [{ id: question.id, question: question.question }],
163
+ [`$survey_response_${question.id}`]: form.message,
164
+ ...(debugLogDumpKey ? { debug_log_dump_key: debugLogDumpKey } : {}),
165
+ });
166
+ });
167
+ },
168
+ isAvailable: checkFeedbackSurveyAvailable,
169
+ },
170
+ ],
171
+ };
172
+ });
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './extension';
@@ -0,0 +1,185 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { beforeEach, describe, expect, test, vi } from 'vitest';
6
+
7
+ import { InvariantViolation } from '@dxos/invariant';
8
+ import { type LogConfig, type LogEntry, LogLevel } from '@dxos/log';
9
+
10
+ // Replace the posthog-js module with a stub so log-processor's top-level import resolves to our mock.
11
+ // Dynamic imports are used so that both the mock and log-processor are loaded after vi.mock is hoisted.
12
+ vi.mock('posthog-js', () => ({
13
+ default: {
14
+ captureException: vi.fn(),
15
+ },
16
+ }));
17
+ const { default: posthog } = await import('posthog-js');
18
+ const { logProcessor } = await import('./log-processor');
19
+
20
+ const baseConfig: LogConfig = {
21
+ options: {},
22
+ captureFilters: [{ level: LogLevel.WARN }],
23
+ processors: [],
24
+ };
25
+
26
+ const createEntry = (overrides: Partial<LogEntry> = {}): LogEntry => ({
27
+ level: LogLevel.ERROR,
28
+ message: 'test error',
29
+ ...overrides,
30
+ });
31
+
32
+ describe('logProcessor', () => {
33
+ beforeEach(() => {
34
+ vi.clearAllMocks();
35
+ });
36
+
37
+ test('skips entries that do not pass capture filters', () => {
38
+ const entry = createEntry({ level: LogLevel.DEBUG });
39
+ logProcessor(baseConfig, entry);
40
+ expect(posthog.captureException).not.toHaveBeenCalled();
41
+ });
42
+
43
+ test('skips entries from remote sessions', () => {
44
+ const entry = createEntry({
45
+ error: new Error('test'),
46
+ meta: { F: 'test.ts', L: 1, S: { remoteSessionId: 'remote-123' } },
47
+ });
48
+ logProcessor(baseConfig, entry);
49
+ expect(posthog.captureException).not.toHaveBeenCalled();
50
+ });
51
+
52
+ test('skips entries without errors', () => {
53
+ const entry = createEntry({ error: undefined, context: {} });
54
+ logProcessor(baseConfig, entry);
55
+ expect(posthog.captureException).not.toHaveBeenCalled();
56
+ });
57
+
58
+ test('captures error from entry.error', () => {
59
+ const error = new Error('direct error');
60
+ const entry = createEntry({
61
+ error,
62
+ meta: { F: 'packages/sdk/observability/src/test.ts', L: 42, S: undefined },
63
+ });
64
+ logProcessor(baseConfig, entry);
65
+ expect(posthog.captureException).toHaveBeenCalledWith(
66
+ error,
67
+ expect.objectContaining({
68
+ transaction: 'packages/sdk/observability/src/test.ts:42',
69
+ }),
70
+ );
71
+ });
72
+
73
+ test('captures error from context when level is ERROR but no entry.error', () => {
74
+ const contextError = new Error('context error');
75
+ const entry = createEntry({
76
+ level: LogLevel.ERROR,
77
+ error: undefined,
78
+ context: { someKey: contextError },
79
+ meta: { F: 'test.ts', L: 10, S: undefined },
80
+ });
81
+ logProcessor(baseConfig, entry);
82
+ expect(posthog.captureException).toHaveBeenCalledWith(contextError, expect.any(Object));
83
+ });
84
+
85
+ test('sets transaction from file:line metadata', () => {
86
+ const entry = createEntry({
87
+ error: new Error('err'),
88
+ meta: { F: '/home/user/project/packages/sdk/observability/src/index.ts', L: 99, S: undefined },
89
+ });
90
+ logProcessor(baseConfig, entry);
91
+ expect(posthog.captureException).toHaveBeenCalledWith(
92
+ expect.any(Error),
93
+ expect.objectContaining({
94
+ transaction: 'packages/sdk/observability/src/index.ts:99',
95
+ }),
96
+ );
97
+ });
98
+
99
+ test('sets service_host_issue/session for worker entries', () => {
100
+ const entry = createEntry({
101
+ error: new Error('worker err'),
102
+ meta: { F: 'test.ts', L: 1, S: { hostSessionId: 'host-abc' } },
103
+ });
104
+ logProcessor(baseConfig, entry);
105
+ expect(posthog.captureException).toHaveBeenCalledWith(
106
+ expect.any(Error),
107
+ expect.objectContaining({
108
+ service_host_issue: true,
109
+ service_host_session: 'host-abc',
110
+ }),
111
+ );
112
+ });
113
+
114
+ test('sets uptime_seconds from metadata', () => {
115
+ const entry = createEntry({
116
+ error: new Error('err'),
117
+ meta: { F: 'test.ts', L: 1, S: { uptimeSeconds: 123 } },
118
+ });
119
+ logProcessor(baseConfig, entry);
120
+ expect(posthog.captureException).toHaveBeenCalledWith(
121
+ expect.any(Error),
122
+ expect.objectContaining({
123
+ uptime_seconds: 123,
124
+ }),
125
+ );
126
+ });
127
+
128
+ test('sets invariant_violation flag for InvariantViolation errors', () => {
129
+ const error = new InvariantViolation('broken invariant');
130
+ const entry = createEntry({
131
+ error,
132
+ meta: { F: 'test.ts', L: 1, S: undefined },
133
+ });
134
+ logProcessor(baseConfig, entry);
135
+ expect(posthog.captureException).toHaveBeenCalledWith(
136
+ error,
137
+ expect.objectContaining({
138
+ invariant_violation: true,
139
+ }),
140
+ );
141
+ });
142
+
143
+ test('does not set invariant_violation for normal errors', () => {
144
+ const error = new Error('normal error');
145
+ const entry = createEntry({
146
+ error,
147
+ meta: { F: 'test.ts', L: 1, S: undefined },
148
+ });
149
+ logProcessor(baseConfig, entry);
150
+ const callArgs = vi.mocked(posthog.captureException).mock.calls[0];
151
+ expect(callArgs[1]).not.toHaveProperty('invariant_violation');
152
+ });
153
+ });
154
+
155
+ describe('getRelativeFilename', () => {
156
+ // We test this indirectly through the transaction property set by logProcessor.
157
+
158
+ test('extracts relative path from absolute path containing packages/', () => {
159
+ const entry = createEntry({
160
+ error: new Error('err'),
161
+ meta: { F: '/home/user/code/packages/sdk/observability/src/file.ts', L: 5, S: undefined },
162
+ });
163
+ logProcessor(baseConfig, entry);
164
+ expect(posthog.captureException).toHaveBeenCalledWith(
165
+ expect.any(Error),
166
+ expect.objectContaining({
167
+ transaction: 'packages/sdk/observability/src/file.ts:5',
168
+ }),
169
+ );
170
+ });
171
+
172
+ test('returns original filename if no match', () => {
173
+ const entry = createEntry({
174
+ error: new Error('err'),
175
+ meta: { F: 'no-packages-here.ts', L: 1, S: undefined },
176
+ });
177
+ logProcessor(baseConfig, entry);
178
+ expect(posthog.captureException).toHaveBeenCalledWith(
179
+ expect.any(Error),
180
+ expect.objectContaining({
181
+ transaction: 'no-packages-here.ts:1',
182
+ }),
183
+ );
184
+ });
185
+ });
@@ -0,0 +1,54 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import posthog from 'posthog-js';
6
+
7
+ import { InvariantViolation } from '@dxos/invariant';
8
+ import { type LogConfig, type LogEntry, LogLevel, type LogProcessor, shouldLog } from '@dxos/log';
9
+
10
+ export const logProcessor: LogProcessor = (config: LogConfig, entry: LogEntry) => {
11
+ // Don't forward logs from remote sessions.
12
+ if (!shouldLog(entry, config.captureFilters) || entry.meta?.S?.remoteSessionId) {
13
+ return;
14
+ }
15
+
16
+ let capturedError = entry.error;
17
+ if (capturedError == null && entry.level === LogLevel.ERROR) {
18
+ capturedError = Object.values(entry.context ?? {}).find((v): v is Error => v instanceof Error);
19
+ }
20
+
21
+ if (!capturedError) {
22
+ return;
23
+ }
24
+
25
+ const additionalProperties: Record<string, string | boolean | number> = {};
26
+ if (entry.meta) {
27
+ additionalProperties.transaction = `${getRelativeFilename(entry.meta.F)}:${entry.meta.L}`;
28
+ if (entry.meta.S?.hostSessionId) {
29
+ additionalProperties.service_host_issue = true;
30
+ additionalProperties.service_host_session = entry.meta.S?.hostSessionId;
31
+ }
32
+ if (entry.meta.S?.uptimeSeconds != null) {
33
+ additionalProperties.uptime_seconds = entry.meta.S.uptimeSeconds;
34
+ }
35
+ }
36
+
37
+ if (capturedError instanceof InvariantViolation) {
38
+ additionalProperties.invariant_violation = true;
39
+ }
40
+
41
+ posthog.captureException(capturedError, additionalProperties);
42
+ };
43
+
44
+ const getRelativeFilename = (filename: string) => {
45
+ // TODO(burdon): Hack uses "packages" as an anchor (pre-parse NX?)
46
+ // Including `packages/` part of the path so that excluded paths (e.g. from dist) are clickable in vscode.
47
+ const match = filename.match(/.+\/(packages\/.+\/.+)/);
48
+ if (match) {
49
+ const [, filePath] = match;
50
+ return filePath;
51
+ }
52
+
53
+ return filename;
54
+ };
@@ -0,0 +1,19 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+
7
+ import { type Extension } from '../observability-extension';
8
+
9
+ export const stubExtension: Extension = {
10
+ initialize: () => Effect.succeed(undefined),
11
+ enable: () => Effect.succeed(undefined),
12
+ disable: () => Effect.succeed(undefined),
13
+ flush: () => Effect.succeed(undefined),
14
+ setTags: () => undefined,
15
+ get enabled() {
16
+ return true;
17
+ },
18
+ apis: [],
19
+ };
package/src/index.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  //
2
- // Copyright 2023 DXOS.org
2
+ // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- export * from './helpers';
6
- export * from './observability';
5
+ export * from './log-buffer';
6
+ export * as Observability from './observability';
7
+ export * as ObservabilityExtension from './observability-extension';
8
+ export * as ObservabilityProvider from './providers';
@@ -0,0 +1,134 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { describe, test } from 'vitest';
6
+
7
+ import { type LogConfig, type LogEntry, LogLevel } from '@dxos/log';
8
+
9
+ import { LogBuffer } from './log-buffer';
10
+
11
+ const baseConfig: LogConfig = {
12
+ options: {},
13
+ filters: [{ level: LogLevel.DEBUG }],
14
+ processors: [],
15
+ };
16
+
17
+ const createEntry = (overrides: Partial<LogEntry> = {}): LogEntry => ({
18
+ level: LogLevel.INFO,
19
+ message: 'test message',
20
+ ...overrides,
21
+ });
22
+
23
+ describe('LogBuffer', () => {
24
+ test('pushes and serializes log entries', ({ expect }) => {
25
+ const buffer = new LogBuffer(10);
26
+ buffer.logProcessor(baseConfig, createEntry({ message: 'hello' }));
27
+ buffer.logProcessor(baseConfig, createEntry({ message: 'world' }));
28
+
29
+ expect(buffer.size).toBe(2);
30
+ const lines = buffer.serialize().split('\n');
31
+ expect(lines).toHaveLength(2);
32
+
33
+ const first = JSON.parse(lines[0]);
34
+ expect(first.m).toBe('hello');
35
+ expect(first.l).toBe('I');
36
+ expect(first.t).toBeDefined();
37
+
38
+ const second = JSON.parse(lines[1]);
39
+ expect(second.m).toBe('world');
40
+ });
41
+
42
+ test('evicts oldest entries when buffer is full', ({ expect }) => {
43
+ const buffer = new LogBuffer(3);
44
+ buffer.logProcessor(baseConfig, createEntry({ message: 'a' }));
45
+ buffer.logProcessor(baseConfig, createEntry({ message: 'b' }));
46
+ buffer.logProcessor(baseConfig, createEntry({ message: 'c' }));
47
+ buffer.logProcessor(baseConfig, createEntry({ message: 'd' }));
48
+
49
+ expect(buffer.size).toBe(3);
50
+ const lines = buffer.serialize().split('\n');
51
+ const messages = lines.map((l) => JSON.parse(l).m);
52
+ expect(messages).toEqual(['b', 'c', 'd']);
53
+ });
54
+
55
+ test('skips TRACE-level logs', ({ expect }) => {
56
+ const buffer = new LogBuffer(10);
57
+ buffer.logProcessor(baseConfig, createEntry({ level: LogLevel.TRACE, message: 'trace' }));
58
+ expect(buffer.size).toBe(0);
59
+ });
60
+
61
+ test('captures DEBUG-level and above', ({ expect }) => {
62
+ const buffer = new LogBuffer(10);
63
+ buffer.logProcessor(baseConfig, createEntry({ level: LogLevel.DEBUG, message: 'debug' }));
64
+ buffer.logProcessor(baseConfig, createEntry({ level: LogLevel.WARN, message: 'warn' }));
65
+ buffer.logProcessor(baseConfig, createEntry({ level: LogLevel.ERROR, message: 'error' }));
66
+
67
+ expect(buffer.size).toBe(3);
68
+ const lines = buffer.serialize().split('\n');
69
+ expect(JSON.parse(lines[0]).l).toBe('D');
70
+ expect(JSON.parse(lines[1]).l).toBe('W');
71
+ expect(JSON.parse(lines[2]).l).toBe('E');
72
+ });
73
+
74
+ test('captures file and line metadata', ({ expect }) => {
75
+ const buffer = new LogBuffer(10);
76
+ buffer.logProcessor(
77
+ baseConfig,
78
+ createEntry({
79
+ meta: { F: '/home/user/project/packages/sdk/test.ts', L: 42, S: undefined },
80
+ }),
81
+ );
82
+
83
+ const lines = buffer.serialize().split('\n');
84
+ const record = JSON.parse(lines[0]);
85
+ expect(record.f).toBe('packages/sdk/test.ts');
86
+ expect(record.n).toBe(42);
87
+ });
88
+
89
+ test('captures error stack', ({ expect }) => {
90
+ const buffer = new LogBuffer(10);
91
+ const error = new Error('boom');
92
+ buffer.logProcessor(baseConfig, createEntry({ error }));
93
+
94
+ const lines = buffer.serialize().split('\n');
95
+ const record = JSON.parse(lines[0]);
96
+ expect(record.e).toContain('boom');
97
+ });
98
+
99
+ test('truncates context to 500 chars', ({ expect }) => {
100
+ const buffer = new LogBuffer(10);
101
+ const longValue = 'x'.repeat(1000);
102
+ buffer.logProcessor(baseConfig, createEntry({ context: { data: longValue } }));
103
+
104
+ const lines = buffer.serialize().split('\n');
105
+ const record = JSON.parse(lines[0]);
106
+ expect(record.c).toBeDefined();
107
+ expect(record.c!.length).toBe(500);
108
+ });
109
+
110
+ test('skips Error context objects', ({ expect }) => {
111
+ const buffer = new LogBuffer(10);
112
+ buffer.logProcessor(baseConfig, createEntry({ context: new Error('ctx error') }));
113
+
114
+ const lines = buffer.serialize().split('\n');
115
+ const record = JSON.parse(lines[0]);
116
+ expect(record.c).toBeUndefined();
117
+ });
118
+
119
+ test('handles non-serializable context gracefully', ({ expect }) => {
120
+ const buffer = new LogBuffer(10);
121
+ const circular: Record<string, any> = {};
122
+ circular.self = circular;
123
+ buffer.logProcessor(baseConfig, createEntry({ context: circular }));
124
+
125
+ const lines = buffer.serialize().split('\n');
126
+ const record = JSON.parse(lines[0]);
127
+ expect(record.c).toBeUndefined();
128
+ });
129
+
130
+ test('serialize returns empty string for empty buffer', ({ expect }) => {
131
+ const buffer = new LogBuffer(10);
132
+ expect(buffer.serialize()).toBe('');
133
+ });
134
+ });
@@ -0,0 +1,101 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { type LogConfig, type LogEntry, LogLevel, type LogProcessor, shortLevelName } from '@dxos/log';
6
+ import { CircularBuffer } from '@dxos/util';
7
+
8
+ const DEFAULT_BUFFER_SIZE = 2_000;
9
+ const MAX_CONTEXT_LENGTH = 500;
10
+
11
+ /**
12
+ * Compact log record with short property names for small serialized size.
13
+ */
14
+ export type LogRecord = {
15
+ /** ISO timestamp. */
16
+ t: string;
17
+ /** Level letter (D, V, I, W, E). */
18
+ l: string;
19
+ /** Message. */
20
+ m: string;
21
+ /** File path. */
22
+ f?: string;
23
+ /** Line number. */
24
+ n?: number;
25
+ /** Error stack. */
26
+ e?: string;
27
+ /** Context JSON. */
28
+ c?: string;
29
+ };
30
+
31
+ /**
32
+ * Captures recent log entries in a circular buffer for debug log dump on feedback submission.
33
+ */
34
+ export class LogBuffer {
35
+ private readonly _buffer: CircularBuffer<LogRecord>;
36
+
37
+ constructor(size = DEFAULT_BUFFER_SIZE) {
38
+ this._buffer = new CircularBuffer<LogRecord>(size);
39
+ }
40
+
41
+ /** Log processor that can be registered with `log.runtimeConfig.processors`. */
42
+ readonly logProcessor: LogProcessor = (_config: LogConfig, entry: LogEntry) => {
43
+ if (entry.level <= LogLevel.TRACE) {
44
+ return;
45
+ }
46
+
47
+ const record: LogRecord = {
48
+ t: new Date().toISOString(),
49
+ l: shortLevelName[entry.level] ?? '?',
50
+ m: entry.message ?? '',
51
+ };
52
+
53
+ if (entry.meta) {
54
+ record.f = getRelativeFilename(entry.meta.F);
55
+ record.n = entry.meta.L;
56
+ }
57
+
58
+ if (entry.error) {
59
+ record.e = entry.error.stack ?? entry.error.message;
60
+ }
61
+
62
+ if (entry.context != null) {
63
+ try {
64
+ const ctx = typeof entry.context === 'function' ? entry.context() : entry.context;
65
+ if (ctx != null && !(ctx instanceof Error)) {
66
+ let json = JSON.stringify(ctx);
67
+ if (json.length > MAX_CONTEXT_LENGTH) {
68
+ json = json.slice(0, MAX_CONTEXT_LENGTH);
69
+ }
70
+ record.c = json;
71
+ }
72
+ } catch {
73
+ // Skip context that throws or is non-serializable.
74
+ }
75
+ }
76
+
77
+ this._buffer.push(record);
78
+ };
79
+
80
+ /** Number of entries currently in the buffer. */
81
+ get size(): number {
82
+ return this._buffer.elementCount;
83
+ }
84
+
85
+ /** Serialize buffer contents as NDJSON (newline-delimited JSON). */
86
+ serialize(): string {
87
+ const lines: string[] = [];
88
+ for (const record of this._buffer) {
89
+ lines.push(JSON.stringify(record));
90
+ }
91
+ return lines.join('\n');
92
+ }
93
+ }
94
+
95
+ const getRelativeFilename = (filename: string): string => {
96
+ const match = filename.match(/.+\/(packages\/.+\/.+)/);
97
+ if (match) {
98
+ return match[1];
99
+ }
100
+ return filename;
101
+ };