@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
@@ -1,634 +1,293 @@
1
1
  //
2
- // Copyright 2023 DXOS.org
2
+ // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Event, scheduleTaskInterval } from '@dxos/async';
6
- import { PublicKey, type Client, type Config } from '@dxos/client';
7
- import { type ClientServices, type Space } from '@dxos/client-protocol';
8
- import { Context } from '@dxos/context';
5
+ import * as Array from 'effect/Array';
6
+ import * as Effect from 'effect/Effect';
7
+ import * as Function from 'effect/Function';
8
+
9
+ import { type CleanupFn, SubscriptionList } from '@dxos/async';
9
10
  import { invariant } from '@dxos/invariant';
10
- import { log, LogLevel } from '@dxos/log';
11
- import { ConnectionState } from '@dxos/network-manager';
12
- import { DeviceKind, type NetworkStatus, Platform } from '@dxos/protocols/proto/dxos/client/services';
13
- import { isNode } from '@dxos/util';
14
-
15
- import buildSecrets from './cli-observability-secrets.json';
16
- import { getTelemetryIdentity, type IPData, mapSpaces } from './helpers';
17
- import { type OtelLogs, type OtelMetrics, type OtelTraces } from './otel';
18
- import { type SegmentTelemetry, type TrackOptions, type PageOptions, TelemetryEvent } from './segment';
19
- import { type InitOptions, type captureException as SentryCaptureException } from './sentry';
20
- import { type SentryLogProcessor } from './sentry/sentry-log-processor';
21
-
22
- const SPACE_METRICS_MIN_INTERVAL = 1000 * 60; // 1 minute
23
- const SPACE_TELEMETRY_MIN_INTERVAL = 1000 * 60 * 60; // 1 hour
24
- const NETWORK_METRICS_MIN_INTERVAL = 1000 * 60 * 5; // 5 minutes
25
-
26
- // Secrets? EnvironmentConfig?
27
-
28
- export type ObservabilitySecrets = {
29
- DX_ENVIRONMENT: string | null;
30
- DX_RELEASE: string | null;
31
- SENTRY_DESTINATION: string | null;
32
- TELEMETRY_API_KEY: string | null;
33
- IPDATA_API_KEY: string | null;
34
- OTEL_ENDPOINT: string | null;
35
- OTEL_AUTHORIZATION: string | null;
36
- };
37
-
38
- export type TagScope = 'errors' | 'telemetry' | 'metrics' | 'all';
39
-
40
- /** Gathering mode. */
41
- export type Mode = 'basic' | 'full' | 'disabled';
42
-
43
- export type ObservabilityOptions = {
44
- mode: Mode;
45
-
46
- /** Environment. */
47
- environment?: string;
48
-
49
- /** Application namespace. */
50
- namespace: string;
51
-
52
- /** Application release. */
53
- release?: string;
54
-
55
- /** User group. */
56
- group?: string;
57
-
58
- config?: Config;
59
- secrets?: Record<string, string>;
60
-
61
- telemetry?: {
62
- batchSize?: number;
63
- };
64
-
65
- errorLog?: {
66
- sentryInitOptions?: InitOptions;
67
- };
68
- };
69
-
70
- /*
71
- * Observability provides a common interface for error logging, metrics, and telemetry.
72
- * It currently provides these capabilities using Sentry, OpenTelemetry, and Segment.
73
- *
74
- * Segment:
75
- * https://app.segment.com/dxos/sources/composer-app/debugger
76
- * https://app.segment.com/dxos/sources/composer-app/settings/keys
77
- *
78
- * NOTE:
79
- * - Segment maintains a set of admin creates Source (e.g., "composer-app").
80
- * - Each source has at least one API_KEY, which is used by the client.
81
- *
82
- * Testing:
83
- * https://app.segment.com/dxos/sources/composer-app/settings/keys
84
- * - DX_TELEMETRY_API_KEY
85
- * - DX_SENTRY_DESTINATION
86
- *
87
- * Sentry:
88
- * https://sentry.io/organizations/dxos/issues
89
- *
90
- * OpenTelemetry:
91
- * https://dxosorg.grafana.net/explore
11
+ import { log } from '@dxos/log';
12
+
13
+ import {
14
+ type Attributes,
15
+ type Errors,
16
+ type Events,
17
+ type Extension,
18
+ type ExtensionApi,
19
+ type Feedback,
20
+ type Kind,
21
+ type Metrics,
22
+ } from './observability-extension';
23
+
24
+ export * from './storage';
25
+
26
+ // TODO(wittjosiah): Figure out how to handle when telemetry is disabled.
27
+ // In theory the setting should be both persisted and synchronized.
28
+ // Initialize probably should still run for the cases where data is emitted manually (e.g., feedback).
29
+
30
+ /**
31
+ * Provider of observability data.
92
32
  */
93
- export class Observability {
94
- private _mode: Mode;
95
- private readonly _namespace: string;
96
- private readonly _config?: Config;
97
- private readonly _group?: string;
98
- private readonly _secrets: ObservabilitySecrets;
99
- private readonly _tags = new Map<string, { value: string; scope: TagScope }>();
100
-
101
- // TODO(wittjosiah): Generic metrics interface.
102
- private _otelMetrics?: OtelMetrics;
103
- private _otelTraces?: OtelTraces;
104
- // TODO(wittjosiah): Generic telemetry interface.
105
- private _telemetryBatchSize: number;
106
- private _telemetry?: SegmentTelemetry;
107
- // TODO(wittjosiah): Generic error logging interface.
108
- private _sentryLogProcessor?: SentryLogProcessor;
109
- private _otelLogs?: OtelLogs;
110
- private _errorReportingOptions?: InitOptions;
111
- private _captureException?: typeof SentryCaptureException;
112
- private _captureUserFeedback?: (message: string) => Promise<void>;
113
- private _lastNetworkStatus?: NetworkStatus;
114
-
115
- private _ctx = new Context();
116
-
117
- // TODO(nf): make platform a required extension?
118
- constructor({
119
- mode,
120
- namespace,
121
- environment,
122
- release,
123
- config,
124
- group,
125
- secrets,
126
- telemetry,
127
- errorLog,
128
- }: ObservabilityOptions) {
129
- this._mode = mode;
130
- this._namespace = namespace;
131
- this._config = config;
132
- this._group = group;
133
- this._secrets = this._loadSecrets(config, secrets);
134
-
135
- this._telemetryBatchSize = telemetry?.batchSize ?? 30;
136
- this._errorReportingOptions = errorLog?.sentryInitOptions;
137
-
138
- // Tags.
139
- this.setTag('mode', this._mode);
140
- this.setTag('namespace', this._namespace);
141
- this.setTag('environment', environment);
142
- this.setTag('release', release);
143
- this.setTag('session', PublicKey.random().toHex());
144
- this.setTag('group', this._group);
145
- }
146
-
147
- get mode() {
148
- return this._mode;
149
- }
150
-
151
- get group() {
152
- return this._group;
153
- }
154
-
155
- get enabled() {
156
- return this._mode !== 'disabled';
157
- }
33
+ export type DataProvider = (observability: Observability) => Effect.Effect<CleanupFn | void, Error>;
158
34
 
159
- private _loadSecrets(config: Config | undefined, secrets?: Record<string, string>) {
160
- if (isNode()) {
161
- const mergedSecrets = {
162
- ...(buildSecrets as ObservabilitySecrets),
163
- ...secrets,
164
- };
165
-
166
- process.env.DX_ENVIRONMENT && (mergedSecrets.DX_ENVIRONMENT = process.env.DX_ENVIRONMENT);
167
- process.env.DX_RELEASE && (mergedSecrets.DX_RELEASE = process.env.DX_RELEASE);
168
- process.env.SENTRY_DESTINATION && (mergedSecrets.SENTRY_DESTINATION = process.env.SENTRY_DESTINATION);
169
- process.env.TELEMETRY_API_KEY && (mergedSecrets.TELEMETRY_API_KEY = process.env.TELEMETRY_API_KEY);
170
- process.env.IPDATA_API_KEY && (mergedSecrets.IPDATA_API_KEY = process.env.IPDATA_API_KEY);
171
- process.env.DX_OTEL_ENDPOINT && (mergedSecrets.OTEL_ENDPOINT = process.env.DX_OTEL_ENDPOINT);
172
- process.env.DX_OTEL_AUTHORIZATION && (mergedSecrets.OTEL_AUTHORIZATION = process.env.DX_OTEL_AUTHORIZATION);
173
-
174
- return mergedSecrets;
175
- } else {
176
- log('config', { rtc: this._secrets, config });
177
- return {
178
- DX_ENVIRONMENT: config?.get('runtime.app.env.DX_ENVIRONMENT'),
179
- DX_RELEASE: config?.get('runtime.app.env.DX_RELEASE'),
180
- SENTRY_DESTINATION: config?.get('runtime.app.env.DX_SENTRY_DESTINATION'),
181
- TELEMETRY_API_KEY: config?.get('runtime.app.env.DX_TELEMETRY_API_KEY'),
182
- IPDATA_API_KEY: config?.get('runtime.app.env.DX_IPDATA_API_KEY'),
183
- OTEL_ENDPOINT: config?.get('runtime.app.env.DX_OTEL_ENDPOINT'),
184
- OTEL_AUTHORIZATION: config?.get('runtime.app.env.DX_OTEL_AUTHORIZATION'),
185
- ...secrets,
186
- };
187
- }
188
- }
189
-
190
- async initialize(): Promise<void> {
191
- log('initializing...');
192
- await this._initLogs();
193
- await this._initMetrics();
194
- await this._initTelemetry();
195
- await this._initErrorLogs();
196
- await this._initTraces();
197
- }
198
-
199
- async close(): Promise<void> {
200
- log('closing...');
201
- const closes: Promise<void>[] = [];
202
- this._telemetry && closes.push(this._telemetry.close());
203
- this._otelMetrics && closes.push(this._otelMetrics.close());
204
- this._otelLogs && closes.push(this._otelLogs.close());
205
-
206
- await Promise.all(closes);
207
- await this._ctx.dispose();
208
- }
209
-
210
- setMode(mode: Mode): void {
211
- this._mode = mode;
212
- }
213
-
214
- //
215
- // Tags
216
- //
217
-
218
- /** Callback (e.g., to share tags with Sentry.) */
219
- private _setTag?: (key: string, value: string) => void;
220
-
221
- /**
222
- * camelCase keys are converted to snake_case in Segment.
223
- */
224
- setTag(key: string, value: string | undefined, scope?: TagScope): void {
225
- if (value === undefined) {
226
- return;
227
- }
228
- if (this.enabled && (scope === undefined || scope === 'all' || scope === 'errors')) {
229
- this._setTag?.(key, value);
230
- }
231
- if (!scope) {
232
- scope = 'all';
233
- }
234
-
235
- this._tags.set(key, { value, scope });
236
- }
237
-
238
- getTag(key: string) {
239
- return this._tags.get(key);
240
- }
35
+ /**
36
+ * Extensible observability provider.
37
+ */
38
+ // TODO(wittjosiah): Add pipe method.
39
+ export interface Observability {
40
+ initialize(): Effect.Effect<void>;
41
+ close(): Effect.Effect<void>;
42
+ enable(): Effect.Effect<void>;
43
+ disable(): Effect.Effect<void>;
44
+ flush(): Effect.Effect<void>;
45
+ addDataProvider(dataProvider: DataProvider): Effect.Effect<void, Error>;
46
+ identify(distinctId: string, attributes?: Attributes, setOnceAttributes?: Attributes): void;
47
+ alias(distinctId: string, previousId?: string): void;
48
+ setTags(tags: Attributes, kind?: Kind): void;
49
+ enabled: boolean;
50
+ errors: Errors;
51
+ events: Events;
52
+ feedback: Feedback;
53
+ /** True if at least one extension of the given kind reports as available. */
54
+ isAvailable(kind: Kind): Effect.Effect<boolean>;
55
+ metrics: Metrics;
56
+ }
241
57
 
242
- // TODO(wittjosiah): Improve privacy of telemetry identifiers. See `getTelemetryIdentifier`.
243
- async setIdentityTags(clientServices: Partial<ClientServices>): Promise<void> {
244
- if (clientServices.IdentityService) {
245
- clientServices.IdentityService.queryIdentity().subscribe((idqr) => {
246
- if (!idqr?.identity?.did) {
247
- log('empty response from identity service', { idqr });
248
- return;
249
- }
58
+ class ObservabilityImpl implements Observability {
59
+ private _initialized = false;
60
+ private readonly _extensions: Extension[] = [];
61
+ private readonly _dataProviders: DataProvider[] = [];
62
+ private readonly _subscriptions = new SubscriptionList();
250
63
 
251
- this.setTag('did', idqr.identity.did);
252
- this._telemetry?.identify({ userId: idqr.identity.did });
253
- });
64
+ initialize(): Effect.Effect<void> {
65
+ if (this._initialized) {
66
+ return Effect.succeed(undefined);
254
67
  }
255
68
 
256
- if (clientServices.DevicesService) {
257
- clientServices.DevicesService.queryDevices().subscribe((dqr) => {
258
- if (!dqr || !dqr.devices || dqr.devices.length === 0) {
259
- log('empty response from device service', { device: dqr });
260
- return;
261
- }
69
+ const initializedExtensions: Extension[] = [];
262
70
 
263
- invariant(dqr, 'empty response from device service');
264
- const thisDevice = dqr.devices.find((device) => device.kind === DeviceKind.CURRENT);
265
- if (!thisDevice) {
266
- log('no current device', { device: dqr });
267
- return;
71
+ return Effect.gen(this, function* () {
72
+ for (const extension of this._extensions) {
73
+ if (extension.initialize) {
74
+ yield* extension.initialize();
268
75
  }
269
-
270
- this.setTag('deviceKey', thisDevice.deviceKey.truncate());
271
- if (thisDevice.profile?.label) {
272
- this.setTag('deviceProfile', thisDevice.profile.label);
273
- }
274
- });
275
- }
276
- }
277
-
278
- setIPDataTelemetryTags = (ipData: IPData) => {
279
- this.setTag('city', ipData.city, 'telemetry');
280
- this.setTag('region', ipData.region, 'telemetry');
281
- this.setTag('country', ipData.country, 'telemetry');
282
- ipData.latitude && this.setTag('latitude', ipData.latitude.toString(), 'telemetry');
283
- ipData.longitude && this.setTag('longitude', ipData.longitude.toString(), 'telemetry');
284
- };
285
-
286
- //
287
- // Logs
288
- //
289
-
290
- private async _initLogs(): Promise<void> {
291
- if (this._secrets.OTEL_ENDPOINT && this._secrets.OTEL_AUTHORIZATION && this._mode !== 'disabled') {
292
- const { OtelLogs } = await import('./otel');
293
- this._otelLogs = new OtelLogs({
294
- endpoint: this._secrets.OTEL_ENDPOINT,
295
- authorizationHeader: this._secrets.OTEL_AUTHORIZATION,
296
- serviceName: this._namespace,
297
- serviceVersion: this.getTag('release')?.value ?? '0.0.0',
298
- getTags: () =>
299
- Object.fromEntries(
300
- Array.from(this._tags)
301
- .filter(([key, value]) => {
302
- return value.scope === 'all' || value.scope === 'errors';
303
- })
304
- .map(([key, value]) => [key, value.value]),
305
- ),
306
- logLevel: LogLevel.VERBOSE,
307
- includeSharedWorkerLogs: false,
308
- });
309
- this._otelLogs && log.runtimeConfig.processors.push(this._otelLogs.logProcessor);
310
- log('otel logs enabled', { namespace: this._namespace });
311
- } else {
312
- log('otel logs disabled');
313
- }
314
- }
315
-
316
- //
317
- // Metrics
318
- //
319
-
320
- private async _initMetrics(): Promise<void> {
321
- if (this.enabled && this._secrets.OTEL_ENDPOINT && this._secrets.OTEL_AUTHORIZATION) {
322
- const { OtelMetrics } = await import('./otel');
323
- this._otelMetrics = new OtelMetrics({
324
- endpoint: this._secrets.OTEL_ENDPOINT,
325
- authorizationHeader: this._secrets.OTEL_AUTHORIZATION,
326
- serviceName: this._namespace,
327
- serviceVersion: this.getTag('release')?.value ?? '0.0.0',
328
- getTags: () =>
329
- Object.fromEntries(
330
- Array.from(this._tags)
331
- .filter(([key, value]) => {
332
- return value.scope === 'all' || value.scope === 'metrics';
333
- })
334
- .map(([key, value]) => [key, value.value]),
335
- ),
336
- });
337
- log('otel metrics enabled');
338
- } else {
339
- log('otel metrics disabled');
340
- }
341
- }
342
-
343
- /**
344
- * Gauge metric.
345
- *
346
- * The default implementation uses OpenTelemetry
347
- */
348
- gauge(name: string, value: number | any, extraTags?: any): void {
349
- this._otelMetrics?.gauge(name, value, extraTags);
350
- }
351
-
352
- // TODO(nf): Refactor into ObservabilityExtensions.
353
-
354
- startNetworkMetrics(clientServices: Partial<ClientServices>): void {
355
- if (!clientServices.NetworkService) {
356
- return;
357
- }
358
- // TODO(nf): support type in debounce()
359
- const updateSignalMetrics = new Event<NetworkStatus>().debounce(NETWORK_METRICS_MIN_INTERVAL);
360
- updateSignalMetrics.on(this._ctx, async () => {
361
- log('send signal metrics');
362
- (this._lastNetworkStatus?.signaling as NetworkStatus.Signal[])?.forEach(({ server, state }) => {
363
- this.gauge('dxos.client.network.signal.connectionState', state, { server });
364
- });
365
-
366
- let swarmCount = 0;
367
- const connectionStates = new Map<string, number>();
368
- for (const state in ConnectionState) {
369
- connectionStates.set(state, 0);
76
+ initializedExtensions.push(extension);
370
77
  }
371
78
 
372
- let totalReadBufferSize = 0;
373
- let totalWriteBufferSize = 0;
374
- let totalChannelBufferSize = 0;
375
-
376
- this._lastNetworkStatus?.connectionInfo?.forEach((connectionInfo) => {
377
- swarmCount++;
378
-
379
- for (const conn of connectionInfo.connections ?? []) {
380
- connectionStates.set(conn.state, (connectionStates.get(conn.state) ?? 0) + 1);
381
- totalReadBufferSize += conn.readBufferSize ?? 0;
382
- totalWriteBufferSize += conn.writeBufferSize ?? 0;
383
- for (const stream of conn.streams ?? []) {
384
- totalChannelBufferSize += stream.writeBufferSize ?? 0;
79
+ const cleanups = yield* Effect.all(this._dataProviders.map((provider) => provider(this)));
80
+ this._subscriptions.add(...cleanups.filter((cleanup) => cleanup !== undefined));
81
+ this._initialized = true;
82
+ }).pipe(
83
+ Effect.catchAll((error) =>
84
+ Effect.gen(this, function* () {
85
+ log.catch(error);
86
+ // Roll back already-initialized extensions.
87
+ for (const extension of initializedExtensions) {
88
+ if (extension.close) {
89
+ yield* extension.close().pipe(Effect.catchAll(() => Effect.succeed(undefined)));
90
+ }
385
91
  }
386
- }
92
+ this._subscriptions.clear();
93
+ }),
94
+ ),
95
+ );
96
+ }
387
97
 
388
- this.gauge('dxos.client.network.swarm.count', swarmCount);
389
- for (const state in ConnectionState) {
390
- this.gauge('dxos.client.network.connection.count', connectionStates.get(state) ?? 0, { state });
98
+ close(): Effect.Effect<void> {
99
+ return Effect.gen(this, function* () {
100
+ this._subscriptions.clear();
101
+ this._dataProviders.length = 0;
102
+ for (const extension of this._extensions) {
103
+ if (extension.close) {
104
+ yield* extension.close();
391
105
  }
392
- this.gauge('dxos.client.network.totalReadBufferSize', totalReadBufferSize);
393
- this.gauge('dxos.client.network.totalWriteBufferSize', totalWriteBufferSize);
394
- this.gauge('dxos.client.network.totalChannelBufferSize', totalChannelBufferSize);
395
- });
106
+ }
107
+ this._initialized = false;
396
108
  });
109
+ }
397
110
 
398
- clientServices.NetworkService.queryStatus().subscribe((networkStatus) => {
399
- this._lastNetworkStatus = networkStatus;
400
- updateSignalMetrics.emit();
111
+ enable(): Effect.Effect<void> {
112
+ return Effect.gen(this, function* () {
113
+ for (const extension of this._extensions) {
114
+ if (extension.enable) {
115
+ yield* extension.enable();
116
+ }
117
+ }
401
118
  });
402
-
403
- scheduleTaskInterval(this._ctx, async () => updateSignalMetrics.emit(), NETWORK_METRICS_MIN_INTERVAL);
404
119
  }
405
120
 
406
- startSpacesMetrics(client: Client, namespace: string): void {
407
- // TODO(nf): update subscription on new spaces
408
- const spaces = client.spaces.get();
409
- const subscriptions = new Map<string, { unsubscribe: () => void }>();
410
- this._ctx.onDispose(() => subscriptions.forEach((subscription) => subscription.unsubscribe()));
411
-
412
- const updateSpaceMetrics = new Event<Space>().debounce(SPACE_METRICS_MIN_INTERVAL);
413
- updateSpaceMetrics.on(this._ctx, async () => {
414
- log('send space metrics');
415
- for (const data of mapSpaces(spaces, { truncateKeys: true })) {
416
- this.gauge('dxos.client.space.members', data.members, { key: data.key });
417
- this.gauge('dxos.client.space.objects', data.objects, { key: data.key });
418
- this.gauge('dxos.client.space.epoch', data.epoch, { key: data.key });
419
- this.gauge('dxos.client.space.currentDataMutations', data.currentDataMutations, { key: data.key });
121
+ disable(): Effect.Effect<void> {
122
+ return Effect.gen(this, function* () {
123
+ for (const extension of this._extensions) {
124
+ if (extension.disable) {
125
+ yield* extension.disable();
126
+ }
420
127
  }
421
128
  });
129
+ }
422
130
 
423
- const updateSpaceTelemetry = new Event<Space>().debounce(SPACE_TELEMETRY_MIN_INTERVAL);
424
- updateSpaceTelemetry.on(this._ctx, async () => {
425
- log('send space telemetry');
426
- for (const data of mapSpaces(spaces, { truncateKeys: true })) {
427
- this.track({
428
- ...getTelemetryIdentity(client),
429
- event: TelemetryEvent.METRICS,
430
- action: 'space.update',
431
- properties: data,
432
- });
131
+ flush(): Effect.Effect<void> {
132
+ return Effect.gen(this, function* () {
133
+ for (const extension of this._extensions) {
134
+ if (extension.flush) {
135
+ yield* extension.flush();
136
+ }
433
137
  }
434
138
  });
139
+ }
435
140
 
436
- const subscribeToSpaceUpdate = (space: Space) =>
437
- space.pipeline.subscribe({
438
- next: () => {
439
- updateSpaceMetrics.emit();
440
- updateSpaceTelemetry.emit();
441
- },
442
- });
141
+ _addExtension(extension: Extension): void {
142
+ invariant(!this._initialized, 'Observability is already initialized');
143
+ this._extensions.push(extension);
144
+ }
443
145
 
444
- spaces.forEach((space) => {
445
- subscriptions.set(space.id, subscribeToSpaceUpdate(space));
446
- });
146
+ _addDataProvider(dataProvider: DataProvider): void {
147
+ invariant(!this._initialized, 'Observability is already initialized');
148
+ this._dataProviders.push(dataProvider);
149
+ }
447
150
 
448
- client.spaces.subscribe({
449
- next: async (spaces) => {
450
- spaces
451
- .filter((space) => !subscriptions.has(space.id))
452
- .forEach((space) => {
453
- subscriptions.set(space.id, subscribeToSpaceUpdate(space));
454
- });
455
- },
151
+ /**
152
+ * Adds a data provider and initializes it.
153
+ */
154
+ addDataProvider(dataProvider: DataProvider): Effect.Effect<void, Error> {
155
+ return Effect.gen(this, function* () {
156
+ this._dataProviders.push(dataProvider);
157
+ const cleanup = yield* dataProvider(this);
158
+ if (cleanup) {
159
+ this._subscriptions.add(cleanup);
160
+ }
456
161
  });
457
-
458
- scheduleTaskInterval(this._ctx, async () => updateSpaceMetrics.emit(), NETWORK_METRICS_MIN_INTERVAL);
459
162
  }
460
163
 
461
- async startRuntimeMetrics(client: Client, frequency: number = NETWORK_METRICS_MIN_INTERVAL): Promise<void> {
462
- const platform = await client.services.services.SystemService?.getPlatform();
463
- invariant(platform, 'platform is required');
464
-
465
- this.setTag('platformType', Platform.PLATFORM_TYPE[platform.type as number].toLowerCase());
466
- if (this._mode === 'full') {
467
- if (platform.platform) {
468
- this.setTag('platform', platform.platform);
469
- }
470
- if (platform.arch) {
471
- this.setTag('arch', platform.arch);
472
- }
473
- if (platform.runtime) {
474
- this.setTag('runtime', platform.runtime);
475
- }
164
+ identify(distinctId: string, attributes?: Attributes, setOnceAttributes?: Attributes): void {
165
+ for (const extension of this._extensions) {
166
+ extension.identify?.(distinctId, attributes, setOnceAttributes);
476
167
  }
477
-
478
- scheduleTaskInterval(
479
- this._ctx,
480
- async () => {
481
- if (client.services.constructor.name === 'WorkerClientServices') {
482
- const memory = (window.performance as any).memory;
483
- if (memory) {
484
- this.gauge('dxos.client.runtime.heapTotal', memory.totalJSHeapSize);
485
- this.gauge('dxos.client.runtime.heapUsed', memory.usedJSHeapSize);
486
- this.gauge('dxos.client.runtime.heapSizeLimit', memory.jsHeapSizeLimit);
487
- }
488
- }
489
- client.services.services.SystemService?.getPlatform()
490
- .then((platform) => {
491
- if (platform.memory) {
492
- this.gauge('dxos.client.services.runtime.rss', platform.memory.rss);
493
- this.gauge('dxos.client.services.runtime.heapTotal', platform.memory.heapTotal);
494
- this.gauge('dxos.client.services.runtime.heapUsed', platform.memory.heapUsed);
495
- }
496
- })
497
- .catch((error) => log('platform error', { error }));
498
- },
499
- frequency,
500
- );
501
168
  }
502
169
 
503
- //
504
- // Telemetry
505
- //
506
-
507
- private async _initTelemetry(): Promise<void> {
508
- if (this._secrets.TELEMETRY_API_KEY && this._mode !== 'disabled' && typeof document !== 'undefined') {
509
- const { SegmentTelemetry } = await import('./segment');
510
- this._telemetry = new SegmentTelemetry({
511
- apiKey: this._secrets.TELEMETRY_API_KEY,
512
- batchSize: this._telemetryBatchSize,
513
- getTags: () =>
514
- Object.fromEntries(
515
- Array.from(this._tags)
516
- .filter(([key, value]) => {
517
- return value.scope === 'all' || value.scope === 'telemetry';
518
- })
519
- .map(([key, value]) => [key, value.value]),
520
- ),
521
- });
522
- } else {
523
- log('segment disabled');
170
+ alias(distinctId: string, previousId?: string): void {
171
+ for (const extension of this._extensions) {
172
+ extension.alias?.(distinctId, previousId);
524
173
  }
525
174
  }
526
175
 
527
- /**
528
- * Submit telemetry page view.
529
- * The default implementation uses Segment.
530
- */
531
- page(options: PageOptions): void {
532
- this._telemetry?.page(options);
176
+ setTags(tags: Attributes, kind?: Kind): void {
177
+ for (const extension of this._extensions) {
178
+ if (kind && !extension.apis.some((api) => api.kind === kind)) {
179
+ continue;
180
+ }
181
+
182
+ const processedTags = Object.fromEntries(
183
+ Object.entries(tags)
184
+ .filter((entry): entry is [string, string | number | boolean] => entry[1] !== undefined)
185
+ .map(([key, value]) => [key, value.toString()]),
186
+ );
187
+ extension.setTags?.(processedTags);
188
+ }
533
189
  }
534
190
 
535
- /**
536
- * Submit telemetry user action.
537
- * The default implementation uses Segment.
538
- */
539
- track(options: TrackOptions): void {
540
- this._telemetry?.track(options);
191
+ get enabled(): boolean {
192
+ return this._extensions.every((extension) => extension.enabled);
541
193
  }
542
194
 
543
- //
544
- // Error Logs
545
- //
546
-
547
- private async _initErrorLogs(): Promise<void> {
548
- if (this._secrets.SENTRY_DESTINATION && this._mode !== 'disabled') {
549
- const { captureException, captureUserFeedback, init, setTag } = await import('./sentry');
550
- const { SentryLogProcessor } = await import('./sentry/sentry-log-processor');
551
- this._captureException = captureException;
552
- this._captureUserFeedback = captureUserFeedback;
553
- this._setTag = setTag;
554
-
555
- // TODO(nf): Refactor package into this one?
556
- log.info('Initializing Sentry', {
557
- dest: this._secrets.SENTRY_DESTINATION,
558
- options: this._errorReportingOptions,
559
- });
560
- this._sentryLogProcessor = new SentryLogProcessor();
561
- init({
562
- ...this._errorReportingOptions,
563
- destination: this._secrets.SENTRY_DESTINATION,
564
- scrubFilenames: this._mode !== 'full',
565
- onError: (event) => this._sentryLogProcessor!.addLogBreadcrumbsTo(event),
566
- });
567
-
568
- // TODO(nf): Set platform at instantiation? needed for node.
569
- // TODO(nf): Is this different than passing as properties in options?
570
- this._tags.forEach((v, k) => {
571
- if (v.scope === 'all' || v.scope === 'errors') {
572
- setTag(k, v.value);
195
+ get errors(): Errors {
196
+ return {
197
+ captureException: (error, attributes) => {
198
+ for (const extension of this._getExtensions('errors')) {
199
+ extension.captureException(error, attributes);
573
200
  }
574
- });
575
- } else {
576
- log('sentry disabled');
577
- }
201
+ },
202
+ };
578
203
  }
579
204
 
580
- startErrorLogs(): void {
581
- this._sentryLogProcessor && log.runtimeConfig.processors.push(this._sentryLogProcessor.logProcessor);
205
+ get events(): Events {
206
+ return {
207
+ captureEvent: (event, attributes) => {
208
+ for (const extension of this._getExtensions('events')) {
209
+ extension.captureEvent(event, attributes);
210
+ }
211
+ },
212
+ };
582
213
  }
583
214
 
584
- startTraces(): void {
585
- this._otelTraces && this._otelTraces.start();
215
+ get feedback(): Feedback {
216
+ return {
217
+ captureUserFeedback: (form) => {
218
+ for (const extension of this._getExtensions('feedback')) {
219
+ extension.captureUserFeedback(form);
220
+ }
221
+ },
222
+ };
586
223
  }
587
224
 
588
- // TODO(nf): Refactor init based on providers and their capabilities.
589
- private async _initTraces(): Promise<void> {
590
- if (this._secrets.OTEL_ENDPOINT && this._secrets.OTEL_AUTHORIZATION && this._mode !== 'disabled') {
591
- const { OtelTraces } = await import('./otel');
592
- this._otelTraces = new OtelTraces({
593
- endpoint: this._secrets.OTEL_ENDPOINT,
594
- authorizationHeader: this._secrets.OTEL_AUTHORIZATION,
595
- serviceName: this._namespace,
596
- serviceVersion: this.getTag('release')?.value ?? '0.0.0',
597
- getTags: () =>
598
- Object.fromEntries(
599
- Array.from(this._tags)
600
- .filter(([key, value]) => {
601
- return value.scope === 'all' || value.scope === 'metrics';
602
- })
603
- .map(([key, value]) => [key, value.value]),
604
- ),
605
- });
225
+ isAvailable(kind: Kind): Effect.Effect<boolean> {
226
+ const apis = this._getExtensions(kind);
227
+ if (apis.length === 0) {
228
+ return Effect.succeed(false);
606
229
  }
230
+ return Effect.gen(this, function* () {
231
+ for (const api of apis) {
232
+ const available = yield* api.isAvailable();
233
+ if (available) {
234
+ return true;
235
+ }
236
+ }
237
+ return false;
238
+ });
607
239
  }
608
240
 
609
- /**
610
- * Manually capture an exception.
611
- * The default implementation uses Sentry.
612
- */
613
- captureException(err: any): void {
614
- if (this.enabled) {
615
- this._captureException?.(err);
616
- }
241
+ get metrics(): Metrics {
242
+ return {
243
+ gauge: (name, value, attributes) => {
244
+ for (const extension of this._getExtensions('metrics')) {
245
+ extension.gauge(name, value, attributes);
246
+ }
247
+ },
248
+ increment: (name, value, attributes) => {
249
+ for (const extension of this._getExtensions('metrics')) {
250
+ extension.increment(name, value, attributes);
251
+ }
252
+ },
253
+ distribution: (name, value, attributes) => {
254
+ for (const extension of this._getExtensions('metrics')) {
255
+ extension.distribution(name, value, attributes);
256
+ }
257
+ },
258
+ };
617
259
  }
618
260
 
619
- /**
620
- * Manually capture user feedback.
621
- * The default implementation uses Sentry.
622
- */
623
- captureUserFeedback(message: string): void {
624
- if (!this._secrets.SENTRY_DESTINATION) {
625
- log.info('Feedback submitted without Sentry destination', { message });
626
- return;
627
- }
628
-
629
- // TODO(Zan): Should this respect telemetry mode? Sending feedback is explicitly user-initiated.
630
- // - Maybe if telemetry is disable we shouldn't enable replay.
631
- // - (Check the browser.ts implementation for reference).
632
- void this._captureUserFeedback?.(message);
261
+ private _getExtensions<T extends Kind>(kind: T): Extract<ExtensionApi, { kind: T }>[] {
262
+ return Function.pipe(
263
+ this._extensions,
264
+ Array.flatMap((extension) => extension.apis),
265
+ Array.filter((api): api is Extract<ExtensionApi, { kind: T }> => api.kind === kind),
266
+ );
633
267
  }
634
268
  }
269
+
270
+ export const make = (): Effect.Effect<Observability> => Effect.succeed(new ObservabilityImpl());
271
+
272
+ export const addExtension = (_extension: Effect.Effect<Extension>) =>
273
+ Effect.fn(function* (_observability: Effect.Effect<Observability>) {
274
+ const observability = yield* _observability;
275
+ const extension = yield* _extension;
276
+ invariant('_addExtension' in observability && typeof observability._addExtension === 'function');
277
+ observability._addExtension(extension);
278
+ return observability;
279
+ });
280
+
281
+ export const addDataProvider = (dataProvider: DataProvider) =>
282
+ Effect.fn(function* (_observability: Effect.Effect<Observability>) {
283
+ const observability = yield* _observability;
284
+ invariant('_addDataProvider' in observability && typeof observability._addDataProvider === 'function');
285
+ observability._addDataProvider(dataProvider);
286
+ return observability;
287
+ });
288
+
289
+ export const initialize = Effect.fn(function* (_observability: Effect.Effect<Observability>) {
290
+ const observability = yield* _observability;
291
+ yield* observability.initialize();
292
+ return observability;
293
+ });