@dxos/observability 0.6.2 → 0.6.3-main.0308ae2

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 (67) hide show
  1. package/dist/lib/browser/{chunk-HKNRDUTP.mjs → chunk-2CXA7PYK.mjs} +187 -221
  2. package/dist/lib/browser/chunk-2CXA7PYK.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +1 -2
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/browser/observability-MXAPN7J6.mjs +7 -0
  6. package/dist/lib/browser/otel-BUKBDMAL.mjs +275 -0
  7. package/dist/lib/browser/otel-BUKBDMAL.mjs.map +7 -0
  8. package/dist/lib/browser/sentry-log-processor-DVUUOZ6G.mjs +132 -0
  9. package/dist/lib/browser/sentry-log-processor-DVUUOZ6G.mjs.map +7 -0
  10. package/dist/lib/node/{chunk-6QQAPUDU.cjs → chunk-HBLKTDQE.cjs} +190 -217
  11. package/dist/lib/node/chunk-HBLKTDQE.cjs.map +7 -0
  12. package/dist/lib/node/index.cjs +15 -16
  13. package/dist/lib/node/index.cjs.map +2 -2
  14. package/dist/lib/node/meta.json +1 -1
  15. package/dist/lib/node/{observability-7TFOBOTA.cjs → observability-4R6M4JMU.cjs} +6 -7
  16. package/dist/lib/node/observability-4R6M4JMU.cjs.map +7 -0
  17. package/dist/lib/node/otel-TSHMOAB4.cjs +276 -0
  18. package/dist/lib/node/otel-TSHMOAB4.cjs.map +7 -0
  19. package/dist/lib/node/sentry-log-processor-H6FUSKZI.cjs +150 -0
  20. package/dist/lib/node/sentry-log-processor-H6FUSKZI.cjs.map +7 -0
  21. package/dist/types/src/cli-observability-secrets.json +3 -1
  22. package/dist/types/src/helpers/browser-observability.d.ts.map +1 -1
  23. package/dist/types/src/helpers/browser-observability.js +1 -0
  24. package/dist/types/src/helpers/browser-observability.js.map +1 -1
  25. package/dist/types/src/observability.d.ts +12 -2
  26. package/dist/types/src/observability.d.ts.map +1 -1
  27. package/dist/types/src/observability.js +125 -42
  28. package/dist/types/src/observability.js.map +1 -1
  29. package/dist/types/src/otel/index.d.ts +5 -0
  30. package/dist/types/src/otel/index.d.ts.map +1 -0
  31. package/dist/types/src/otel/index.js +24 -0
  32. package/dist/types/src/otel/index.js.map +1 -0
  33. package/dist/types/src/otel/logs.d.ts +11 -0
  34. package/dist/types/src/otel/logs.d.ts.map +1 -0
  35. package/dist/types/src/otel/logs.js +72 -0
  36. package/dist/types/src/otel/logs.js.map +1 -0
  37. package/dist/types/src/otel/metrics.d.ts +14 -0
  38. package/dist/types/src/otel/metrics.d.ts.map +1 -0
  39. package/dist/types/src/otel/metrics.js +91 -0
  40. package/dist/types/src/otel/metrics.js.map +1 -0
  41. package/dist/types/src/otel/otel.d.ts +12 -0
  42. package/dist/types/src/otel/otel.d.ts.map +1 -0
  43. package/dist/types/src/otel/otel.js +15 -0
  44. package/dist/types/src/otel/otel.js.map +1 -0
  45. package/dist/types/src/otel/traces-browser.d.ts +8 -0
  46. package/dist/types/src/otel/traces-browser.d.ts.map +1 -0
  47. package/dist/types/src/otel/traces-browser.js +51 -0
  48. package/dist/types/src/otel/traces-browser.js.map +1 -0
  49. package/dist/types/src/otel/traces.d.ts +8 -0
  50. package/dist/types/src/otel/traces.d.ts.map +1 -0
  51. package/dist/types/src/otel/traces.js +44 -0
  52. package/dist/types/src/otel/traces.js.map +1 -0
  53. package/package.json +35 -20
  54. package/src/cli-observability-secrets.json +3 -1
  55. package/src/helpers/browser-observability.ts +1 -0
  56. package/src/observability.ts +141 -42
  57. package/src/otel/index.ts +8 -0
  58. package/src/otel/logs.ts +86 -0
  59. package/src/otel/metrics.ts +111 -0
  60. package/src/otel/otel.ts +21 -0
  61. package/src/otel/traces-browser.ts +59 -0
  62. package/src/otel/traces.ts +57 -0
  63. package/dist/lib/browser/chunk-HKNRDUTP.mjs.map +0 -7
  64. package/dist/lib/browser/observability-6FYBCIL6.mjs +0 -8
  65. package/dist/lib/node/chunk-6QQAPUDU.cjs.map +0 -7
  66. package/dist/lib/node/observability-7TFOBOTA.cjs.map +0 -7
  67. /package/dist/lib/browser/{observability-6FYBCIL6.mjs.map → observability-MXAPN7J6.mjs.map} +0 -0
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ //
3
+ // Copyright 2024 DXOS.org
4
+ //
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.setDiagLogger = void 0;
7
+ const api_1 = require("@opentelemetry/api");
8
+ const setDiagLogger = (level) => {
9
+ const logLevel = api_1.DiagLogLevel[level];
10
+ if (logLevel) {
11
+ api_1.diag.setLogger(new api_1.DiagConsoleLogger(), logLevel);
12
+ }
13
+ };
14
+ exports.setDiagLogger = setDiagLogger;
15
+ //# sourceMappingURL=otel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otel.js","sourceRoot":"","sources":["../../../../src/otel/otel.ts"],"names":[],"mappings":";AAAA,EAAE;AACF,0BAA0B;AAC1B,EAAE;;;AAEF,4CAA2E;AAWpE,MAAM,aAAa,GAAG,CAAC,KAAc,EAAE,EAAE;IAC9C,MAAM,QAAQ,GAAG,kBAAY,CAAC,KAAkC,CAAC,CAAC;IAClE,IAAI,QAAQ,EAAE,CAAC;QACb,UAAI,CAAC,SAAS,CAAC,IAAI,uBAAiB,EAAE,EAAE,QAAQ,CAAC,CAAC;IACpD,CAAC;AACH,CAAC,CAAC;AALW,QAAA,aAAa,iBAKxB"}
@@ -0,0 +1,8 @@
1
+ import { type OtelOptions } from './otel';
2
+ export declare class OtelTraces {
3
+ private readonly options;
4
+ private _tracer;
5
+ constructor(options: OtelOptions);
6
+ start(): void;
7
+ }
8
+ //# sourceMappingURL=traces-browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traces-browser.d.ts","sourceRoot":"","sources":["../../../../src/otel/traces-browser.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AAE1C,qBAAa,UAAU;IAET,OAAO,CAAC,QAAQ,CAAC,OAAO;IADpC,OAAO,CAAC,OAAO,CAAS;gBACK,OAAO,EAAE,WAAW;IA0B1C,KAAK;CAYb"}
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ //
3
+ // Copyright 2024 DXOS.org
4
+ //
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.OtelTraces = void 0;
7
+ const api_1 = require("@opentelemetry/api");
8
+ const auto_instrumentations_web_1 = require("@opentelemetry/auto-instrumentations-web");
9
+ const exporter_trace_otlp_http_1 = require("@opentelemetry/exporter-trace-otlp-http");
10
+ const instrumentation_1 = require("@opentelemetry/instrumentation");
11
+ const resources_1 = require("@opentelemetry/resources");
12
+ const sdk_trace_base_1 = require("@opentelemetry/sdk-trace-base");
13
+ const sdk_trace_web_1 = require("@opentelemetry/sdk-trace-web");
14
+ const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
15
+ const log_1 = require("@dxos/log");
16
+ const tracing_1 = require("@dxos/tracing");
17
+ class OtelTraces {
18
+ constructor(options) {
19
+ this.options = options;
20
+ const resource = resources_1.Resource.default().merge(new resources_1.Resource({
21
+ [semantic_conventions_1.SEMRESATTRS_SERVICE_NAME]: this.options.serviceName,
22
+ [semantic_conventions_1.SEMRESATTRS_SERVICE_VERSION]: this.options.serviceVersion,
23
+ }));
24
+ const tracerProvider = new sdk_trace_web_1.WebTracerProvider({ resource });
25
+ tracerProvider.addSpanProcessor(new sdk_trace_base_1.SimpleSpanProcessor(new sdk_trace_base_1.ConsoleSpanExporter()));
26
+ tracerProvider.addSpanProcessor(new sdk_trace_base_1.BatchSpanProcessor(new exporter_trace_otlp_http_1.OTLPTraceExporter({
27
+ url: this.options.endpoint + '/v1/traces',
28
+ headers: {
29
+ Authorization: this.options.authorizationHeader,
30
+ },
31
+ concurrencyLimit: 10, // an optional limit on pending requests
32
+ })));
33
+ // TODO(nf): ContextManager? Propogator?
34
+ tracerProvider.register({});
35
+ this._tracer = api_1.trace.getTracer('dxos-observability', this.options.serviceVersion);
36
+ }
37
+ start() {
38
+ (0, instrumentation_1.registerInstrumentations)({
39
+ instrumentations: [(0, auto_instrumentations_web_1.getWebAutoInstrumentations)()],
40
+ });
41
+ (0, log_1.log)('trace processor registered');
42
+ tracing_1.TRACE_PROCESSOR.remoteTracing.registerProcessor({
43
+ startSpan: (options) => {
44
+ (0, log_1.log)('begin otel trace', { options });
45
+ return this._tracer.startSpan(options.name, options);
46
+ },
47
+ });
48
+ }
49
+ }
50
+ exports.OtelTraces = OtelTraces;
51
+ //# sourceMappingURL=traces-browser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traces-browser.js","sourceRoot":"","sources":["../../../../src/otel/traces-browser.ts"],"names":[],"mappings":";AAAA,EAAE;AACF,0BAA0B;AAC1B,EAAE;;;AAEF,4CAAwD;AACxD,wFAAsF;AACtF,sFAA4E;AAC5E,oEAA0E;AAC1E,wDAAoD;AACpD,kEAA6G;AAC7G,gEAAiE;AACjE,8EAA4G;AAE5G,mCAAgC;AAChC,2CAAuE;AAIvE,MAAa,UAAU;IAErB,YAA6B,OAAoB;QAApB,YAAO,GAAP,OAAO,CAAa;QAC/C,MAAM,QAAQ,GAAG,oBAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,CACvC,IAAI,oBAAQ,CAAC;YACX,CAAC,+CAAwB,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW;YACpD,CAAC,kDAA2B,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,cAAc;SAC3D,CAAC,CACH,CAAC;QAEF,MAAM,cAAc,GAAG,IAAI,iCAAiB,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC3D,cAAc,CAAC,gBAAgB,CAAC,IAAI,oCAAmB,CAAC,IAAI,oCAAmB,EAAE,CAAC,CAAC,CAAC;QACpF,cAAc,CAAC,gBAAgB,CAC7B,IAAI,mCAAkB,CACpB,IAAI,4CAAiB,CAAC;YACpB,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,GAAG,YAAY;YACzC,OAAO,EAAE;gBACP,aAAa,EAAE,IAAI,CAAC,OAAO,CAAC,mBAAmB;aAChD;YACD,gBAAgB,EAAE,EAAE,EAAE,wCAAwC;SAC/D,CAAC,CACH,CACF,CAAC;QACF,wCAAwC;QACxC,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC5B,IAAI,CAAC,OAAO,GAAG,WAAK,CAAC,SAAS,CAAC,oBAAoB,EAAE,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IACpF,CAAC;IAEM,KAAK;QACV,IAAA,0CAAwB,EAAC;YACvB,gBAAgB,EAAE,CAAC,IAAA,sDAA0B,GAAE,CAAC;SACjD,CAAC,CAAC;QACH,IAAA,SAAG,EAAC,4BAA4B,CAAC,CAAC;QAClC,yBAAe,CAAC,aAAa,CAAC,iBAAiB,CAAC;YAC9C,SAAS,EAAE,CAAC,OAAyB,EAAE,EAAE;gBACvC,IAAA,SAAG,EAAC,kBAAkB,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;gBACrC,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YACvD,CAAC;SACF,CAAC,CAAC;IACL,CAAC;CACF;AAxCD,gCAwCC"}
@@ -0,0 +1,8 @@
1
+ import { type OtelOptions } from './otel';
2
+ export declare class OtelTraces {
3
+ private readonly options;
4
+ private _tracer;
5
+ constructor(options: OtelOptions);
6
+ start(): void;
7
+ }
8
+ //# sourceMappingURL=traces.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traces.d.ts","sourceRoot":"","sources":["../../../../src/otel/traces.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AAE1C,qBAAa,UAAU;IAET,OAAO,CAAC,QAAQ,CAAC,OAAO;IADpC,OAAO,CAAC,OAAO,CAAS;gBACK,OAAO,EAAE,WAAW;IAyB1C,KAAK;CASb"}
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ //
3
+ // Copyright 2024 DXOS.org
4
+ //
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.OtelTraces = void 0;
7
+ const api_1 = require("@opentelemetry/api");
8
+ const exporter_trace_otlp_http_1 = require("@opentelemetry/exporter-trace-otlp-http");
9
+ const resources_1 = require("@opentelemetry/resources");
10
+ const sdk_trace_base_1 = require("@opentelemetry/sdk-trace-base");
11
+ const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
12
+ const debug_1 = require("debug");
13
+ const tracing_1 = require("@dxos/tracing");
14
+ class OtelTraces {
15
+ constructor(options) {
16
+ this.options = options;
17
+ const resource = resources_1.Resource.default().merge(new resources_1.Resource({
18
+ [semantic_conventions_1.SEMRESATTRS_SERVICE_NAME]: this.options.serviceName,
19
+ [semantic_conventions_1.SEMRESATTRS_SERVICE_VERSION]: this.options.serviceVersion,
20
+ }));
21
+ const tracerProvider = new sdk_trace_base_1.BasicTracerProvider({ resource });
22
+ tracerProvider.addSpanProcessor(new sdk_trace_base_1.SimpleSpanProcessor(new sdk_trace_base_1.ConsoleSpanExporter()));
23
+ tracerProvider.addSpanProcessor(new sdk_trace_base_1.BatchSpanProcessor(new exporter_trace_otlp_http_1.OTLPTraceExporter({
24
+ url: this.options.endpoint + '/v1/traces',
25
+ headers: {
26
+ Authorization: this.options.authorizationHeader,
27
+ },
28
+ concurrencyLimit: 10, // an optional limit on pending requests
29
+ })));
30
+ tracerProvider.register();
31
+ this._tracer = api_1.trace.getTracer('dxos-observability', this.options.serviceVersion);
32
+ }
33
+ start() {
34
+ (0, debug_1.log)('trace processor registered');
35
+ tracing_1.TRACE_PROCESSOR.remoteTracing.registerProcessor({
36
+ startSpan: (options) => {
37
+ (0, debug_1.log)('begin otel trace', { options });
38
+ return this._tracer.startSpan(options.name, options);
39
+ },
40
+ });
41
+ }
42
+ }
43
+ exports.OtelTraces = OtelTraces;
44
+ //# sourceMappingURL=traces.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traces.js","sourceRoot":"","sources":["../../../../src/otel/traces.ts"],"names":[],"mappings":";AAAA,EAAE;AACF,0BAA0B;AAC1B,EAAE;;;AAEF,4CAAwD;AACxD,sFAA4E;AAC5E,wDAAoD;AACpD,kEAKuC;AACvC,8EAA4G;AAC5G,iCAA4B;AAE5B,2CAAuE;AAIvE,MAAa,UAAU;IAErB,YAA6B,OAAoB;QAApB,YAAO,GAAP,OAAO,CAAa;QAC/C,MAAM,QAAQ,GAAG,oBAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,CACvC,IAAI,oBAAQ,CAAC;YACX,CAAC,+CAAwB,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW;YACpD,CAAC,kDAA2B,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,cAAc;SAC3D,CAAC,CACH,CAAC;QAEF,MAAM,cAAc,GAAG,IAAI,oCAAmB,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC7D,cAAc,CAAC,gBAAgB,CAAC,IAAI,oCAAmB,CAAC,IAAI,oCAAmB,EAAE,CAAC,CAAC,CAAC;QACpF,cAAc,CAAC,gBAAgB,CAC7B,IAAI,mCAAkB,CACpB,IAAI,4CAAiB,CAAC;YACpB,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,GAAG,YAAY;YACzC,OAAO,EAAE;gBACP,aAAa,EAAE,IAAI,CAAC,OAAO,CAAC,mBAAmB;aAChD;YACD,gBAAgB,EAAE,EAAE,EAAE,wCAAwC;SAC/D,CAAC,CACH,CACF,CAAC;QACF,cAAc,CAAC,QAAQ,EAAE,CAAC;QAC1B,IAAI,CAAC,OAAO,GAAG,WAAK,CAAC,SAAS,CAAC,oBAAoB,EAAE,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IACpF,CAAC;IAEM,KAAK;QACV,IAAA,WAAG,EAAC,4BAA4B,CAAC,CAAC;QAClC,yBAAe,CAAC,aAAa,CAAC,iBAAiB,CAAC;YAC9C,SAAS,EAAE,CAAC,OAAyB,EAAE,EAAE;gBACvC,IAAA,WAAG,EAAC,kBAAkB,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;gBACrC,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YACvD,CAAC;SACF,CAAC,CAAC;IACL,CAAC;CACF;AApCD,gCAoCC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/observability",
3
- "version": "0.6.2",
3
+ "version": "0.6.3-main.0308ae2",
4
4
  "description": "Provides a common interface for app and platform observability",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -37,7 +37,8 @@
37
37
  "./src/datadog/node.ts": "./src/datadog/browser.ts",
38
38
  "./src/segment/node.ts": "./src/segment/browser.ts",
39
39
  "./src/sentry/node.ts": "./src/sentry/browser.ts",
40
- "./testing/testkit/index.ts": "./testing/testkit/browser.ts"
40
+ "./testing/testkit/index.ts": "./testing/testkit/browser.ts",
41
+ "./src/otel/traces.ts": "./src/otel/traces-browser.ts"
41
42
  },
42
43
  "types": "dist/types/src/index.d.ts",
43
44
  "typesVersions": {
@@ -58,35 +59,49 @@
58
59
  "src"
59
60
  ],
60
61
  "dependencies": {
62
+ "@opentelemetry/api": "^1.9.0",
63
+ "@opentelemetry/api-logs": "^0.52.1",
64
+ "@opentelemetry/auto-instrumentations-web": "^0.40.0",
65
+ "@opentelemetry/exporter-logs-otlp-http": "^0.52.1",
66
+ "@opentelemetry/exporter-metrics-otlp-http": "^0.52.0",
67
+ "@opentelemetry/exporter-trace-otlp-http": "^0.52.1",
68
+ "@opentelemetry/instrumentation": "^0.52.1",
69
+ "@opentelemetry/resources": "^1.25.1",
70
+ "@opentelemetry/sdk-logs": "^0.52.1",
71
+ "@opentelemetry/sdk-metrics": "^1.25.1",
72
+ "@opentelemetry/sdk-trace-base": "^1.25.1",
73
+ "@opentelemetry/sdk-trace-web": "^1.25.1",
74
+ "@opentelemetry/semantic-conventions": "^1.25.0",
61
75
  "@segment/analytics-node": "^2.1.0",
62
76
  "@segment/snippet": "^4.15.3",
63
- "@sentry/browser": "^8.7.0",
64
- "@sentry/node": "^8.7.0",
77
+ "@sentry/browser": "^8.8.0",
78
+ "@sentry/node": "^8.8.0",
65
79
  "datadog-metrics": "^0.11.1",
66
80
  "debug": "^4.3.4",
67
81
  "js-yaml": "^4.1.0",
68
82
  "localforage": "^1.10.0",
69
83
  "uuid": "^9.0.0",
70
- "@dxos/async": "0.6.2",
71
- "@dxos/client": "0.6.2",
72
- "@dxos/client-protocol": "0.6.2",
73
- "@dxos/config": "0.6.2",
74
- "@dxos/client-services": "0.6.2",
75
- "@dxos/context": "0.6.2",
76
- "@dxos/debug": "0.6.2",
77
- "@dxos/invariant": "0.6.2",
78
- "@dxos/log": "0.6.2",
79
- "@dxos/node-std": "0.6.2",
80
- "@dxos/network-manager": "0.6.2",
81
- "@dxos/protocols": "0.6.2",
82
- "@dxos/tracing": "0.6.2",
83
- "@dxos/util": "0.6.2"
84
+ "@dxos/async": "0.6.3-main.0308ae2",
85
+ "@dxos/client-protocol": "0.6.3-main.0308ae2",
86
+ "@dxos/context": "0.6.3-main.0308ae2",
87
+ "@dxos/config": "0.6.3-main.0308ae2",
88
+ "@dxos/client": "0.6.3-main.0308ae2",
89
+ "@dxos/client-services": "0.6.3-main.0308ae2",
90
+ "@dxos/debug": "0.6.3-main.0308ae2",
91
+ "@dxos/invariant": "0.6.3-main.0308ae2",
92
+ "@dxos/log": "0.6.3-main.0308ae2",
93
+ "@dxos/network-manager": "0.6.3-main.0308ae2",
94
+ "@dxos/node-std": "0.6.3-main.0308ae2",
95
+ "@dxos/protocols": "0.6.3-main.0308ae2",
96
+ "@dxos/tracing": "0.6.3-main.0308ae2",
97
+ "@dxos/util": "0.6.3-main.0308ae2"
84
98
  },
85
99
  "devDependencies": {
86
- "@sentry/types": "^8.7.0",
100
+ "@sentry/types": "^8.8.0",
87
101
  "@types/debug": "^4.1.10",
88
102
  "@types/js-yaml": "^4.0.5",
89
- "sentry-testkit": "^5.0.5"
103
+ "sentry-testkit": "^5.0.5",
104
+ "zone.js": ">=0.11.4 <0.12.0-0 || >=0.13.0 <0.14.0-0 || >=0.14.0 <0.15.0-0"
90
105
  },
91
106
  "publishConfig": {
92
107
  "access": "public"
@@ -3,5 +3,7 @@
3
3
  "TELEMETRY_API_KEY": "B00QG6PtJJrJ0VVFe0H5a6bcUUShKyZM",
4
4
  "IPDATA_API_KEY": "73dfdecdf979c18f07d50cf841bbdd9e589f237256326ac8cca23786",
5
5
  "DATADOG_API_KEY": null,
6
- "DATADOG_APP_KEY": null
6
+ "DATADOG_APP_KEY": null,
7
+ "OTEL_ENDPOINT": null,
8
+ "OTEL_AUTHORIZATION": null
7
9
  }
@@ -155,6 +155,7 @@ export const initializeAppObservability = async ({
155
155
  // TODO(nf): should provide capability to init Sentry earlier in booting process to capture errors during initialization.
156
156
 
157
157
  await observability.initialize();
158
+ observability.startErrorLogs();
158
159
 
159
160
  const ipData = await getIPData(config);
160
161
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { Event, scheduleTaskInterval } from '@dxos/async';
6
6
  import { type Client, type Config } from '@dxos/client';
7
- import { type Space } from '@dxos/client-protocol';
7
+ import { type ClientServices, type Space } from '@dxos/client-protocol';
8
8
  import { Context } from '@dxos/context';
9
9
  import { invariant } from '@dxos/invariant';
10
10
  import { log } from '@dxos/log';
@@ -15,9 +15,10 @@ import { isNode } from '@dxos/util';
15
15
  import buildSecrets from './cli-observability-secrets.json';
16
16
  import { type DatadogMetrics } from './datadog';
17
17
  import { type IPData, getTelemetryIdentifier, mapSpaces } from './helpers';
18
+ import { type OtelLogs, type OtelMetrics, type OtelTraces } from './otel';
18
19
  import { type SegmentTelemetry, type EventOptions, type PageOptions } from './segment';
19
20
  import { type InitOptions, type captureException as SentryCaptureException } from './sentry';
20
- import { SentryLogProcessor } from './sentry/sentry-log-processor';
21
+ import { type SentryLogProcessor } from './sentry/sentry-log-processor';
21
22
 
22
23
  const SPACE_METRICS_MIN_INTERVAL = 1000 * 60; // 1 minute
23
24
  const SPACE_TELEMETRY_MIN_INTERVAL = 1000 * 60 * 60; // 1 hour
@@ -33,6 +34,8 @@ export type ObservabilitySecrets = {
33
34
  IPDATA_API_KEY: string | null;
34
35
  DATADOG_API_KEY: string | null;
35
36
  DATADOG_APP_KEY: string | null;
37
+ OTEL_ENDPOINT: string | null;
38
+ OTEL_AUTHORIZATION: string | null;
36
39
  };
37
40
 
38
41
  export type Mode = 'basic' | 'full' | 'disabled';
@@ -66,10 +69,14 @@ export type ObservabilityOptions = {
66
69
  export class Observability {
67
70
  // TODO(wittjosiah): Generic metrics interface.
68
71
  private _metrics?: DatadogMetrics;
72
+ private _otelMetrics?: OtelMetrics;
73
+ private _otelTraces?: OtelTraces;
69
74
  // TODO(wittjosiah): Generic telemetry interface.
70
75
  private _telemetryBatchSize: number;
71
76
  private _telemetry?: SegmentTelemetry;
72
77
  // TODO(wittjosiah): Generic error logging interface.
78
+ private _sentryLogProcessor?: SentryLogProcessor;
79
+ private _otelLogs?: OtelLogs;
73
80
  private _errorReportingOptions?: InitOptions;
74
81
  private _captureException?: typeof SentryCaptureException;
75
82
  private _captureUserFeedback?: (name: string, email: string, message: string) => Promise<void>;
@@ -135,11 +142,14 @@ export class Observability {
135
142
 
136
143
  process.env.DX_ENVIRONMENT && (mergedSecrets.DX_ENVIRONMENT = process.env.DX_ENVIRONMENT);
137
144
  process.env.DX_RELEASE && (mergedSecrets.DX_RELEASE = process.env.DX_RELEASE);
145
+ // TODO: prefix these with DX_?
138
146
  process.env.SENTRY_DESTINATION && (mergedSecrets.SENTRY_DESTINATION = process.env.SENTRY_DESTINATION);
139
147
  process.env.TELEMETRY_API_KEY && (mergedSecrets.TELEMETRY_API_KEY = process.env.TELEMETRY_API_KEY);
140
148
  process.env.IPDATA_API_KEY && (mergedSecrets.IPDATA_API_KEY = process.env.IPDATA_API_KEY);
141
149
  process.env.DATADOG_API_KEY && (mergedSecrets.DATADOG_API_KEY = process.env.DATADOG_API_KEY);
142
150
  process.env.DATADOG_APP_KEY && (mergedSecrets.DATADOG_APP_KEY = process.env.DATADOG_APP_KEY);
151
+ process.env.DX_OTEL_ENDPOINT && (mergedSecrets.OTEL_ENDPOINT = process.env.DX_OTEL_ENDPOINT);
152
+ process.env.DX_OTEL_AUTHORIZATION && (mergedSecrets.OTEL_AUTHORIZATION = process.env.DX_OTEL_AUTHORIZATION);
143
153
 
144
154
  return mergedSecrets;
145
155
  } else {
@@ -152,6 +162,8 @@ export class Observability {
152
162
  IPDATA_API_KEY: config?.get('runtime.app.env.DX_IPDATA_API_KEY'),
153
163
  DATADOG_API_KEY: config?.get('runtime.app.env.DX_DATADOG_API_KEY'),
154
164
  DATADOG_APP_KEY: config?.get('runtime.app.env.DX_DATADOG_APP_KEY'),
165
+ OTEL_ENDPOINT: config?.get('runtime.app.env.DX_OTEL_ENDPOINT'),
166
+ OTEL_AUTHORIZATION: config?.get('runtime.app.env.DX_OTEL_AUTHORIZATION'),
155
167
  ...secrets,
156
168
  };
157
169
  }
@@ -161,12 +173,16 @@ export class Observability {
161
173
  await this._initMetrics();
162
174
  await this._initTelemetry();
163
175
  await this._initErrorLogs();
176
+ await this._initTraces();
164
177
  }
165
178
 
166
179
  async close() {
167
- if (this._telemetry) {
168
- await this._telemetry.close();
169
- }
180
+ const closes: Promise<void>[] = [];
181
+ this._telemetry && closes.push(this._telemetry.close());
182
+ this._otelMetrics && closes.push(this._otelMetrics.close());
183
+ this._otelLogs && closes.push(this._otelLogs.close());
184
+
185
+ await Promise.all(closes);
170
186
  await this._ctx.dispose();
171
187
 
172
188
  // TODO(wittjosiah): Remove telemetry, etc. scripts.
@@ -203,33 +219,36 @@ export class Observability {
203
219
  };
204
220
 
205
221
  // TODO(wittjosiah): Improve privacy of telemetry identifiers. See `getTelemetryIdentifier`.
206
- async setIdentityTags(client: Client) {
207
- client.services.services.IdentityService!.queryIdentity().subscribe((idqr) => {
208
- if (!idqr?.identity?.identityKey) {
209
- log('empty response from identity service', { idqr });
210
- return;
211
- }
212
-
213
- this.setTag('identityKey', idqr.identity.identityKey.truncate());
214
- });
222
+ async setIdentityTags(clientServices: Partial<ClientServices>) {
223
+ if (clientServices.IdentityService) {
224
+ clientServices.IdentityService.queryIdentity().subscribe((idqr) => {
225
+ if (!idqr?.identity?.identityKey) {
226
+ log('empty response from identity service', { idqr });
227
+ return;
228
+ }
229
+ this.setTag('identityKey', idqr.identity.identityKey.truncate());
230
+ });
231
+ }
215
232
 
216
- client.services.services.DevicesService!.queryDevices().subscribe((dqr) => {
217
- if (!dqr || !dqr.devices || dqr.devices.length === 0) {
218
- log('empty response from device service', { device: dqr });
219
- return;
220
- }
221
- invariant(dqr, 'empty response from device service');
233
+ if (clientServices.DevicesService) {
234
+ clientServices.DevicesService.queryDevices().subscribe((dqr) => {
235
+ if (!dqr || !dqr.devices || dqr.devices.length === 0) {
236
+ log('empty response from device service', { device: dqr });
237
+ return;
238
+ }
239
+ invariant(dqr, 'empty response from device service');
222
240
 
223
- const thisDevice = dqr.devices.find((device) => device.kind === DeviceKind.CURRENT);
224
- if (!thisDevice) {
225
- log('no current device', { device: dqr });
226
- return;
227
- }
228
- this.setTag('deviceKey', thisDevice.deviceKey.truncate());
229
- if (thisDevice.profile?.label) {
230
- this.setTag('deviceProfile', thisDevice.profile.label);
231
- }
232
- });
241
+ const thisDevice = dqr.devices.find((device) => device.kind === DeviceKind.CURRENT);
242
+ if (!thisDevice) {
243
+ log('no current device', { device: dqr });
244
+ return;
245
+ }
246
+ this.setTag('deviceKey', thisDevice.deviceKey.truncate());
247
+ if (thisDevice.profile?.label) {
248
+ this.setTag('deviceProfile', thisDevice.profile.label);
249
+ }
250
+ });
251
+ }
233
252
  }
234
253
 
235
254
  //
@@ -255,6 +274,27 @@ export class Observability {
255
274
  } else {
256
275
  log('datadog disabled');
257
276
  }
277
+
278
+ if (this.enabled && this._secrets.OTEL_ENDPOINT && this._secrets.OTEL_AUTHORIZATION) {
279
+ const { OtelMetrics } = await import('./otel');
280
+ this._otelMetrics = new OtelMetrics({
281
+ endpoint: this._secrets.OTEL_ENDPOINT,
282
+ authorizationHeader: this._secrets.OTEL_AUTHORIZATION,
283
+ serviceName: this._namespace,
284
+ serviceVersion: this.getTag('release')?.value ?? '0.0.0',
285
+ getTags: () =>
286
+ Object.fromEntries(
287
+ Array.from(this._tags)
288
+ .filter(([key, value]) => {
289
+ return value.scope === 'all' || value.scope === 'metrics';
290
+ })
291
+ .map(([key, value]) => [key, value.value]),
292
+ ),
293
+ });
294
+ log('otel metrics enabled');
295
+ } else {
296
+ log('otel metrics disabled');
297
+ }
258
298
  }
259
299
 
260
300
  /**
@@ -264,11 +304,15 @@ export class Observability {
264
304
  */
265
305
  gauge(name: string, value: number | any, extraTags?: any) {
266
306
  this._metrics?.gauge(name, value, extraTags);
307
+ this._otelMetrics?.gauge(name, value, extraTags);
267
308
  }
268
309
 
269
310
  // TODO(nf): Refactor into ObservabilityExtensions.
270
311
 
271
- startNetworkMetrics(client: Client) {
312
+ startNetworkMetrics(clientServices: Partial<ClientServices>) {
313
+ if (!clientServices.NetworkService) {
314
+ return;
315
+ }
272
316
  // TODO(nf): support type in debounce()
273
317
  const updateSignalMetrics = new Event<NetworkStatus>().debounce(NETWORK_METRICS_MIN_INTERVAL);
274
318
  updateSignalMetrics.on(this._ctx, async () => {
@@ -310,7 +354,7 @@ export class Observability {
310
354
  });
311
355
  });
312
356
 
313
- client.services.services.NetworkService?.queryStatus().subscribe((networkStatus) => {
357
+ clientServices.NetworkService.queryStatus().subscribe((networkStatus) => {
314
358
  this._lastNetworkStatus = networkStatus;
315
359
  updateSignalMetrics.emit();
316
360
  });
@@ -393,14 +437,20 @@ export class Observability {
393
437
  scheduleTaskInterval(
394
438
  this._ctx,
395
439
  async () => {
396
- log('platform');
440
+ if (client.services.constructor.name === 'WorkerClientServices') {
441
+ const memory = (window.performance as any).memory;
442
+ if (memory) {
443
+ this.gauge('dxos.client.runtime.heapTotal', memory.totalJSHeapSize);
444
+ this.gauge('dxos.client.runtime.heapUsed', memory.usedJSHeapSize);
445
+ this.gauge('dxos.client.runtime.heapSizeLimit', memory.jsHeapSizeLimit);
446
+ }
447
+ }
397
448
  client.services.services.SystemService?.getPlatform()
398
449
  .then((platform) => {
399
- log('platform', { platform });
400
450
  if (platform.memory) {
401
- this.gauge('dxos.client.runtime.rss', platform.memory.rss);
402
- this.gauge('dxos.client.runtime.heapTotal', platform.memory.heapTotal);
403
- this.gauge('dxos.client.runtime.heapUsed', platform.memory.heapUsed);
451
+ this.gauge('dxos.client.services.runtime.rss', platform.memory.rss);
452
+ this.gauge('dxos.client.services.runtime.heapTotal', platform.memory.heapTotal);
453
+ this.gauge('dxos.client.services.runtime.heapUsed', platform.memory.heapUsed);
404
454
  }
405
455
  })
406
456
  .catch((error) => log('platform error', { error }));
@@ -458,6 +508,7 @@ export class Observability {
458
508
  private async _initErrorLogs() {
459
509
  if (this._secrets.SENTRY_DESTINATION && this._mode !== 'disabled') {
460
510
  const { captureException, captureUserFeedback, init, setTag } = await import('./sentry');
511
+ const { SentryLogProcessor } = await import('./sentry/sentry-log-processor');
461
512
  this._captureException = captureException;
462
513
  this._captureUserFeedback = captureUserFeedback;
463
514
 
@@ -468,17 +519,14 @@ export class Observability {
468
519
  dest: this._secrets.SENTRY_DESTINATION,
469
520
  options: this._errorReportingOptions,
470
521
  });
471
-
472
- const logProcessor = new SentryLogProcessor();
522
+ this._sentryLogProcessor = new SentryLogProcessor();
473
523
  init({
474
524
  ...this._errorReportingOptions,
475
525
  destination: this._secrets.SENTRY_DESTINATION,
476
526
  scrubFilenames: this._mode !== 'full',
477
- onError: (event) => logProcessor.addLogBreadcrumbsTo(event),
527
+ onError: (event) => this._sentryLogProcessor!.addLogBreadcrumbsTo(event),
478
528
  });
479
-
480
529
  // TODO(nf): set platform at instantiation? needed for node.
481
- log.runtimeConfig.processors.push(logProcessor.logProcessor);
482
530
 
483
531
  // TODO(nf): is this different than passing as properties in options?
484
532
  this._tags.forEach((v, k) => {
@@ -489,6 +537,57 @@ export class Observability {
489
537
  } else {
490
538
  log('sentry disabled');
491
539
  }
540
+
541
+ if (this._secrets.OTEL_ENDPOINT && this._secrets.OTEL_AUTHORIZATION && this._mode !== 'disabled') {
542
+ const { OtelLogs } = await import('./otel');
543
+ this._otelLogs = new OtelLogs({
544
+ endpoint: this._secrets.OTEL_ENDPOINT,
545
+ authorizationHeader: this._secrets.OTEL_AUTHORIZATION,
546
+ serviceName: this._namespace,
547
+ serviceVersion: this.getTag('release')?.value ?? '0.0.0',
548
+ getTags: () =>
549
+ Object.fromEntries(
550
+ Array.from(this._tags)
551
+ .filter(([key, value]) => {
552
+ return value.scope === 'all' || value.scope === 'errors';
553
+ })
554
+ .map(([key, value]) => [key, value.value]),
555
+ ),
556
+ });
557
+ log('otel logs enabled', { namespace: this._namespace });
558
+ } else {
559
+ log('otel logs disabled');
560
+ }
561
+ }
562
+
563
+ startErrorLogs() {
564
+ this._sentryLogProcessor && log.runtimeConfig.processors.push(this._sentryLogProcessor.logProcessor);
565
+ this._otelLogs && log.runtimeConfig.processors.push(this._otelLogs.logProcessor);
566
+ }
567
+
568
+ startTraces() {
569
+ this._otelTraces && this._otelTraces.start();
570
+ }
571
+
572
+ // TODO(nf): refactor init based on providers and their capabilities
573
+ private async _initTraces() {
574
+ if (this._secrets.OTEL_ENDPOINT && this._secrets.OTEL_AUTHORIZATION && this._mode !== 'disabled') {
575
+ const { OtelTraces } = await import('./otel');
576
+ this._otelTraces = new OtelTraces({
577
+ endpoint: this._secrets.OTEL_ENDPOINT,
578
+ authorizationHeader: this._secrets.OTEL_AUTHORIZATION,
579
+ serviceName: this._namespace,
580
+ serviceVersion: this.getTag('release')?.value ?? '0.0.0',
581
+ getTags: () =>
582
+ Object.fromEntries(
583
+ Array.from(this._tags)
584
+ .filter(([key, value]) => {
585
+ return value.scope === 'all' || value.scope === 'metrics';
586
+ })
587
+ .map(([key, value]) => [key, value.value]),
588
+ ),
589
+ });
590
+ }
492
591
  }
493
592
 
494
593
  /**
@@ -0,0 +1,8 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export * from './otel';
6
+ export * from './logs';
7
+ export * from './metrics';
8
+ export * from './traces';