@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.
- package/dist/lib/browser/chunk-J5LGTIGS.mjs +10 -0
- package/dist/lib/browser/chunk-K4VFBKST.mjs +13 -0
- package/dist/lib/browser/chunk-K4VFBKST.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +1066 -34
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/log-processor-FDLTDQEM.mjs +45 -0
- package/dist/lib/browser/log-processor-FDLTDQEM.mjs.map +7 -0
- package/dist/lib/browser/logs-ATTRIUTL.mjs +113 -0
- package/dist/lib/browser/logs-ATTRIUTL.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/metrics-PKTV6IGF.mjs +130 -0
- package/dist/lib/browser/metrics-PKTV6IGF.mjs.map +7 -0
- package/dist/lib/browser/traces-browser-XYXBF5ZX.mjs +62 -0
- package/dist/lib/browser/traces-browser-XYXBF5ZX.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-FEVP3MK4.mjs +15 -0
- package/dist/lib/node-esm/chunk-FEVP3MK4.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
- package/dist/lib/node-esm/index.mjs +1070 -34
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/log-processor-TKJVJJSJ.mjs +46 -0
- package/dist/lib/node-esm/log-processor-TKJVJJSJ.mjs.map +7 -0
- package/dist/lib/node-esm/logs-7J45KLM7.mjs +114 -0
- package/dist/lib/node-esm/logs-7J45KLM7.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/metrics-H7DDLYSG.mjs +131 -0
- package/dist/lib/node-esm/metrics-H7DDLYSG.mjs.map +7 -0
- package/dist/lib/node-esm/traces-KMTHMYFX.mjs +44 -0
- package/dist/lib/node-esm/traces-KMTHMYFX.mjs.map +7 -0
- package/dist/types/src/cli-observability-secrets.json +3 -4
- package/dist/types/src/extensions/index.d.ts +3 -0
- package/dist/types/src/extensions/index.d.ts.map +1 -0
- package/dist/types/src/extensions/index.js +6 -0
- package/dist/types/src/extensions/index.js.map +1 -0
- package/dist/types/src/extensions/otel/extension.d.ts +23 -0
- package/dist/types/src/extensions/otel/extension.d.ts.map +1 -0
- package/dist/types/src/extensions/otel/extension.js +124 -0
- package/dist/types/src/extensions/otel/extension.js.map +1 -0
- package/dist/types/src/extensions/otel/index.d.ts +2 -0
- package/dist/types/src/extensions/otel/index.d.ts.map +1 -0
- package/dist/types/src/extensions/otel/index.js +5 -0
- package/dist/types/src/extensions/otel/index.js.map +1 -0
- package/dist/types/src/{otel → extensions/otel}/logs.d.ts +4 -3
- package/dist/types/src/extensions/otel/logs.d.ts.map +1 -0
- package/dist/types/src/extensions/otel/logs.js +104 -0
- package/dist/types/src/extensions/otel/logs.js.map +1 -0
- package/dist/types/src/{otel → extensions/otel}/metrics.d.ts +0 -1
- package/dist/types/src/extensions/otel/metrics.d.ts.map +1 -0
- package/dist/types/src/{otel → extensions/otel}/metrics.js +6 -12
- package/dist/types/src/extensions/otel/metrics.js.map +1 -0
- package/dist/types/src/{otel → extensions/otel}/otel.d.ts +3 -3
- package/dist/types/src/extensions/otel/otel.d.ts.map +1 -0
- package/dist/types/src/{otel → extensions/otel}/otel.js +1 -1
- package/dist/types/src/extensions/otel/otel.js.map +1 -0
- package/dist/types/src/extensions/otel/traces-browser.d.ts.map +1 -0
- package/dist/types/src/extensions/otel/traces-browser.js +44 -0
- package/dist/types/src/extensions/otel/traces-browser.js.map +1 -0
- package/dist/types/src/extensions/otel/traces.d.ts.map +1 -0
- package/dist/types/src/extensions/otel/traces.js +38 -0
- package/dist/types/src/extensions/otel/traces.js.map +1 -0
- package/dist/types/src/extensions/posthog/extension.d.ts +15 -0
- package/dist/types/src/extensions/posthog/extension.d.ts.map +1 -0
- package/dist/types/src/extensions/posthog/extension.js +143 -0
- package/dist/types/src/extensions/posthog/extension.js.map +1 -0
- package/dist/types/src/extensions/posthog/index.d.ts +2 -0
- package/dist/types/src/extensions/posthog/index.d.ts.map +1 -0
- package/dist/types/src/extensions/posthog/index.js +5 -0
- package/dist/types/src/extensions/posthog/index.js.map +1 -0
- package/dist/types/src/extensions/posthog/log-processor.d.ts +3 -0
- package/dist/types/src/extensions/posthog/log-processor.d.ts.map +1 -0
- package/dist/types/src/extensions/posthog/log-processor.js +45 -0
- package/dist/types/src/extensions/posthog/log-processor.js.map +1 -0
- package/dist/types/src/extensions/posthog/log-processor.test.d.ts +2 -0
- package/dist/types/src/extensions/posthog/log-processor.test.d.ts.map +1 -0
- package/dist/types/src/extensions/posthog/log-processor.test.js +146 -0
- package/dist/types/src/extensions/posthog/log-processor.test.js.map +1 -0
- package/dist/types/src/extensions/stub.d.ts +3 -0
- package/dist/types/src/extensions/stub.d.ts.map +1 -0
- package/dist/types/src/extensions/stub.js +16 -0
- package/dist/types/src/extensions/stub.js.map +1 -0
- package/dist/types/src/index.d.ts +4 -2
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/index.js +5 -3
- package/dist/types/src/index.js.map +1 -1
- package/dist/types/src/log-buffer.d.ts +34 -0
- package/dist/types/src/log-buffer.d.ts.map +1 -0
- package/dist/types/src/log-buffer.js +70 -0
- package/dist/types/src/log-buffer.js.map +1 -0
- package/dist/types/src/log-buffer.test.d.ts +2 -0
- package/dist/types/src/log-buffer.test.d.ts.map +1 -0
- package/dist/types/src/log-buffer.test.js +107 -0
- package/dist/types/src/log-buffer.test.js.map +1 -0
- package/dist/types/src/observability-extension.d.ts +74 -0
- package/dist/types/src/observability-extension.d.ts.map +1 -0
- package/dist/types/src/observability-extension.js +5 -0
- package/dist/types/src/observability-extension.js.map +1 -0
- package/dist/types/src/observability.d.ts +32 -110
- package/dist/types/src/observability.d.ts.map +1 -1
- package/dist/types/src/observability.js +176 -455
- package/dist/types/src/observability.js.map +1 -1
- package/dist/types/src/observability.test.d.ts +2 -0
- package/dist/types/src/observability.test.d.ts.map +1 -0
- package/dist/types/src/observability.test.js +312 -0
- package/dist/types/src/observability.test.js.map +1 -0
- package/dist/types/src/providers/client-observability.d.ts +11 -0
- package/dist/types/src/providers/client-observability.d.ts.map +1 -0
- package/dist/types/src/providers/client-observability.js +200 -0
- package/dist/types/src/providers/client-observability.js.map +1 -0
- package/dist/types/src/providers/index.d.ts +4 -0
- package/dist/types/src/providers/index.d.ts.map +1 -0
- package/dist/types/src/providers/index.js +7 -0
- package/dist/types/src/providers/index.js.map +1 -0
- package/dist/types/src/providers/ip-data.d.ts +5 -0
- package/dist/types/src/providers/ip-data.d.ts.map +1 -0
- package/dist/types/src/providers/ip-data.js +55 -0
- package/dist/types/src/providers/ip-data.js.map +1 -0
- package/dist/types/src/providers/storage.d.ts +3 -0
- package/dist/types/src/providers/storage.d.ts.map +1 -0
- package/dist/types/src/providers/storage.js +19 -0
- package/dist/types/src/providers/storage.js.map +1 -0
- package/dist/types/src/storage/browser.d.ts +19 -0
- package/dist/types/src/storage/browser.d.ts.map +1 -0
- package/dist/types/src/storage/browser.js +58 -0
- package/dist/types/src/storage/browser.js.map +1 -0
- package/dist/types/src/storage/index.d.ts +2 -0
- package/dist/types/src/storage/index.d.ts.map +1 -0
- package/{src/segment/index.ts → dist/types/src/storage/index.js} +1 -2
- package/dist/types/src/storage/index.js.map +1 -0
- package/dist/types/src/storage/node.d.ts +26 -0
- package/dist/types/src/storage/node.d.ts.map +1 -0
- package/dist/types/src/storage/node.js +92 -0
- package/dist/types/src/storage/node.js.map +1 -0
- package/dist/types/src/storage/node.test.d.ts +2 -0
- package/dist/types/src/storage/node.test.d.ts.map +1 -0
- package/dist/types/src/storage/node.test.js +103 -0
- package/dist/types/src/storage/node.test.js.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +42 -63
- package/src/cli-observability-secrets.json +3 -4
- package/src/extensions/index.ts +6 -0
- package/src/extensions/otel/extension.ts +178 -0
- package/src/extensions/otel/index.ts +5 -0
- package/src/extensions/otel/logs.ts +134 -0
- package/src/{otel → extensions/otel}/metrics.ts +4 -21
- package/src/{otel → extensions/otel}/otel.ts +4 -4
- package/src/extensions/otel/traces-browser.ts +57 -0
- package/src/extensions/otel/traces.ts +49 -0
- package/src/extensions/posthog/extension.ts +172 -0
- package/src/extensions/posthog/index.ts +5 -0
- package/src/extensions/posthog/log-processor.test.ts +185 -0
- package/src/extensions/posthog/log-processor.ts +54 -0
- package/src/extensions/stub.ts +19 -0
- package/src/index.ts +5 -3
- package/src/log-buffer.test.ts +134 -0
- package/src/log-buffer.ts +101 -0
- package/src/observability-extension.ts +94 -0
- package/src/observability.test.ts +531 -0
- package/src/observability.ts +236 -577
- package/src/providers/client-observability.ts +253 -0
- package/src/providers/index.ts +7 -0
- package/src/providers/ip-data.ts +88 -0
- package/src/providers/storage.ts +23 -0
- package/src/storage/browser.ts +61 -0
- package/src/{sentry → storage}/index.ts +0 -1
- package/src/storage/node.test.ts +130 -0
- package/src/{helpers/node-observability.ts → storage/node.ts} +42 -70
- package/dist/lib/browser/chunk-G6EE7HFV.mjs +0 -147
- package/dist/lib/browser/chunk-G6EE7HFV.mjs.map +0 -7
- package/dist/lib/browser/chunk-JA5VJRKF.mjs +0 -164
- package/dist/lib/browser/chunk-JA5VJRKF.mjs.map +0 -7
- package/dist/lib/browser/chunk-KDP3SESE.mjs +0 -1
- package/dist/lib/browser/chunk-YQJELTRP.mjs +0 -996
- package/dist/lib/browser/chunk-YQJELTRP.mjs.map +0 -7
- package/dist/lib/browser/observability-HDE3I7TA.mjs +0 -10
- package/dist/lib/browser/otel-LHAFLNBQ.mjs +0 -277
- package/dist/lib/browser/otel-LHAFLNBQ.mjs.map +0 -7
- package/dist/lib/browser/segment/index.mjs +0 -11
- package/dist/lib/browser/segment/index.mjs.map +0 -7
- package/dist/lib/browser/sentry/index.mjs +0 -24
- package/dist/lib/browser/sentry/index.mjs.map +0 -7
- package/dist/lib/browser/sentry-log-processor-625AISXI.mjs +0 -146
- package/dist/lib/browser/sentry-log-processor-625AISXI.mjs.map +0 -7
- package/dist/lib/node/chunk-325GAGFA.cjs +0 -213
- package/dist/lib/node/chunk-325GAGFA.cjs.map +0 -7
- package/dist/lib/node/chunk-BZHVFSLF.cjs +0 -1025
- package/dist/lib/node/chunk-BZHVFSLF.cjs.map +0 -7
- package/dist/lib/node/chunk-GIYJMZEQ.cjs +0 -2
- package/dist/lib/node/chunk-GIYJMZEQ.cjs.map +0 -7
- package/dist/lib/node/chunk-MZ3PMDTP.cjs +0 -163
- package/dist/lib/node/chunk-MZ3PMDTP.cjs.map +0 -7
- package/dist/lib/node/index.cjs +0 -60
- package/dist/lib/node/index.cjs.map +0 -7
- package/dist/lib/node/meta.json +0 -1
- package/dist/lib/node/observability-E2NGRIEN.cjs +0 -32
- package/dist/lib/node/observability-E2NGRIEN.cjs.map +0 -7
- package/dist/lib/node/otel-VF5YNCR3.cjs +0 -278
- package/dist/lib/node/otel-VF5YNCR3.cjs.map +0 -7
- package/dist/lib/node/segment/index.cjs +0 -33
- package/dist/lib/node/segment/index.cjs.map +0 -7
- package/dist/lib/node/sentry/index.cjs +0 -46
- package/dist/lib/node/sentry/index.cjs.map +0 -7
- package/dist/lib/node/sentry-log-processor-CCV4RL7N.cjs +0 -164
- package/dist/lib/node/sentry-log-processor-CCV4RL7N.cjs.map +0 -7
- package/dist/lib/node-esm/chunk-AZMSBUWR.mjs +0 -202
- package/dist/lib/node-esm/chunk-AZMSBUWR.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-H7Y2DDUN.mjs +0 -135
- package/dist/lib/node-esm/chunk-H7Y2DDUN.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-M7QJLFGR.mjs +0 -997
- package/dist/lib/node-esm/chunk-M7QJLFGR.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-YJ4KVBWC.mjs +0 -2
- package/dist/lib/node-esm/chunk-YJ4KVBWC.mjs.map +0 -7
- package/dist/lib/node-esm/observability-7BTI46NM.mjs +0 -11
- package/dist/lib/node-esm/observability-7BTI46NM.mjs.map +0 -7
- package/dist/lib/node-esm/otel-AF5TSABC.mjs +0 -260
- package/dist/lib/node-esm/otel-AF5TSABC.mjs.map +0 -7
- package/dist/lib/node-esm/segment/index.mjs +0 -12
- package/dist/lib/node-esm/segment/index.mjs.map +0 -7
- package/dist/lib/node-esm/sentry/index.mjs +0 -25
- package/dist/lib/node-esm/sentry/index.mjs.map +0 -7
- package/dist/lib/node-esm/sentry-log-processor-HPUPCMRG.mjs +0 -147
- package/dist/lib/node-esm/sentry-log-processor-HPUPCMRG.mjs.map +0 -7
- package/dist/types/src/helpers/browser-observability.d.ts +0 -17
- package/dist/types/src/helpers/browser-observability.d.ts.map +0 -1
- package/dist/types/src/helpers/browser-observability.js +0 -140
- package/dist/types/src/helpers/browser-observability.js.map +0 -1
- package/dist/types/src/helpers/common.d.ts +0 -12
- package/dist/types/src/helpers/common.d.ts.map +0 -1
- package/dist/types/src/helpers/common.js +0 -23
- package/dist/types/src/helpers/common.js.map +0 -1
- package/dist/types/src/helpers/index.d.ts +0 -6
- package/dist/types/src/helpers/index.d.ts.map +0 -1
- package/dist/types/src/helpers/index.js +0 -9
- package/dist/types/src/helpers/index.js.map +0 -1
- package/dist/types/src/helpers/map-spaces.d.ts +0 -18
- package/dist/types/src/helpers/map-spaces.d.ts.map +0 -1
- package/dist/types/src/helpers/map-spaces.js +0 -37
- package/dist/types/src/helpers/map-spaces.js.map +0 -1
- package/dist/types/src/helpers/node-observability.d.ts +0 -24
- package/dist/types/src/helpers/node-observability.d.ts.map +0 -1
- package/dist/types/src/helpers/node-observability.js +0 -101
- package/dist/types/src/helpers/node-observability.js.map +0 -1
- package/dist/types/src/helpers/setup-telemetry-listeners.d.ts +0 -4
- package/dist/types/src/helpers/setup-telemetry-listeners.d.ts.map +0 -1
- package/dist/types/src/helpers/setup-telemetry-listeners.js +0 -97
- package/dist/types/src/helpers/setup-telemetry-listeners.js.map +0 -1
- package/dist/types/src/otel/index.d.ts +0 -5
- package/dist/types/src/otel/index.d.ts.map +0 -1
- package/dist/types/src/otel/index.js +0 -8
- package/dist/types/src/otel/index.js.map +0 -1
- package/dist/types/src/otel/logs.d.ts.map +0 -1
- package/dist/types/src/otel/logs.js +0 -71
- package/dist/types/src/otel/logs.js.map +0 -1
- package/dist/types/src/otel/metrics.d.ts.map +0 -1
- package/dist/types/src/otel/metrics.js.map +0 -1
- package/dist/types/src/otel/otel.d.ts.map +0 -1
- package/dist/types/src/otel/otel.js.map +0 -1
- package/dist/types/src/otel/traces-browser.d.ts.map +0 -1
- package/dist/types/src/otel/traces-browser.js +0 -47
- package/dist/types/src/otel/traces-browser.js.map +0 -1
- package/dist/types/src/otel/traces.d.ts.map +0 -1
- package/dist/types/src/otel/traces.js +0 -40
- package/dist/types/src/otel/traces.js.map +0 -1
- package/dist/types/src/segment/base.d.ts +0 -15
- package/dist/types/src/segment/base.d.ts.map +0 -1
- package/dist/types/src/segment/base.js +0 -50
- package/dist/types/src/segment/base.js.map +0 -1
- package/dist/types/src/segment/browser.d.ts +0 -15
- package/dist/types/src/segment/browser.d.ts.map +0 -1
- package/dist/types/src/segment/browser.js +0 -67
- package/dist/types/src/segment/browser.js.map +0 -1
- package/dist/types/src/segment/index.d.ts +0 -3
- package/dist/types/src/segment/index.d.ts.map +0 -1
- package/dist/types/src/segment/index.js +0 -6
- package/dist/types/src/segment/index.js.map +0 -1
- package/dist/types/src/segment/node.d.ts +0 -16
- package/dist/types/src/segment/node.d.ts.map +0 -1
- package/dist/types/src/segment/node.js +0 -83
- package/dist/types/src/segment/node.js.map +0 -1
- package/dist/types/src/segment/types.d.ts +0 -52
- package/dist/types/src/segment/types.d.ts.map +0 -1
- package/dist/types/src/segment/types.js +0 -18
- package/dist/types/src/segment/types.js.map +0 -1
- package/dist/types/src/sentry/browser.d.ts +0 -32
- package/dist/types/src/sentry/browser.d.ts.map +0 -1
- package/dist/types/src/sentry/browser.js +0 -112
- package/dist/types/src/sentry/browser.js.map +0 -1
- package/dist/types/src/sentry/index.d.ts +0 -3
- package/dist/types/src/sentry/index.d.ts.map +0 -1
- package/dist/types/src/sentry/index.js +0 -6
- package/dist/types/src/sentry/index.js.map +0 -1
- package/dist/types/src/sentry/node.d.ts +0 -32
- package/dist/types/src/sentry/node.d.ts.map +0 -1
- package/dist/types/src/sentry/node.js +0 -111
- package/dist/types/src/sentry/node.js.map +0 -1
- package/dist/types/src/sentry/node.node.test.d.ts +0 -2
- package/dist/types/src/sentry/node.node.test.d.ts.map +0 -1
- package/dist/types/src/sentry/node.node.test.js +0 -34
- package/dist/types/src/sentry/node.node.test.js.map +0 -1
- package/dist/types/src/sentry/sentry-log-processor.d.ts +0 -9
- package/dist/types/src/sentry/sentry-log-processor.d.ts.map +0 -1
- package/dist/types/src/sentry/sentry-log-processor.js +0 -149
- package/dist/types/src/sentry/sentry-log-processor.js.map +0 -1
- package/dist/types/src/sentry/sentry.node.test.d.ts +0 -2
- package/dist/types/src/sentry/sentry.node.test.d.ts.map +0 -1
- package/dist/types/src/sentry/sentry.node.test.js +0 -28
- package/dist/types/src/sentry/sentry.node.test.js.map +0 -1
- package/dist/types/src/sentry/types.d.ts +0 -18
- package/dist/types/src/sentry/types.d.ts.map +0 -1
- package/dist/types/src/sentry/types.js +0 -4
- package/dist/types/src/sentry/types.js.map +0 -1
- package/dist/types/src/testing/index.d.ts +0 -2
- package/dist/types/src/testing/index.d.ts.map +0 -1
- package/dist/types/src/testing/index.js +0 -5
- package/dist/types/src/testing/index.js.map +0 -1
- package/dist/types/src/testing/testkit/browser.d.ts +0 -2
- package/dist/types/src/testing/testkit/browser.d.ts.map +0 -1
- package/dist/types/src/testing/testkit/browser.js +0 -7
- package/dist/types/src/testing/testkit/browser.js.map +0 -1
- package/dist/types/src/testing/testkit/index.d.ts +0 -2
- package/dist/types/src/testing/testkit/index.d.ts.map +0 -1
- package/dist/types/src/testing/testkit/index.js +0 -6
- package/dist/types/src/testing/testkit/index.js.map +0 -1
- package/src/helpers/browser-observability.ts +0 -177
- package/src/helpers/common.ts +0 -38
- package/src/helpers/index.ts +0 -9
- package/src/helpers/map-spaces.ts +0 -48
- package/src/helpers/setup-telemetry-listeners.ts +0 -108
- package/src/otel/index.ts +0 -8
- package/src/otel/logs.ts +0 -100
- package/src/otel/traces-browser.ts +0 -59
- package/src/otel/traces.ts +0 -57
- package/src/segment/base.ts +0 -69
- package/src/segment/browser.ts +0 -68
- package/src/segment/node.ts +0 -94
- package/src/segment/types.ts +0 -57
- package/src/sentry/browser.ts +0 -133
- package/src/sentry/node.node.test.ts +0 -39
- package/src/sentry/node.ts +0 -126
- package/src/sentry/sentry-log-processor.ts +0 -166
- package/src/sentry/sentry.node.test.ts +0 -34
- package/src/sentry/types.ts +0 -22
- package/src/testing/index.ts +0 -5
- package/src/testing/testkit/browser.ts +0 -8
- package/src/testing/testkit/index.ts +0 -7
- package/src/testing/testkit/shims.d.ts +0 -5
- /package/dist/lib/browser/{chunk-KDP3SESE.mjs.map → chunk-J5LGTIGS.mjs.map} +0 -0
- /package/dist/lib/{browser/observability-HDE3I7TA.mjs.map → node-esm/chunk-HSLMI22Q.mjs.map} +0 -0
- /package/dist/types/src/{otel → extensions/otel}/traces-browser.d.ts +0 -0
- /package/dist/types/src/{otel → extensions/otel}/traces.d.ts +0 -0
package/src/observability.ts
CHANGED
|
@@ -1,634 +1,293 @@
|
|
|
1
1
|
//
|
|
2
|
-
// Copyright
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
|
|
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
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
|
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
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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
|
-
|
|
252
|
-
|
|
253
|
-
|
|
64
|
+
initialize(): Effect.Effect<void> {
|
|
65
|
+
if (this._initialized) {
|
|
66
|
+
return Effect.succeed(undefined);
|
|
254
67
|
}
|
|
255
68
|
|
|
256
|
-
|
|
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
|
-
|
|
264
|
-
|
|
265
|
-
if (
|
|
266
|
-
|
|
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
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
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
|
-
|
|
389
|
-
|
|
390
|
-
|
|
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
|
-
|
|
393
|
-
|
|
394
|
-
this.gauge('dxos.client.network.totalChannelBufferSize', totalChannelBufferSize);
|
|
395
|
-
});
|
|
106
|
+
}
|
|
107
|
+
this._initialized = false;
|
|
396
108
|
});
|
|
109
|
+
}
|
|
397
110
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
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
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
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
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
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
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
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
|
-
|
|
445
|
-
|
|
446
|
-
|
|
146
|
+
_addDataProvider(dataProvider: DataProvider): void {
|
|
147
|
+
invariant(!this._initialized, 'Observability is already initialized');
|
|
148
|
+
this._dataProviders.push(dataProvider);
|
|
149
|
+
}
|
|
447
150
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
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
|
-
|
|
462
|
-
const
|
|
463
|
-
|
|
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
|
-
|
|
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
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
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
|
-
|
|
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
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
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
|
-
}
|
|
576
|
-
log('sentry disabled');
|
|
577
|
-
}
|
|
201
|
+
},
|
|
202
|
+
};
|
|
578
203
|
}
|
|
579
204
|
|
|
580
|
-
|
|
581
|
-
|
|
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
|
-
|
|
585
|
-
|
|
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
|
-
|
|
589
|
-
|
|
590
|
-
if (
|
|
591
|
-
|
|
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
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
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
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
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
|
+
});
|