@dxos/observability 0.8.4-main.a4bbb77 → 0.8.4-main.abd8ff62ef

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 (324) hide show
  1. package/README.md +14 -11
  2. package/dist/lib/browser/chunk-3534PNWM.mjs +13 -0
  3. package/dist/lib/browser/chunk-3534PNWM.mjs.map +7 -0
  4. package/dist/lib/browser/chunk-J5LGTIGS.mjs +10 -0
  5. package/dist/lib/browser/index.mjs +940 -34
  6. package/dist/lib/browser/index.mjs.map +4 -4
  7. package/dist/lib/browser/log-processor-HPHWNBOK.mjs +38 -0
  8. package/dist/lib/browser/log-processor-HPHWNBOK.mjs.map +7 -0
  9. package/dist/lib/browser/logs-A2VDAHHD.mjs +115 -0
  10. package/dist/lib/browser/logs-A2VDAHHD.mjs.map +7 -0
  11. package/dist/lib/browser/meta.json +1 -1
  12. package/dist/lib/browser/metrics-6OSN54ZV.mjs +115 -0
  13. package/dist/lib/browser/metrics-6OSN54ZV.mjs.map +7 -0
  14. package/dist/lib/browser/traces-browser-6MRGAKFC.mjs +151 -0
  15. package/dist/lib/browser/traces-browser-6MRGAKFC.mjs.map +7 -0
  16. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
  17. package/dist/lib/node-esm/chunk-SYPJQI4L.mjs +15 -0
  18. package/dist/lib/node-esm/chunk-SYPJQI4L.mjs.map +7 -0
  19. package/dist/lib/node-esm/index.mjs +962 -34
  20. package/dist/lib/node-esm/index.mjs.map +4 -4
  21. package/dist/lib/node-esm/log-processor-ZODHERST.mjs +39 -0
  22. package/dist/lib/node-esm/log-processor-ZODHERST.mjs.map +7 -0
  23. package/dist/lib/node-esm/logs-TA32MBMW.mjs +116 -0
  24. package/dist/lib/node-esm/logs-TA32MBMW.mjs.map +7 -0
  25. package/dist/lib/node-esm/meta.json +1 -1
  26. package/dist/lib/node-esm/metrics-C5IKPAWD.mjs +116 -0
  27. package/dist/lib/node-esm/metrics-C5IKPAWD.mjs.map +7 -0
  28. package/dist/lib/node-esm/traces-5LKHMVVG.mjs +122 -0
  29. package/dist/lib/node-esm/traces-5LKHMVVG.mjs.map +7 -0
  30. package/dist/types/src/cli-observability-secrets.json +3 -4
  31. package/dist/types/src/extensions/index.d.ts +3 -0
  32. package/dist/types/src/extensions/index.d.ts.map +1 -0
  33. package/dist/types/src/extensions/index.js +6 -0
  34. package/dist/types/src/extensions/index.js.map +1 -0
  35. package/dist/types/src/extensions/otel/extension.d.ts +23 -0
  36. package/dist/types/src/extensions/otel/extension.d.ts.map +1 -0
  37. package/dist/types/src/extensions/otel/extension.js +201 -0
  38. package/dist/types/src/extensions/otel/extension.js.map +1 -0
  39. package/dist/types/src/extensions/otel/index.d.ts +2 -0
  40. package/dist/types/src/extensions/otel/index.d.ts.map +1 -0
  41. package/dist/types/src/extensions/otel/index.js +5 -0
  42. package/dist/types/src/extensions/otel/index.js.map +1 -0
  43. package/dist/types/src/{otel → extensions/otel}/logs.d.ts +4 -3
  44. package/dist/types/src/extensions/otel/logs.d.ts.map +1 -0
  45. package/dist/types/src/{otel → extensions/otel}/logs.js +52 -19
  46. package/dist/types/src/extensions/otel/logs.js.map +1 -0
  47. package/dist/types/src/extensions/otel/metrics.d.ts.map +1 -0
  48. package/dist/types/src/{otel → extensions/otel}/metrics.js +2 -10
  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/extensions/otel/otel.js.map +1 -0
  53. package/dist/types/src/extensions/otel/span-processors.d.ts +25 -0
  54. package/dist/types/src/extensions/otel/span-processors.d.ts.map +1 -0
  55. package/dist/types/src/extensions/otel/span-processors.js +41 -0
  56. package/dist/types/src/extensions/otel/span-processors.js.map +1 -0
  57. package/dist/types/src/extensions/otel/traces-browser.d.ts +25 -0
  58. package/dist/types/src/extensions/otel/traces-browser.d.ts.map +1 -0
  59. package/dist/types/src/extensions/otel/traces-browser.js +104 -0
  60. package/dist/types/src/extensions/otel/traces-browser.js.map +1 -0
  61. package/dist/types/src/extensions/otel/traces.d.ts +25 -0
  62. package/dist/types/src/extensions/otel/traces.d.ts.map +1 -0
  63. package/dist/types/src/extensions/otel/traces.js +87 -0
  64. package/dist/types/src/extensions/otel/traces.js.map +1 -0
  65. package/dist/types/src/extensions/posthog/extension.d.ts +22 -0
  66. package/dist/types/src/extensions/posthog/extension.d.ts.map +1 -0
  67. package/dist/types/src/extensions/posthog/extension.js +144 -0
  68. package/dist/types/src/extensions/posthog/extension.js.map +1 -0
  69. package/dist/types/src/extensions/posthog/index.d.ts +2 -0
  70. package/dist/types/src/extensions/posthog/index.d.ts.map +1 -0
  71. package/dist/types/src/extensions/posthog/index.js +5 -0
  72. package/dist/types/src/extensions/posthog/index.js.map +1 -0
  73. package/dist/types/src/extensions/posthog/log-processor.d.ts +3 -0
  74. package/dist/types/src/extensions/posthog/log-processor.d.ts.map +1 -0
  75. package/dist/types/src/extensions/posthog/log-processor.js +36 -0
  76. package/dist/types/src/extensions/posthog/log-processor.js.map +1 -0
  77. package/dist/types/src/extensions/posthog/log-processor.test.d.ts +2 -0
  78. package/dist/types/src/extensions/posthog/log-processor.test.d.ts.map +1 -0
  79. package/dist/types/src/extensions/posthog/log-processor.test.js +146 -0
  80. package/dist/types/src/extensions/posthog/log-processor.test.js.map +1 -0
  81. package/dist/types/src/extensions/stub.d.ts +3 -0
  82. package/dist/types/src/extensions/stub.d.ts.map +1 -0
  83. package/dist/types/src/extensions/stub.js +16 -0
  84. package/dist/types/src/extensions/stub.js.map +1 -0
  85. package/dist/types/src/index.d.ts +3 -2
  86. package/dist/types/src/index.d.ts.map +1 -1
  87. package/dist/types/src/index.js +4 -3
  88. package/dist/types/src/index.js.map +1 -1
  89. package/dist/types/src/observability-extension.d.ts +74 -0
  90. package/dist/types/src/observability-extension.d.ts.map +1 -0
  91. package/dist/types/src/observability-extension.js +5 -0
  92. package/dist/types/src/observability-extension.js.map +1 -0
  93. package/dist/types/src/observability.d.ts +32 -110
  94. package/dist/types/src/observability.d.ts.map +1 -1
  95. package/dist/types/src/observability.js +177 -465
  96. package/dist/types/src/observability.js.map +1 -1
  97. package/dist/types/src/observability.test.d.ts +2 -0
  98. package/dist/types/src/observability.test.d.ts.map +1 -0
  99. package/dist/types/src/observability.test.js +312 -0
  100. package/dist/types/src/observability.test.js.map +1 -0
  101. package/dist/types/src/providers/client-observability.d.ts +11 -0
  102. package/dist/types/src/providers/client-observability.d.ts.map +1 -0
  103. package/dist/types/src/providers/client-observability.js +202 -0
  104. package/dist/types/src/providers/client-observability.js.map +1 -0
  105. package/dist/types/src/providers/index.d.ts +4 -0
  106. package/dist/types/src/providers/index.d.ts.map +1 -0
  107. package/dist/types/src/providers/index.js +7 -0
  108. package/dist/types/src/providers/index.js.map +1 -0
  109. package/dist/types/src/providers/ip-data.d.ts +5 -0
  110. package/dist/types/src/providers/ip-data.d.ts.map +1 -0
  111. package/dist/types/src/providers/ip-data.js +57 -0
  112. package/dist/types/src/providers/ip-data.js.map +1 -0
  113. package/dist/types/src/providers/storage.d.ts +3 -0
  114. package/dist/types/src/providers/storage.d.ts.map +1 -0
  115. package/dist/types/src/providers/storage.js +19 -0
  116. package/dist/types/src/providers/storage.js.map +1 -0
  117. package/dist/types/src/storage/browser.d.ts +19 -0
  118. package/dist/types/src/storage/browser.d.ts.map +1 -0
  119. package/dist/types/src/storage/browser.js +69 -0
  120. package/dist/types/src/storage/browser.js.map +1 -0
  121. package/dist/types/src/storage/index.d.ts +2 -0
  122. package/dist/types/src/storage/index.d.ts.map +1 -0
  123. package/dist/types/src/storage/index.js.map +1 -0
  124. package/dist/types/src/storage/node.d.ts +26 -0
  125. package/dist/types/src/storage/node.d.ts.map +1 -0
  126. package/dist/types/src/{helpers/node-observability.js → storage/node.js} +38 -43
  127. package/dist/types/src/storage/node.js.map +1 -0
  128. package/dist/types/src/storage/node.test.d.ts +2 -0
  129. package/dist/types/src/storage/node.test.d.ts.map +1 -0
  130. package/dist/types/src/storage/node.test.js +103 -0
  131. package/dist/types/src/storage/node.test.js.map +1 -0
  132. package/dist/types/tsconfig.tsbuildinfo +1 -1
  133. package/package.json +34 -54
  134. package/src/cli-observability-secrets.json +3 -4
  135. package/src/extensions/index.ts +6 -0
  136. package/src/extensions/otel/extension.ts +258 -0
  137. package/src/extensions/otel/index.ts +5 -0
  138. package/src/extensions/otel/logs.ts +137 -0
  139. package/src/{otel → extensions/otel}/metrics.ts +2 -12
  140. package/src/{otel → extensions/otel}/otel.ts +3 -3
  141. package/src/extensions/otel/span-processors.ts +45 -0
  142. package/src/extensions/otel/traces-browser.ts +139 -0
  143. package/src/extensions/otel/traces.ts +113 -0
  144. package/src/extensions/posthog/extension.ts +181 -0
  145. package/src/extensions/posthog/index.ts +5 -0
  146. package/src/extensions/posthog/log-processor.test.ts +186 -0
  147. package/src/extensions/posthog/log-processor.ts +43 -0
  148. package/src/extensions/stub.ts +19 -0
  149. package/src/index.ts +4 -3
  150. package/src/observability-extension.ts +94 -0
  151. package/src/observability.test.ts +531 -0
  152. package/src/observability.ts +236 -577
  153. package/src/providers/client-observability.ts +255 -0
  154. package/src/providers/index.ts +7 -0
  155. package/src/providers/ip-data.ts +91 -0
  156. package/src/providers/storage.ts +23 -0
  157. package/src/storage/browser.ts +71 -0
  158. package/src/{segment → storage}/index.ts +0 -1
  159. package/src/storage/node.test.ts +129 -0
  160. package/src/{helpers/node-observability.ts → storage/node.ts} +41 -71
  161. package/src/vite-import-meta.d.ts +14 -0
  162. package/dist/lib/browser/chunk-5ICT2XF2.mjs +0 -1
  163. package/dist/lib/browser/chunk-ICKR6U3G.mjs +0 -161
  164. package/dist/lib/browser/chunk-ICKR6U3G.mjs.map +0 -7
  165. package/dist/lib/browser/chunk-LJO63BXO.mjs +0 -164
  166. package/dist/lib/browser/chunk-LJO63BXO.mjs.map +0 -7
  167. package/dist/lib/browser/chunk-YTRUOREY.mjs +0 -1025
  168. package/dist/lib/browser/chunk-YTRUOREY.mjs.map +0 -7
  169. package/dist/lib/browser/observability-CQGG3MID.mjs +0 -10
  170. package/dist/lib/browser/otel-6FVBNA5F.mjs +0 -327
  171. package/dist/lib/browser/otel-6FVBNA5F.mjs.map +0 -7
  172. package/dist/lib/browser/segment/index.mjs +0 -11
  173. package/dist/lib/browser/segment/index.mjs.map +0 -7
  174. package/dist/lib/browser/sentry/index.mjs +0 -24
  175. package/dist/lib/browser/sentry/index.mjs.map +0 -7
  176. package/dist/lib/browser/sentry-log-processor-RG4CFVGL.mjs +0 -162
  177. package/dist/lib/browser/sentry-log-processor-RG4CFVGL.mjs.map +0 -7
  178. package/dist/lib/node-esm/chunk-24NMRR4E.mjs +0 -229
  179. package/dist/lib/node-esm/chunk-24NMRR4E.mjs.map +0 -7
  180. package/dist/lib/node-esm/chunk-4EWQFQ2F.mjs +0 -1026
  181. package/dist/lib/node-esm/chunk-4EWQFQ2F.mjs.map +0 -7
  182. package/dist/lib/node-esm/chunk-QK5IUYVA.mjs +0 -135
  183. package/dist/lib/node-esm/chunk-QK5IUYVA.mjs.map +0 -7
  184. package/dist/lib/node-esm/chunk-QUZL7LKE.mjs +0 -2
  185. package/dist/lib/node-esm/chunk-QUZL7LKE.mjs.map +0 -7
  186. package/dist/lib/node-esm/observability-DHNVVRC7.mjs +0 -11
  187. package/dist/lib/node-esm/observability-DHNVVRC7.mjs.map +0 -7
  188. package/dist/lib/node-esm/otel-KHSGBROB.mjs +0 -310
  189. package/dist/lib/node-esm/otel-KHSGBROB.mjs.map +0 -7
  190. package/dist/lib/node-esm/segment/index.mjs +0 -12
  191. package/dist/lib/node-esm/segment/index.mjs.map +0 -7
  192. package/dist/lib/node-esm/sentry/index.mjs +0 -25
  193. package/dist/lib/node-esm/sentry/index.mjs.map +0 -7
  194. package/dist/lib/node-esm/sentry-log-processor-3BDS4BB4.mjs +0 -163
  195. package/dist/lib/node-esm/sentry-log-processor-3BDS4BB4.mjs.map +0 -7
  196. package/dist/types/src/helpers/browser-observability.d.ts +0 -17
  197. package/dist/types/src/helpers/browser-observability.d.ts.map +0 -1
  198. package/dist/types/src/helpers/browser-observability.js +0 -138
  199. package/dist/types/src/helpers/browser-observability.js.map +0 -1
  200. package/dist/types/src/helpers/common.d.ts +0 -12
  201. package/dist/types/src/helpers/common.d.ts.map +0 -1
  202. package/dist/types/src/helpers/common.js +0 -23
  203. package/dist/types/src/helpers/common.js.map +0 -1
  204. package/dist/types/src/helpers/index.d.ts +0 -6
  205. package/dist/types/src/helpers/index.d.ts.map +0 -1
  206. package/dist/types/src/helpers/index.js +0 -9
  207. package/dist/types/src/helpers/index.js.map +0 -1
  208. package/dist/types/src/helpers/map-spaces.d.ts +0 -18
  209. package/dist/types/src/helpers/map-spaces.d.ts.map +0 -1
  210. package/dist/types/src/helpers/map-spaces.js +0 -36
  211. package/dist/types/src/helpers/map-spaces.js.map +0 -1
  212. package/dist/types/src/helpers/node-observability.d.ts +0 -24
  213. package/dist/types/src/helpers/node-observability.d.ts.map +0 -1
  214. package/dist/types/src/helpers/node-observability.js.map +0 -1
  215. package/dist/types/src/helpers/setup-telemetry-listeners.d.ts +0 -4
  216. package/dist/types/src/helpers/setup-telemetry-listeners.d.ts.map +0 -1
  217. package/dist/types/src/helpers/setup-telemetry-listeners.js +0 -94
  218. package/dist/types/src/helpers/setup-telemetry-listeners.js.map +0 -1
  219. package/dist/types/src/otel/index.d.ts +0 -5
  220. package/dist/types/src/otel/index.d.ts.map +0 -1
  221. package/dist/types/src/otel/index.js +0 -8
  222. package/dist/types/src/otel/index.js.map +0 -1
  223. package/dist/types/src/otel/logs.d.ts.map +0 -1
  224. package/dist/types/src/otel/logs.js.map +0 -1
  225. package/dist/types/src/otel/metrics.d.ts.map +0 -1
  226. package/dist/types/src/otel/metrics.js.map +0 -1
  227. package/dist/types/src/otel/otel.d.ts.map +0 -1
  228. package/dist/types/src/otel/otel.js.map +0 -1
  229. package/dist/types/src/otel/traces-browser.d.ts +0 -8
  230. package/dist/types/src/otel/traces-browser.d.ts.map +0 -1
  231. package/dist/types/src/otel/traces-browser.js +0 -53
  232. package/dist/types/src/otel/traces-browser.js.map +0 -1
  233. package/dist/types/src/otel/traces.d.ts +0 -8
  234. package/dist/types/src/otel/traces.d.ts.map +0 -1
  235. package/dist/types/src/otel/traces.js +0 -46
  236. package/dist/types/src/otel/traces.js.map +0 -1
  237. package/dist/types/src/segment/base.d.ts +0 -15
  238. package/dist/types/src/segment/base.d.ts.map +0 -1
  239. package/dist/types/src/segment/base.js +0 -51
  240. package/dist/types/src/segment/base.js.map +0 -1
  241. package/dist/types/src/segment/browser.d.ts +0 -15
  242. package/dist/types/src/segment/browser.d.ts.map +0 -1
  243. package/dist/types/src/segment/browser.js +0 -63
  244. package/dist/types/src/segment/browser.js.map +0 -1
  245. package/dist/types/src/segment/index.d.ts +0 -3
  246. package/dist/types/src/segment/index.d.ts.map +0 -1
  247. package/dist/types/src/segment/index.js +0 -6
  248. package/dist/types/src/segment/index.js.map +0 -1
  249. package/dist/types/src/segment/node.d.ts +0 -16
  250. package/dist/types/src/segment/node.d.ts.map +0 -1
  251. package/dist/types/src/segment/node.js +0 -84
  252. package/dist/types/src/segment/node.js.map +0 -1
  253. package/dist/types/src/segment/types.d.ts +0 -52
  254. package/dist/types/src/segment/types.d.ts.map +0 -1
  255. package/dist/types/src/segment/types.js +0 -18
  256. package/dist/types/src/segment/types.js.map +0 -1
  257. package/dist/types/src/sentry/browser.d.ts +0 -32
  258. package/dist/types/src/sentry/browser.d.ts.map +0 -1
  259. package/dist/types/src/sentry/browser.js +0 -110
  260. package/dist/types/src/sentry/browser.js.map +0 -1
  261. package/dist/types/src/sentry/index.d.ts +0 -3
  262. package/dist/types/src/sentry/index.d.ts.map +0 -1
  263. package/dist/types/src/sentry/index.js.map +0 -1
  264. package/dist/types/src/sentry/node.d.ts +0 -32
  265. package/dist/types/src/sentry/node.d.ts.map +0 -1
  266. package/dist/types/src/sentry/node.js +0 -106
  267. package/dist/types/src/sentry/node.js.map +0 -1
  268. package/dist/types/src/sentry/node.node.test.d.ts +0 -2
  269. package/dist/types/src/sentry/node.node.test.d.ts.map +0 -1
  270. package/dist/types/src/sentry/node.node.test.js +0 -32
  271. package/dist/types/src/sentry/node.node.test.js.map +0 -1
  272. package/dist/types/src/sentry/sentry-log-processor.d.ts +0 -9
  273. package/dist/types/src/sentry/sentry-log-processor.d.ts.map +0 -1
  274. package/dist/types/src/sentry/sentry-log-processor.js +0 -144
  275. package/dist/types/src/sentry/sentry-log-processor.js.map +0 -1
  276. package/dist/types/src/sentry/sentry.node.test.d.ts +0 -2
  277. package/dist/types/src/sentry/sentry.node.test.d.ts.map +0 -1
  278. package/dist/types/src/sentry/sentry.node.test.js +0 -28
  279. package/dist/types/src/sentry/sentry.node.test.js.map +0 -1
  280. package/dist/types/src/sentry/types.d.ts +0 -18
  281. package/dist/types/src/sentry/types.d.ts.map +0 -1
  282. package/dist/types/src/sentry/types.js +0 -4
  283. package/dist/types/src/sentry/types.js.map +0 -1
  284. package/dist/types/src/testing/index.d.ts +0 -2
  285. package/dist/types/src/testing/index.d.ts.map +0 -1
  286. package/dist/types/src/testing/index.js +0 -5
  287. package/dist/types/src/testing/index.js.map +0 -1
  288. package/dist/types/src/testing/testkit/browser.d.ts +0 -2
  289. package/dist/types/src/testing/testkit/browser.d.ts.map +0 -1
  290. package/dist/types/src/testing/testkit/browser.js +0 -7
  291. package/dist/types/src/testing/testkit/browser.js.map +0 -1
  292. package/dist/types/src/testing/testkit/index.d.ts +0 -2
  293. package/dist/types/src/testing/testkit/index.d.ts.map +0 -1
  294. package/dist/types/src/testing/testkit/index.js +0 -6
  295. package/dist/types/src/testing/testkit/index.js.map +0 -1
  296. package/src/helpers/browser-observability.ts +0 -178
  297. package/src/helpers/common.ts +0 -38
  298. package/src/helpers/index.ts +0 -9
  299. package/src/helpers/map-spaces.ts +0 -48
  300. package/src/helpers/setup-telemetry-listeners.ts +0 -109
  301. package/src/otel/index.ts +0 -8
  302. package/src/otel/logs.ts +0 -102
  303. package/src/otel/traces-browser.ts +0 -62
  304. package/src/otel/traces.ts +0 -60
  305. package/src/segment/base.ts +0 -69
  306. package/src/segment/browser.ts +0 -69
  307. package/src/segment/node.ts +0 -95
  308. package/src/segment/types.ts +0 -57
  309. package/src/sentry/browser.ts +0 -133
  310. package/src/sentry/index.ts +0 -6
  311. package/src/sentry/node.node.test.ts +0 -40
  312. package/src/sentry/node.ts +0 -126
  313. package/src/sentry/sentry-log-processor.ts +0 -174
  314. package/src/sentry/sentry.node.test.ts +0 -35
  315. package/src/sentry/types.ts +0 -22
  316. package/src/testing/index.ts +0 -5
  317. package/src/testing/testkit/browser.ts +0 -8
  318. package/src/testing/testkit/index.ts +0 -7
  319. package/src/testing/testkit/shims.d.ts +0 -5
  320. /package/dist/lib/browser/{chunk-5ICT2XF2.mjs.map → chunk-J5LGTIGS.mjs.map} +0 -0
  321. /package/dist/lib/{browser/observability-CQGG3MID.mjs.map → node-esm/chunk-HSLMI22Q.mjs.map} +0 -0
  322. /package/dist/types/src/{otel → extensions/otel}/metrics.d.ts +0 -0
  323. /package/dist/types/src/{otel → extensions/otel}/otel.js +0 -0
  324. /package/dist/types/src/{sentry → storage}/index.js +0 -0
@@ -0,0 +1,139 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import {
6
+ ROOT_CONTEXT,
7
+ SpanStatusCode,
8
+ type Tracer,
9
+ context as otelContext,
10
+ propagation,
11
+ trace,
12
+ } from '@opentelemetry/api';
13
+ import { getWebAutoInstrumentations } from '@opentelemetry/auto-instrumentations-web';
14
+ import { W3CTraceContextPropagator } from '@opentelemetry/core';
15
+ import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
16
+ import { registerInstrumentations } from '@opentelemetry/instrumentation';
17
+ import {
18
+ AlwaysOnSampler,
19
+ BatchSpanProcessor,
20
+ ParentBasedSampler,
21
+ TraceIdRatioBasedSampler,
22
+ } from '@opentelemetry/sdk-trace-base';
23
+ import { WebTracerProvider } from '@opentelemetry/sdk-trace-web';
24
+ import { ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';
25
+
26
+ import { log } from '@dxos/log';
27
+ import { TRACE_ALL_KEY, type RemoteSpan, type StartSpanOptions, TRACE_PROCESSOR } from '@dxos/tracing';
28
+
29
+ import { type OtelOptions } from './otel';
30
+ import { TagInjectorSpanProcessor } from './span-processors';
31
+
32
+ export class OtelTraces {
33
+ private _tracer: Tracer;
34
+ private readonly _tracerProvider: WebTracerProvider;
35
+
36
+ constructor(private readonly options: OtelOptions) {
37
+ propagation.setGlobalPropagator(new W3CTraceContextPropagator());
38
+
39
+ const forceTraceAll = typeof localStorage !== 'undefined' && localStorage.getItem(TRACE_ALL_KEY) === 'true';
40
+
41
+ this._tracerProvider = new WebTracerProvider({
42
+ resource: this.options.resource,
43
+ sampler: new ParentBasedSampler({
44
+ root: forceTraceAll ? new AlwaysOnSampler() : new TraceIdRatioBasedSampler(0.3),
45
+ }),
46
+ spanProcessors: [
47
+ new TagInjectorSpanProcessor(this.options.getTags),
48
+ new BatchSpanProcessor(
49
+ new OTLPTraceExporter({
50
+ url: this.options.endpoint + '/v1/traces',
51
+ headers: this.options.headers,
52
+ concurrencyLimit: 10,
53
+ }),
54
+ { scheduledDelayMillis: 5_000 },
55
+ ),
56
+ ],
57
+ });
58
+
59
+ trace.setGlobalTracerProvider(this._tracerProvider);
60
+
61
+ this._tracer = trace.getTracer(
62
+ 'dxos-observability',
63
+ this.options.resource.attributes[ATTR_SERVICE_VERSION]?.toString(),
64
+ );
65
+ }
66
+
67
+ /**
68
+ * Forcibly flush the BatchSpanProcessor. Call before process exit / page unload
69
+ * to avoid losing queued spans (which manifests as "Missing Span" in SigNoz —
70
+ * their already-exported children reference a parent that never made it to OTLP).
71
+ */
72
+ public async flush(): Promise<void> {
73
+ await this._tracerProvider.forceFlush();
74
+ }
75
+
76
+ /**
77
+ * Flush + shut down the tracer provider via `WebTracerProvider.shutdown()`,
78
+ * which forces a final export then terminates all span processors.
79
+ *
80
+ * Terminal and effectively one-shot: safe to call after `flush()`, but
81
+ * `flush()` MUST NOT be called after `close()` — shutdown stops further
82
+ * exporting, so subsequent `close()`/`flush()` calls resolve without
83
+ * emitting new spans.
84
+ */
85
+ public async close(): Promise<void> {
86
+ await this._tracerProvider.shutdown();
87
+ }
88
+
89
+ public start(): void {
90
+ log('trace processor registered');
91
+
92
+ registerInstrumentations({
93
+ instrumentations: [
94
+ getWebAutoInstrumentations({
95
+ '@opentelemetry/instrumentation-fetch': { enabled: false, ignoreUrls: [/api\.ipdata\.co/] },
96
+ '@opentelemetry/instrumentation-document-load': { enabled: false },
97
+ '@opentelemetry/instrumentation-xml-http-request': { enabled: false },
98
+ '@opentelemetry/instrumentation-user-interaction': { enabled: false },
99
+ }),
100
+ ],
101
+ });
102
+
103
+ const tracer = this._tracer;
104
+
105
+ TRACE_PROCESSOR.tracingBackend = {
106
+ startSpan: (options: StartSpanOptions): RemoteSpan => {
107
+ log('begin otel trace', { options });
108
+ const parentCtx = options.parentContext
109
+ ? propagation.extract(ROOT_CONTEXT, {
110
+ traceparent: options.parentContext.traceparent,
111
+ tracestate: options.parentContext.tracestate ?? '',
112
+ })
113
+ : otelContext.active();
114
+
115
+ const span = tracer.startSpan(options.name, options, parentCtx);
116
+
117
+ const sc = span.spanContext();
118
+ const spanContext =
119
+ sc && sc.traceId && sc.spanId
120
+ ? {
121
+ traceparent: `00-${sc.traceId}-${sc.spanId}-${(sc.traceFlags ?? 0).toString(16).padStart(2, '0')}`,
122
+ tracestate: sc.traceState?.serialize(),
123
+ }
124
+ : undefined;
125
+
126
+ return {
127
+ end: (endTime?: number) => span.end(endTime),
128
+ setError: (err: unknown) => {
129
+ if (err instanceof Error) {
130
+ span.recordException(err);
131
+ }
132
+ span.setStatus({ code: SpanStatusCode.ERROR, message: err instanceof Error ? err.message : String(err) });
133
+ },
134
+ spanContext,
135
+ };
136
+ },
137
+ };
138
+ }
139
+ }
@@ -0,0 +1,113 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import {
6
+ ROOT_CONTEXT,
7
+ SpanStatusCode,
8
+ type Tracer,
9
+ context as otelContext,
10
+ propagation,
11
+ trace,
12
+ } from '@opentelemetry/api';
13
+ import { W3CTraceContextPropagator } from '@opentelemetry/core';
14
+ import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
15
+ import { BasicTracerProvider, BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
16
+ import { ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';
17
+
18
+ import { log } from '@dxos/log';
19
+ import { type RemoteSpan, type StartSpanOptions, TRACE_PROCESSOR } from '@dxos/tracing';
20
+
21
+ import { type OtelOptions } from './otel';
22
+ import { TagInjectorSpanProcessor } from './span-processors';
23
+
24
+ export class OtelTraces {
25
+ private _tracer: Tracer;
26
+ private readonly _tracerProvider: BasicTracerProvider;
27
+
28
+ constructor(private readonly options: OtelOptions) {
29
+ propagation.setGlobalPropagator(new W3CTraceContextPropagator());
30
+
31
+ this._tracerProvider = new BasicTracerProvider({
32
+ resource: this.options.resource,
33
+ spanProcessors: [
34
+ new TagInjectorSpanProcessor(this.options.getTags),
35
+ new BatchSpanProcessor(
36
+ new OTLPTraceExporter({
37
+ url: this.options.endpoint + '/v1/traces',
38
+ headers: this.options.headers,
39
+ concurrencyLimit: 10,
40
+ }),
41
+ ),
42
+ ],
43
+ });
44
+
45
+ trace.setGlobalTracerProvider(this._tracerProvider);
46
+ this._tracer = trace.getTracer(
47
+ 'dxos-observability',
48
+ this.options.resource.attributes[ATTR_SERVICE_VERSION]?.toString(),
49
+ );
50
+ }
51
+
52
+ /**
53
+ * Forcibly flush the BatchSpanProcessor. Call before process exit to avoid
54
+ * losing queued spans (which manifests as "Missing Span" in SigNoz — their
55
+ * already-exported children reference a parent that never made it to OTLP).
56
+ */
57
+ public async flush(): Promise<void> {
58
+ await this._tracerProvider.forceFlush();
59
+ }
60
+
61
+ /**
62
+ * Flush + shut down the tracer provider via `BasicTracerProvider.shutdown()`,
63
+ * which forces a final export then terminates all span processors.
64
+ *
65
+ * Terminal and effectively one-shot: safe to call after `flush()`, but
66
+ * `flush()` MUST NOT be called after `close()` — shutdown stops further
67
+ * exporting, so subsequent `close()`/`flush()` calls resolve without
68
+ * emitting new spans.
69
+ */
70
+ public async close(): Promise<void> {
71
+ await this._tracerProvider.shutdown();
72
+ }
73
+
74
+ public start(): void {
75
+ log('trace processor registered');
76
+
77
+ const tracer = this._tracer;
78
+
79
+ TRACE_PROCESSOR.tracingBackend = {
80
+ startSpan: (options: StartSpanOptions): RemoteSpan => {
81
+ log('begin otel trace', { options });
82
+ const parentCtx = options.parentContext
83
+ ? propagation.extract(ROOT_CONTEXT, {
84
+ traceparent: options.parentContext.traceparent,
85
+ tracestate: options.parentContext.tracestate ?? '',
86
+ })
87
+ : otelContext.active();
88
+
89
+ const span = tracer.startSpan(options.name, options, parentCtx);
90
+
91
+ const sc = span.spanContext();
92
+ const spanContext =
93
+ sc && sc.traceId && sc.spanId
94
+ ? {
95
+ traceparent: `00-${sc.traceId}-${sc.spanId}-${(sc.traceFlags ?? 0).toString(16).padStart(2, '0')}`,
96
+ tracestate: sc.traceState?.serialize(),
97
+ }
98
+ : undefined;
99
+
100
+ return {
101
+ end: (endTime?: number) => span.end(endTime),
102
+ setError: (err: unknown) => {
103
+ if (err instanceof Error) {
104
+ span.recordException(err);
105
+ }
106
+ span.setStatus({ code: SpanStatusCode.ERROR, message: err instanceof Error ? err.message : String(err) });
107
+ },
108
+ spanContext,
109
+ };
110
+ },
111
+ };
112
+ }
113
+ }
@@ -0,0 +1,181 @@
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
+ import { type IdbLogStore } from '@dxos/log-store-idb';
11
+
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
+ * Shared persistent log store for debug log dumps.
24
+ * The owning app is expected to register `logStore.processor` with `log` itself —
25
+ * this extension only consumes the buffered logs (via `export()`).
26
+ */
27
+ logStore?: IdbLogStore;
28
+ };
29
+
30
+ /** Upload serialized logs to the feedback-logs endpoint. Returns the R2 key on success. */
31
+ const uploadLogs = async (body: string): Promise<string | undefined> => {
32
+ try {
33
+ const response = await fetch('/api/feedback-logs', {
34
+ method: 'POST',
35
+ headers: { 'Content-Type': 'application/x-ndjson' },
36
+ body,
37
+ });
38
+ if (!response.ok) {
39
+ log.warn('feedback log upload failed', { status: response.status });
40
+ return undefined;
41
+ }
42
+ const { key } = await response.json();
43
+ return key;
44
+ } catch (err) {
45
+ log.warn('feedback log upload error', { error: err });
46
+ return undefined;
47
+ }
48
+ };
49
+
50
+ /** Create a PostHog-backed observability extension for events, errors, and feedback. */
51
+ export const extensions: (options: ExtensionsOptions) => Effect.Effect<Extension> = Effect.fn(function* ({
52
+ config,
53
+ release,
54
+ environment,
55
+ posthog: posthogConfig,
56
+ logStore,
57
+ }) {
58
+ if (typeof window === 'undefined') {
59
+ log('PostHog is being stubbed because it is running in a worker.');
60
+ return stubExtension;
61
+ }
62
+
63
+ const feedbackSurveyId = config.get('runtime.app.env.DX_POSTHOG_FEEDBACK_SURVEY_ID');
64
+ const apiKey = config.get('runtime.app.env.DX_POSTHOG_API_KEY');
65
+ const api_host = config.get('runtime.app.env.DX_POSTHOG_API_HOST');
66
+ if (!apiKey || !api_host) {
67
+ log.info('Missing POSTHOG_API_KEY or POSTHOG_API_HOST');
68
+ return stubExtension;
69
+ }
70
+
71
+ const { default: posthog } = yield* Effect.promise(() => import('posthog-js'));
72
+ const { logProcessor } = yield* Effect.promise(() => import('./log-processor'));
73
+ let feedbackSurveyAvailable: boolean | null = null;
74
+ let unregisterPosthogProcessors: (() => void) | undefined;
75
+
76
+ const checkFeedbackSurveyAvailable = (): Effect.Effect<boolean> =>
77
+ feedbackSurveyId
78
+ ? Effect.promise(() => {
79
+ if (feedbackSurveyAvailable !== null) {
80
+ return Promise.resolve(feedbackSurveyAvailable);
81
+ }
82
+ return new Promise<boolean>((resolve) => {
83
+ posthog.getSurveys((surveys) => {
84
+ const found = surveys.some((s) => s.id === feedbackSurveyId);
85
+ feedbackSurveyAvailable = found;
86
+ resolve(found);
87
+ });
88
+ });
89
+ })
90
+ : Effect.succeed(false);
91
+
92
+ return {
93
+ initialize: () =>
94
+ Effect.sync(() => {
95
+ // https://posthog.com/docs/libraries/js/config
96
+ posthog.init(apiKey, {
97
+ api_host,
98
+ mask_all_text: true,
99
+ capture_exceptions: true,
100
+ ...posthogConfig,
101
+ });
102
+ if (release || environment) {
103
+ posthog.register({
104
+ ...(release ? { release } : {}),
105
+ ...(environment ? { environment } : {}),
106
+ });
107
+ }
108
+ unregisterPosthogProcessors?.();
109
+ const removePosthogLog = log.addProcessor(logProcessor);
110
+ unregisterPosthogProcessors = () => {
111
+ removePosthogLog();
112
+ };
113
+ }),
114
+ close: () =>
115
+ Effect.sync(() => {
116
+ unregisterPosthogProcessors?.();
117
+ unregisterPosthogProcessors = undefined;
118
+ }),
119
+ enable: () => Effect.sync(() => posthog.opt_in_capturing()),
120
+ disable: () => Effect.sync(() => posthog.opt_out_capturing()),
121
+ identify: (distinctId, attributes, setOnceAttributes) => {
122
+ posthog.identify(distinctId, attributes, setOnceAttributes);
123
+ },
124
+ alias: (distinctId, previousId) => {
125
+ posthog.alias(distinctId, previousId);
126
+ },
127
+ setTags: (tags) => {
128
+ posthog.register_for_session(tags);
129
+ },
130
+ get enabled(): boolean {
131
+ return posthog.is_capturing();
132
+ },
133
+ apis: [
134
+ {
135
+ kind: 'events',
136
+ isAvailable: () => Effect.succeed(true),
137
+ captureEvent: (event, attributes) => {
138
+ posthog.capture(event, attributes);
139
+ },
140
+ },
141
+ {
142
+ kind: 'errors',
143
+ isAvailable: () => Effect.succeed(true),
144
+ captureException: (error, attributes) => {
145
+ posthog.captureException(error, attributes);
146
+ },
147
+ },
148
+ {
149
+ kind: 'feedback',
150
+ // TODO(wittjosiah): Support custom surveys.
151
+ captureUserFeedback: (form) => {
152
+ posthog.getSurveys(async (surveys) => {
153
+ const survey = surveys.find((survey) => survey.id === feedbackSurveyId);
154
+ if (!survey || survey.questions.length === 0) {
155
+ log.error('Missing feedback survey or survey has no questions', { feedbackSurveyId });
156
+ return;
157
+ }
158
+
159
+ let debugLogDumpKey: string | null = null;
160
+ if (form.includeLogs !== false && logStore !== undefined) {
161
+ const ndjson = await logStore.export();
162
+ if (ndjson.length > 0) {
163
+ debugLogDumpKey = (await uploadLogs(ndjson)) ?? 'failed';
164
+ }
165
+ }
166
+
167
+ // https://posthog.com/docs/surveys/implementing-custom-surveys
168
+ const question = survey.questions[0];
169
+ posthog.capture('survey sent', {
170
+ $survey_id: survey.id,
171
+ $survey_questions: [{ id: question.id, question: question.question }],
172
+ [`$survey_response_${question.id}`]: form.message,
173
+ debug_log_dump_key: debugLogDumpKey,
174
+ });
175
+ });
176
+ },
177
+ isAvailable: checkFeedbackSurveyAvailable,
178
+ },
179
+ ],
180
+ };
181
+ });
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './extension';
@@ -0,0 +1,186 @@
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, LogEntry, type LogEntryInit, 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<LogEntryInit> = {}): LogEntry =>
27
+ new LogEntry({
28
+ level: LogLevel.ERROR,
29
+ message: 'test error',
30
+ ...overrides,
31
+ });
32
+
33
+ describe('logProcessor', () => {
34
+ beforeEach(() => {
35
+ vi.clearAllMocks();
36
+ });
37
+
38
+ test('skips entries that do not pass capture filters', () => {
39
+ const entry = createEntry({ level: LogLevel.DEBUG });
40
+ logProcessor(baseConfig, entry);
41
+ expect(posthog.captureException).not.toHaveBeenCalled();
42
+ });
43
+
44
+ test('skips entries from remote sessions', () => {
45
+ const entry = createEntry({
46
+ error: new Error('test'),
47
+ meta: { F: 'test.ts', L: 1, S: { remoteSessionId: 'remote-123' } },
48
+ });
49
+ logProcessor(baseConfig, entry);
50
+ expect(posthog.captureException).not.toHaveBeenCalled();
51
+ });
52
+
53
+ test('skips entries without errors', () => {
54
+ const entry = createEntry({ error: undefined, context: {} });
55
+ logProcessor(baseConfig, entry);
56
+ expect(posthog.captureException).not.toHaveBeenCalled();
57
+ });
58
+
59
+ test('captures error from entry.error', () => {
60
+ const error = new Error('direct error');
61
+ const entry = createEntry({
62
+ error,
63
+ meta: { F: 'packages/sdk/observability/src/test.ts', L: 42, S: undefined },
64
+ });
65
+ logProcessor(baseConfig, entry);
66
+ expect(posthog.captureException).toHaveBeenCalledWith(
67
+ error,
68
+ expect.objectContaining({
69
+ transaction: 'packages/sdk/observability/src/test.ts:42',
70
+ }),
71
+ );
72
+ });
73
+
74
+ test('captures error from context when level is ERROR but no entry.error', () => {
75
+ const contextError = new Error('context error');
76
+ const entry = createEntry({
77
+ level: LogLevel.ERROR,
78
+ error: undefined,
79
+ context: { someKey: contextError },
80
+ meta: { F: 'test.ts', L: 10, S: undefined },
81
+ });
82
+ logProcessor(baseConfig, entry);
83
+ expect(posthog.captureException).toHaveBeenCalledWith(contextError, expect.any(Object));
84
+ });
85
+
86
+ test('sets transaction from file:line metadata', () => {
87
+ const entry = createEntry({
88
+ error: new Error('err'),
89
+ meta: { F: '/home/user/project/packages/sdk/observability/src/index.ts', L: 99, S: undefined },
90
+ });
91
+ logProcessor(baseConfig, entry);
92
+ expect(posthog.captureException).toHaveBeenCalledWith(
93
+ expect.any(Error),
94
+ expect.objectContaining({
95
+ transaction: 'packages/sdk/observability/src/index.ts:99',
96
+ }),
97
+ );
98
+ });
99
+
100
+ test('sets service_host_issue/session for worker entries', () => {
101
+ const entry = createEntry({
102
+ error: new Error('worker err'),
103
+ meta: { F: 'test.ts', L: 1, S: { hostSessionId: 'host-abc' } },
104
+ });
105
+ logProcessor(baseConfig, entry);
106
+ expect(posthog.captureException).toHaveBeenCalledWith(
107
+ expect.any(Error),
108
+ expect.objectContaining({
109
+ service_host_issue: true,
110
+ service_host_session: 'host-abc',
111
+ }),
112
+ );
113
+ });
114
+
115
+ test('sets uptime_seconds from metadata', () => {
116
+ const entry = createEntry({
117
+ error: new Error('err'),
118
+ meta: { F: 'test.ts', L: 1, S: { uptimeSeconds: 123 } },
119
+ });
120
+ logProcessor(baseConfig, entry);
121
+ expect(posthog.captureException).toHaveBeenCalledWith(
122
+ expect.any(Error),
123
+ expect.objectContaining({
124
+ uptime_seconds: 123,
125
+ }),
126
+ );
127
+ });
128
+
129
+ test('sets invariant_violation flag for InvariantViolation errors', () => {
130
+ const error = new InvariantViolation('broken invariant');
131
+ const entry = createEntry({
132
+ error,
133
+ meta: { F: 'test.ts', L: 1, S: undefined },
134
+ });
135
+ logProcessor(baseConfig, entry);
136
+ expect(posthog.captureException).toHaveBeenCalledWith(
137
+ error,
138
+ expect.objectContaining({
139
+ invariant_violation: true,
140
+ }),
141
+ );
142
+ });
143
+
144
+ test('does not set invariant_violation for normal errors', () => {
145
+ const error = new Error('normal error');
146
+ const entry = createEntry({
147
+ error,
148
+ meta: { F: 'test.ts', L: 1, S: undefined },
149
+ });
150
+ logProcessor(baseConfig, entry);
151
+ const callArgs = vi.mocked(posthog.captureException).mock.calls[0];
152
+ expect(callArgs[1]).not.toHaveProperty('invariant_violation');
153
+ });
154
+ });
155
+
156
+ describe('getRelativeFilename', () => {
157
+ // We test this indirectly through the transaction property set by logProcessor.
158
+
159
+ test('extracts relative path from absolute path containing packages/', () => {
160
+ const entry = createEntry({
161
+ error: new Error('err'),
162
+ meta: { F: '/home/user/code/packages/sdk/observability/src/file.ts', L: 5, S: undefined },
163
+ });
164
+ logProcessor(baseConfig, entry);
165
+ expect(posthog.captureException).toHaveBeenCalledWith(
166
+ expect.any(Error),
167
+ expect.objectContaining({
168
+ transaction: 'packages/sdk/observability/src/file.ts:5',
169
+ }),
170
+ );
171
+ });
172
+
173
+ test('returns original filename if no match', () => {
174
+ const entry = createEntry({
175
+ error: new Error('err'),
176
+ meta: { F: 'no-packages-here.ts', L: 1, S: undefined },
177
+ });
178
+ logProcessor(baseConfig, entry);
179
+ expect(posthog.captureException).toHaveBeenCalledWith(
180
+ expect.any(Error),
181
+ expect.objectContaining({
182
+ transaction: 'no-packages-here.ts:1',
183
+ }),
184
+ );
185
+ });
186
+ });
@@ -0,0 +1,43 @@
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
+ const { filename, line } = entry.computedMeta;
27
+ if (filename !== undefined && line !== undefined) {
28
+ additionalProperties.transaction = `${filename}:${line}`;
29
+ }
30
+ if (entry.meta?.S?.hostSessionId) {
31
+ additionalProperties.service_host_issue = true;
32
+ additionalProperties.service_host_session = entry.meta.S.hostSessionId;
33
+ }
34
+ if (entry.meta?.S?.uptimeSeconds != null) {
35
+ additionalProperties.uptime_seconds = entry.meta.S.uptimeSeconds;
36
+ }
37
+
38
+ if (capturedError instanceof InvariantViolation) {
39
+ additionalProperties.invariant_violation = true;
40
+ }
41
+
42
+ posthog.captureException(capturedError, additionalProperties);
43
+ };
@@ -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
+ };