@dxos/observability 0.5.9-main.4c63b2f → 0.5.9-main.4cd994e
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-Y56RE3XY.mjs → chunk-VHY5QSKY.mjs} +80 -19
- package/dist/lib/browser/chunk-VHY5QSKY.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +1 -1
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/{observability-PQXVFXD7.mjs → observability-QSVYYZQL.mjs} +2 -2
- package/dist/lib/browser/otel-3B5NJ7JN.mjs +127 -0
- package/dist/lib/browser/otel-3B5NJ7JN.mjs.map +7 -0
- package/dist/lib/node/{chunk-AUTP6TII.cjs → chunk-2JAUQJ4Y.cjs} +83 -22
- package/dist/lib/node/chunk-2JAUQJ4Y.cjs.map +7 -0
- package/dist/lib/node/index.cjs +15 -15
- package/dist/lib/node/index.cjs.map +1 -1
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/{observability-LPC6KPIO.cjs → observability-XBZZCSZG.cjs} +6 -6
- package/dist/lib/node/{observability-LPC6KPIO.cjs.map → observability-XBZZCSZG.cjs.map} +2 -2
- package/dist/lib/node/otel-WOKFA2PO.cjs +149 -0
- package/dist/lib/node/otel-WOKFA2PO.cjs.map +7 -0
- package/dist/types/src/cli-observability-secrets.json +3 -1
- package/dist/types/src/observability.d.ts +3 -0
- package/dist/types/src/observability.d.ts.map +1 -1
- package/dist/types/src/observability.js +48 -1
- package/dist/types/src/observability.js.map +1 -1
- package/dist/types/src/otel/index.d.ts +4 -0
- package/dist/types/src/otel/index.d.ts.map +1 -0
- package/dist/types/src/otel/index.js +23 -0
- package/dist/types/src/otel/index.js.map +1 -0
- package/dist/types/src/otel/logs.d.ts +8 -0
- package/dist/types/src/otel/logs.d.ts.map +1 -0
- package/dist/types/src/otel/logs.js +64 -0
- package/dist/types/src/otel/logs.js.map +1 -0
- package/dist/types/src/otel/metrics.d.ts +11 -0
- package/dist/types/src/otel/metrics.d.ts.map +1 -0
- package/dist/types/src/otel/metrics.js +64 -0
- package/dist/types/src/otel/metrics.js.map +1 -0
- package/dist/types/src/otel/otel.d.ts +10 -0
- package/dist/types/src/otel/otel.d.ts.map +1 -0
- package/dist/types/src/otel/otel.js +6 -0
- package/dist/types/src/otel/otel.js.map +1 -0
- package/package.json +23 -15
- package/src/cli-observability-secrets.json +3 -1
- package/src/observability.ts +55 -0
- package/src/otel/index.ts +7 -0
- package/src/otel/logs.ts +69 -0
- package/src/otel/metrics.ts +79 -0
- package/src/otel/otel.ts +11 -0
- package/dist/lib/browser/chunk-Y56RE3XY.mjs.map +0 -7
- package/dist/lib/node/chunk-AUTP6TII.cjs.map +0 -7
- /package/dist/lib/browser/{observability-PQXVFXD7.mjs.map → observability-QSVYYZQL.mjs.map} +0 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type LogProcessor } from '@dxos/log';
|
|
2
|
+
import { type OtelOptions } from './otel';
|
|
3
|
+
export declare class OtelLogs {
|
|
4
|
+
private readonly options;
|
|
5
|
+
constructor(options: OtelOptions);
|
|
6
|
+
getLogProcessor(): LogProcessor;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=logs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../../../../src/otel/logs.ts"],"names":[],"mappings":"AAWA,OAAO,EAA2C,KAAK,YAAY,EAAa,MAAM,WAAW,CAAC;AAElG,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AAE1C,qBAAa,QAAQ;IACP,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,WAAW;IAIjD,eAAe,IAAI,YAAY;CAiChC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
//
|
|
3
|
+
// Copyright 2024 DXOS.org
|
|
4
|
+
//
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.OtelLogs = void 0;
|
|
7
|
+
const api_1 = require("@opentelemetry/api");
|
|
8
|
+
const api_logs_1 = require("@opentelemetry/api-logs");
|
|
9
|
+
const exporter_logs_otlp_http_1 = require("@opentelemetry/exporter-logs-otlp-http");
|
|
10
|
+
const resources_1 = require("@opentelemetry/resources");
|
|
11
|
+
const sdk_logs_1 = require("@opentelemetry/sdk-logs");
|
|
12
|
+
const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
|
|
13
|
+
const log_1 = require("@dxos/log");
|
|
14
|
+
class OtelLogs {
|
|
15
|
+
constructor(options) {
|
|
16
|
+
this.options = options;
|
|
17
|
+
api_1.diag.setLogger(new api_1.DiagConsoleLogger(), api_1.DiagLogLevel.INFO);
|
|
18
|
+
}
|
|
19
|
+
getLogProcessor() {
|
|
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 collectorOptions = {
|
|
25
|
+
url: this.options.endpoint + '/v1/logs',
|
|
26
|
+
headers: {
|
|
27
|
+
Authorization: this.options.authorizationHeader,
|
|
28
|
+
},
|
|
29
|
+
concurrencyLimit: 1, // an optional limit on pending requests
|
|
30
|
+
};
|
|
31
|
+
const logExporter = new exporter_logs_otlp_http_1.OTLPLogExporter(collectorOptions);
|
|
32
|
+
const loggerProvider = new sdk_logs_1.LoggerProvider({ resource });
|
|
33
|
+
loggerProvider.addLogRecordProcessor(new sdk_logs_1.BatchLogRecordProcessor(logExporter));
|
|
34
|
+
// TODO: namespace?
|
|
35
|
+
const logger = loggerProvider.getLogger('dxos-observability', '0.0.0');
|
|
36
|
+
return (config, entry) => {
|
|
37
|
+
const { level, message, context, error } = entry;
|
|
38
|
+
if (!(0, log_1.shouldLog)(entry, config.filters)) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
logger.emit({
|
|
42
|
+
severityNumber: convertLevel(level),
|
|
43
|
+
body: { message, error: error !== null && error !== void 0 ? error : undefined, ...context },
|
|
44
|
+
attributes: this.options.getTags(),
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.OtelLogs = OtelLogs;
|
|
50
|
+
const convertLevel = (level) => {
|
|
51
|
+
switch (level) {
|
|
52
|
+
case log_1.LogLevel.DEBUG:
|
|
53
|
+
return api_logs_1.SeverityNumber.DEBUG;
|
|
54
|
+
case log_1.LogLevel.INFO:
|
|
55
|
+
return api_logs_1.SeverityNumber.INFO;
|
|
56
|
+
case log_1.LogLevel.WARN:
|
|
57
|
+
return api_logs_1.SeverityNumber.WARN;
|
|
58
|
+
case log_1.LogLevel.ERROR:
|
|
59
|
+
return api_logs_1.SeverityNumber.ERROR;
|
|
60
|
+
default:
|
|
61
|
+
return api_logs_1.SeverityNumber.ERROR;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
//# sourceMappingURL=logs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs.js","sourceRoot":"","sources":["../../../../src/otel/logs.ts"],"names":[],"mappings":";AAAA,EAAE;AACF,0BAA0B;AAC1B,EAAE;;;AAEF,4CAA2E;AAC3E,sDAAyD;AACzD,oFAAyE;AACzE,wDAAoD;AACpD,sDAAkF;AAClF,8EAA4G;AAE5G,mCAAkG;AAIlG,MAAa,QAAQ;IACnB,YAA6B,OAAoB;QAApB,YAAO,GAAP,OAAO,CAAa;QAC/C,UAAI,CAAC,SAAS,CAAC,IAAI,uBAAiB,EAAE,EAAE,kBAAY,CAAC,IAAI,CAAC,CAAC;IAC7D,CAAC;IAED,eAAe;QACb,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;QACF,MAAM,gBAAgB,GAAG;YACvB,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,GAAG,UAAU;YACvC,OAAO,EAAE;gBACP,aAAa,EAAE,IAAI,CAAC,OAAO,CAAC,mBAAmB;aAChD;YACD,gBAAgB,EAAE,CAAC,EAAE,wCAAwC;SAC9D,CAAC;QACF,MAAM,WAAW,GAAG,IAAI,yCAAe,CAAC,gBAAgB,CAAC,CAAC;QAC1D,MAAM,cAAc,GAAG,IAAI,yBAAc,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;QAExD,cAAc,CAAC,qBAAqB,CAAC,IAAI,kCAAuB,CAAC,WAAW,CAAC,CAAC,CAAC;QAE/E,mBAAmB;QACnB,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC;QACvE,OAAO,CAAC,MAAiB,EAAE,KAAe,EAAE,EAAE;YAC5C,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;YACjD,IAAI,CAAC,IAAA,eAAS,EAAC,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;gBACtC,OAAO;YACT,CAAC;YACD,MAAM,CAAC,IAAI,CAAC;gBACV,cAAc,EAAE,YAAY,CAAC,KAAK,CAAC;gBACnC,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,aAAL,KAAK,cAAL,KAAK,GAAI,SAAS,EAAE,GAAG,OAAO,EAAE;gBACxD,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE;aACnC,CAAC,CAAC;QACL,CAAC,CAAC;IACJ,CAAC;CACF;AAtCD,4BAsCC;AAED,MAAM,YAAY,GAAG,CAAC,KAAe,EAAkB,EAAE;IACvD,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,cAAQ,CAAC,KAAK;YACjB,OAAO,yBAAc,CAAC,KAAK,CAAC;QAC9B,KAAK,cAAQ,CAAC,IAAI;YAChB,OAAO,yBAAc,CAAC,IAAI,CAAC;QAC7B,KAAK,cAAQ,CAAC,IAAI;YAChB,OAAO,yBAAc,CAAC,IAAI,CAAC;QAC7B,KAAK,cAAQ,CAAC,KAAK;YACjB,OAAO,yBAAc,CAAC,KAAK,CAAC;QAC9B;YACE,OAAO,yBAAc,CAAC,KAAK,CAAC;IAChC,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type OtelOptions } from './otel';
|
|
2
|
+
export declare class OtelMetrics {
|
|
3
|
+
private readonly options;
|
|
4
|
+
private _meterProvider;
|
|
5
|
+
private _gauges;
|
|
6
|
+
constructor(options: OtelOptions);
|
|
7
|
+
gauge(name: string, value: number, tags?: any): void;
|
|
8
|
+
flush(): Promise<void>;
|
|
9
|
+
close(): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=metrics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../../../src/otel/metrics.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AAU1C,qBAAa,WAAW;IAIV,OAAO,CAAC,QAAQ,CAAC,OAAO;IAHpC,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,OAAO,CAAuC;gBAEzB,OAAO,EAAE,WAAW;IA0BjD,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG;IAqB7C,KAAK;IAIL,KAAK;CAGN"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
//
|
|
3
|
+
// Copyright 2024 DXOS.org
|
|
4
|
+
//
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.OtelMetrics = void 0;
|
|
7
|
+
const exporter_metrics_otlp_http_1 = require("@opentelemetry/exporter-metrics-otlp-http");
|
|
8
|
+
const resources_1 = require("@opentelemetry/resources");
|
|
9
|
+
const sdk_metrics_1 = require("@opentelemetry/sdk-metrics");
|
|
10
|
+
const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
|
|
11
|
+
const EXPORT_INTERVAL = 60 * 1000;
|
|
12
|
+
class OtelMetrics {
|
|
13
|
+
constructor(options) {
|
|
14
|
+
this.options = options;
|
|
15
|
+
this._gauges = new Map();
|
|
16
|
+
// TODO: improve error handling/logging
|
|
17
|
+
// https://github.com/open-telemetry/opentelemetry-js/issues/4823
|
|
18
|
+
const resource = resources_1.Resource.default().merge(new resources_1.Resource({
|
|
19
|
+
[semantic_conventions_1.SEMRESATTRS_SERVICE_NAME]: this.options.serviceName,
|
|
20
|
+
[semantic_conventions_1.SEMRESATTRS_SERVICE_VERSION]: this.options.serviceVersion,
|
|
21
|
+
}));
|
|
22
|
+
const grafanaMetricReader = new sdk_metrics_1.PeriodicExportingMetricReader({
|
|
23
|
+
exporter: new exporter_metrics_otlp_http_1.OTLPMetricExporter({
|
|
24
|
+
url: this.options.endpoint + '/v1/metrics',
|
|
25
|
+
headers: {
|
|
26
|
+
Authorization: this.options.authorizationHeader,
|
|
27
|
+
},
|
|
28
|
+
}),
|
|
29
|
+
exportIntervalMillis: EXPORT_INTERVAL,
|
|
30
|
+
});
|
|
31
|
+
this._meterProvider = new sdk_metrics_1.MeterProvider({
|
|
32
|
+
resource,
|
|
33
|
+
readers: [grafanaMetricReader],
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
gauge(name, value, tags) {
|
|
37
|
+
const meter = this._meterProvider.getMeter('dxos-observability');
|
|
38
|
+
const observableGauge = this._gauges.get(name);
|
|
39
|
+
const mergedTags = { ...this.options.getTags(), ...tags };
|
|
40
|
+
if (!observableGauge) {
|
|
41
|
+
const synchronousGauge = {
|
|
42
|
+
gauge: meter.createObservableGauge(name),
|
|
43
|
+
nextValue: value,
|
|
44
|
+
nextTags: mergedTags,
|
|
45
|
+
};
|
|
46
|
+
synchronousGauge.gauge.addCallback((observerResult) => {
|
|
47
|
+
observerResult.observe(synchronousGauge.nextValue, synchronousGauge.nextTags);
|
|
48
|
+
});
|
|
49
|
+
this._gauges.set(name, synchronousGauge);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
observableGauge.nextTags = mergedTags;
|
|
53
|
+
observableGauge.nextValue = value;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
flush() {
|
|
57
|
+
return this._meterProvider.forceFlush();
|
|
58
|
+
}
|
|
59
|
+
close() {
|
|
60
|
+
return this._meterProvider.shutdown();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
exports.OtelMetrics = OtelMetrics;
|
|
64
|
+
//# sourceMappingURL=metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../../../src/otel/metrics.ts"],"names":[],"mappings":";AAAA,EAAE;AACF,0BAA0B;AAC1B,EAAE;;;AAGF,0FAA+E;AAC/E,wDAAoD;AACpD,4DAA0F;AAC1F,8EAA4G;AAI5G,MAAM,eAAe,GAAG,EAAE,GAAG,IAAI,CAAC;AAQlC,MAAa,WAAW;IAItB,YAA6B,OAAoB;QAApB,YAAO,GAAP,OAAO,CAAa;QAFzC,YAAO,GAAG,IAAI,GAAG,EAA4B,CAAC;QAGpD,uCAAuC;QACvC,kEAAkE;QAClE,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,mBAAmB,GAAG,IAAI,2CAA6B,CAAC;YAC5D,QAAQ,EAAE,IAAI,+CAAkB,CAAC;gBAC/B,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,GAAG,aAAa;gBAC1C,OAAO,EAAE;oBACP,aAAa,EAAE,IAAI,CAAC,OAAO,CAAC,mBAAmB;iBAChD;aACF,CAAC;YACF,oBAAoB,EAAE,eAAe;SACtC,CAAC,CAAC;QAEH,IAAI,CAAC,cAAc,GAAG,IAAI,2BAAa,CAAC;YACtC,QAAQ;YACR,OAAO,EAAE,CAAC,mBAAmB,CAAC;SAC/B,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAY,EAAE,KAAa,EAAE,IAAU;QAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;QACjE,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAE/C,MAAM,UAAU,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC;QAC1D,IAAI,CAAC,eAAe,EAAE,CAAC;YACrB,MAAM,gBAAgB,GAAG;gBACvB,KAAK,EAAE,KAAK,CAAC,qBAAqB,CAAC,IAAI,CAAC;gBACxC,SAAS,EAAE,KAAK;gBAChB,QAAQ,EAAE,UAAU;aACrB,CAAC;YACF,gBAAgB,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,cAAc,EAAE,EAAE;gBACpD,cAAc,CAAC,OAAO,CAAC,gBAAgB,CAAC,SAAS,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YAChF,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;QAC3C,CAAC;aAAM,CAAC;YACN,eAAe,CAAC,QAAQ,GAAG,UAAU,CAAC;YACtC,eAAe,CAAC,SAAS,GAAG,KAAK,CAAC;QACpC,CAAC;IACH,CAAC;IAED,KAAK;QACH,OAAO,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE,CAAC;IAC1C,CAAC;IAED,KAAK;QACH,OAAO,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,CAAC;IACxC,CAAC;CACF;AA1DD,kCA0DC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otel.d.ts","sourceRoot":"","sources":["../../../../src/otel/otel.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;CAC1C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otel.js","sourceRoot":"","sources":["../../../../src/otel/otel.ts"],"names":[],"mappings":";AAAA,EAAE;AACF,0BAA0B;AAC1B,EAAE"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/observability",
|
|
3
|
-
"version": "0.5.9-main.
|
|
3
|
+
"version": "0.5.9-main.4cd994e",
|
|
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",
|
|
@@ -58,6 +58,14 @@
|
|
|
58
58
|
"src"
|
|
59
59
|
],
|
|
60
60
|
"dependencies": {
|
|
61
|
+
"@opentelemetry/api": "^1.8.0",
|
|
62
|
+
"@opentelemetry/api-logs": "^0.52.1",
|
|
63
|
+
"@opentelemetry/exporter-logs-otlp-http": "^0.52.1",
|
|
64
|
+
"@opentelemetry/exporter-metrics-otlp-http": "^0.52.0",
|
|
65
|
+
"@opentelemetry/resources": "^1.25.0",
|
|
66
|
+
"@opentelemetry/sdk-logs": "^0.52.1",
|
|
67
|
+
"@opentelemetry/sdk-metrics": "^1.8.0",
|
|
68
|
+
"@opentelemetry/semantic-conventions": "^1.25.0",
|
|
61
69
|
"@segment/analytics-node": "^2.1.0",
|
|
62
70
|
"@segment/snippet": "^4.15.3",
|
|
63
71
|
"@sentry/browser": "^8.7.0",
|
|
@@ -67,20 +75,20 @@
|
|
|
67
75
|
"js-yaml": "^4.1.0",
|
|
68
76
|
"localforage": "^1.10.0",
|
|
69
77
|
"uuid": "^8.3.2",
|
|
70
|
-
"@dxos/
|
|
71
|
-
"@dxos/
|
|
72
|
-
"@dxos/client-services": "0.5.9-main.
|
|
73
|
-
"@dxos/config": "0.5.9-main.
|
|
74
|
-
"@dxos/context": "0.5.9-main.
|
|
75
|
-
"@dxos/invariant": "0.5.9-main.
|
|
76
|
-
"@dxos/log": "0.5.9-main.
|
|
77
|
-
"@dxos/debug": "0.5.9-main.
|
|
78
|
-
"@dxos/
|
|
79
|
-
"@dxos/
|
|
80
|
-
"@dxos/
|
|
81
|
-
"@dxos/
|
|
82
|
-
"@dxos/util": "0.5.9-main.
|
|
83
|
-
"@dxos/
|
|
78
|
+
"@dxos/async": "0.5.9-main.4cd994e",
|
|
79
|
+
"@dxos/client-protocol": "0.5.9-main.4cd994e",
|
|
80
|
+
"@dxos/client-services": "0.5.9-main.4cd994e",
|
|
81
|
+
"@dxos/config": "0.5.9-main.4cd994e",
|
|
82
|
+
"@dxos/context": "0.5.9-main.4cd994e",
|
|
83
|
+
"@dxos/invariant": "0.5.9-main.4cd994e",
|
|
84
|
+
"@dxos/log": "0.5.9-main.4cd994e",
|
|
85
|
+
"@dxos/debug": "0.5.9-main.4cd994e",
|
|
86
|
+
"@dxos/node-std": "0.5.9-main.4cd994e",
|
|
87
|
+
"@dxos/network-manager": "0.5.9-main.4cd994e",
|
|
88
|
+
"@dxos/protocols": "0.5.9-main.4cd994e",
|
|
89
|
+
"@dxos/react-client": "0.5.9-main.4cd994e",
|
|
90
|
+
"@dxos/util": "0.5.9-main.4cd994e",
|
|
91
|
+
"@dxos/tracing": "0.5.9-main.4cd994e"
|
|
84
92
|
},
|
|
85
93
|
"devDependencies": {
|
|
86
94
|
"@sentry/types": "^8.7.0",
|
|
@@ -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
|
}
|
package/src/observability.ts
CHANGED
|
@@ -15,6 +15,7 @@ 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 OtelMetrics } 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
21
|
import { SentryLogProcessor } from './sentry/sentry-log-processor';
|
|
@@ -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,6 +69,7 @@ export type ObservabilityOptions = {
|
|
|
66
69
|
export class Observability {
|
|
67
70
|
// TODO(wittjosiah): Generic metrics interface.
|
|
68
71
|
private _metrics?: DatadogMetrics;
|
|
72
|
+
private _otelMetrics?: OtelMetrics;
|
|
69
73
|
// TODO(wittjosiah): Generic telemetry interface.
|
|
70
74
|
private _telemetryBatchSize: number;
|
|
71
75
|
private _telemetry?: SegmentTelemetry;
|
|
@@ -135,11 +139,14 @@ export class Observability {
|
|
|
135
139
|
|
|
136
140
|
process.env.DX_ENVIRONMENT && (mergedSecrets.DX_ENVIRONMENT = process.env.DX_ENVIRONMENT);
|
|
137
141
|
process.env.DX_RELEASE && (mergedSecrets.DX_RELEASE = process.env.DX_RELEASE);
|
|
142
|
+
// TODO: prefix these with DX_?
|
|
138
143
|
process.env.SENTRY_DESTINATION && (mergedSecrets.SENTRY_DESTINATION = process.env.SENTRY_DESTINATION);
|
|
139
144
|
process.env.TELEMETRY_API_KEY && (mergedSecrets.TELEMETRY_API_KEY = process.env.TELEMETRY_API_KEY);
|
|
140
145
|
process.env.IPDATA_API_KEY && (mergedSecrets.IPDATA_API_KEY = process.env.IPDATA_API_KEY);
|
|
141
146
|
process.env.DATADOG_API_KEY && (mergedSecrets.DATADOG_API_KEY = process.env.DATADOG_API_KEY);
|
|
142
147
|
process.env.DATADOG_APP_KEY && (mergedSecrets.DATADOG_APP_KEY = process.env.DATADOG_APP_KEY);
|
|
148
|
+
process.env.DX_OTEL_ENDPOINT && (mergedSecrets.OTEL_ENDPOINT = process.env.DX_OTEL_ENDPOINT);
|
|
149
|
+
process.env.DX_OTEL_AUTHORIZATION && (mergedSecrets.OTEL_AUTHORIZATION = process.env.DX_OTEL_AUTHORIZATION);
|
|
143
150
|
|
|
144
151
|
return mergedSecrets;
|
|
145
152
|
} else {
|
|
@@ -152,6 +159,8 @@ export class Observability {
|
|
|
152
159
|
IPDATA_API_KEY: config?.get('runtime.app.env.DX_IPDATA_API_KEY'),
|
|
153
160
|
DATADOG_API_KEY: config?.get('runtime.app.env.DX_DATADOG_API_KEY'),
|
|
154
161
|
DATADOG_APP_KEY: config?.get('runtime.app.env.DX_DATADOG_APP_KEY'),
|
|
162
|
+
OTEL_ENDPOINT: config?.get('runtime.app.env.DX_OTEL_ENDPOINT'),
|
|
163
|
+
OTEL_AUTHORIZATION: config?.get('runtime.app.env.DX_OTEL_AUTHORIZATION'),
|
|
155
164
|
...secrets,
|
|
156
165
|
};
|
|
157
166
|
}
|
|
@@ -167,6 +176,9 @@ export class Observability {
|
|
|
167
176
|
if (this._telemetry) {
|
|
168
177
|
await this._telemetry.close();
|
|
169
178
|
}
|
|
179
|
+
if (this._otelMetrics) {
|
|
180
|
+
await this._otelMetrics.close();
|
|
181
|
+
}
|
|
170
182
|
await this._ctx.dispose();
|
|
171
183
|
|
|
172
184
|
// TODO(wittjosiah): Remove telemetry, etc. scripts.
|
|
@@ -255,6 +267,27 @@ export class Observability {
|
|
|
255
267
|
} else {
|
|
256
268
|
log('datadog disabled');
|
|
257
269
|
}
|
|
270
|
+
|
|
271
|
+
if (this.enabled && this._secrets.OTEL_ENDPOINT && this._secrets.OTEL_AUTHORIZATION) {
|
|
272
|
+
const { OtelMetrics } = await import('./otel');
|
|
273
|
+
this._otelMetrics = new OtelMetrics({
|
|
274
|
+
endpoint: this._secrets.OTEL_ENDPOINT,
|
|
275
|
+
authorizationHeader: this._secrets.OTEL_AUTHORIZATION,
|
|
276
|
+
serviceName: this._namespace,
|
|
277
|
+
serviceVersion: this.getTag('release')?.value ?? '0.0.0',
|
|
278
|
+
getTags: () =>
|
|
279
|
+
Object.fromEntries(
|
|
280
|
+
Array.from(this._tags)
|
|
281
|
+
.filter(([key, value]) => {
|
|
282
|
+
return value.scope === 'all' || value.scope === 'metrics';
|
|
283
|
+
})
|
|
284
|
+
.map(([key, value]) => [key, value.value]),
|
|
285
|
+
),
|
|
286
|
+
});
|
|
287
|
+
log('otel metrics enabled');
|
|
288
|
+
} else {
|
|
289
|
+
log('otel metrics disabled');
|
|
290
|
+
}
|
|
258
291
|
}
|
|
259
292
|
|
|
260
293
|
/**
|
|
@@ -264,6 +297,7 @@ export class Observability {
|
|
|
264
297
|
*/
|
|
265
298
|
gauge(name: string, value: number | any, extraTags?: any) {
|
|
266
299
|
this._metrics?.gauge(name, value, extraTags);
|
|
300
|
+
this._otelMetrics?.gauge(name, value, extraTags);
|
|
267
301
|
}
|
|
268
302
|
|
|
269
303
|
// TODO(nf): Refactor into ObservabilityExtensions.
|
|
@@ -489,6 +523,27 @@ export class Observability {
|
|
|
489
523
|
} else {
|
|
490
524
|
log('sentry disabled');
|
|
491
525
|
}
|
|
526
|
+
|
|
527
|
+
if (this._secrets.OTEL_ENDPOINT && this._secrets.OTEL_AUTHORIZATION && this._mode !== 'disabled') {
|
|
528
|
+
const { OtelLogs } = await import('./otel');
|
|
529
|
+
const logs = new OtelLogs({
|
|
530
|
+
endpoint: this._secrets.OTEL_ENDPOINT,
|
|
531
|
+
authorizationHeader: this._secrets.OTEL_AUTHORIZATION,
|
|
532
|
+
serviceName: this._namespace,
|
|
533
|
+
serviceVersion: this.getTag('release')?.value ?? '0.0.0',
|
|
534
|
+
getTags: () =>
|
|
535
|
+
Object.fromEntries(
|
|
536
|
+
Array.from(this._tags)
|
|
537
|
+
.filter(([key, value]) => {
|
|
538
|
+
return value.scope === 'all' || value.scope === 'errors';
|
|
539
|
+
})
|
|
540
|
+
.map(([key, value]) => [key, value.value]),
|
|
541
|
+
),
|
|
542
|
+
});
|
|
543
|
+
log.runtimeConfig.processors.push(logs.getLogProcessor());
|
|
544
|
+
} else {
|
|
545
|
+
log('otel logs disabled');
|
|
546
|
+
}
|
|
492
547
|
}
|
|
493
548
|
|
|
494
549
|
/**
|
package/src/otel/logs.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { diag, DiagConsoleLogger, DiagLogLevel } from '@opentelemetry/api';
|
|
6
|
+
import { SeverityNumber } from '@opentelemetry/api-logs';
|
|
7
|
+
import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http';
|
|
8
|
+
import { Resource } from '@opentelemetry/resources';
|
|
9
|
+
import { LoggerProvider, BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';
|
|
10
|
+
import { SEMRESATTRS_SERVICE_NAME, SEMRESATTRS_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';
|
|
11
|
+
|
|
12
|
+
import { type LogConfig, type LogEntry, LogLevel, type LogProcessor, shouldLog } from '@dxos/log';
|
|
13
|
+
|
|
14
|
+
import { type OtelOptions } from './otel';
|
|
15
|
+
|
|
16
|
+
export class OtelLogs {
|
|
17
|
+
constructor(private readonly options: OtelOptions) {
|
|
18
|
+
diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.INFO);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
getLogProcessor(): LogProcessor {
|
|
22
|
+
const resource = Resource.default().merge(
|
|
23
|
+
new Resource({
|
|
24
|
+
[SEMRESATTRS_SERVICE_NAME]: this.options.serviceName,
|
|
25
|
+
[SEMRESATTRS_SERVICE_VERSION]: this.options.serviceVersion,
|
|
26
|
+
}),
|
|
27
|
+
);
|
|
28
|
+
const collectorOptions = {
|
|
29
|
+
url: this.options.endpoint + '/v1/logs',
|
|
30
|
+
headers: {
|
|
31
|
+
Authorization: this.options.authorizationHeader,
|
|
32
|
+
},
|
|
33
|
+
concurrencyLimit: 1, // an optional limit on pending requests
|
|
34
|
+
};
|
|
35
|
+
const logExporter = new OTLPLogExporter(collectorOptions);
|
|
36
|
+
const loggerProvider = new LoggerProvider({ resource });
|
|
37
|
+
|
|
38
|
+
loggerProvider.addLogRecordProcessor(new BatchLogRecordProcessor(logExporter));
|
|
39
|
+
|
|
40
|
+
// TODO: namespace?
|
|
41
|
+
const logger = loggerProvider.getLogger('dxos-observability', '0.0.0');
|
|
42
|
+
return (config: LogConfig, entry: LogEntry) => {
|
|
43
|
+
const { level, message, context, error } = entry;
|
|
44
|
+
if (!shouldLog(entry, config.filters)) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
logger.emit({
|
|
48
|
+
severityNumber: convertLevel(level),
|
|
49
|
+
body: { message, error: error ?? undefined, ...context },
|
|
50
|
+
attributes: this.options.getTags(),
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const convertLevel = (level: LogLevel): SeverityNumber => {
|
|
57
|
+
switch (level) {
|
|
58
|
+
case LogLevel.DEBUG:
|
|
59
|
+
return SeverityNumber.DEBUG;
|
|
60
|
+
case LogLevel.INFO:
|
|
61
|
+
return SeverityNumber.INFO;
|
|
62
|
+
case LogLevel.WARN:
|
|
63
|
+
return SeverityNumber.WARN;
|
|
64
|
+
case LogLevel.ERROR:
|
|
65
|
+
return SeverityNumber.ERROR;
|
|
66
|
+
default:
|
|
67
|
+
return SeverityNumber.ERROR;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type Attributes, type ObservableGauge } from '@opentelemetry/api';
|
|
6
|
+
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';
|
|
7
|
+
import { Resource } from '@opentelemetry/resources';
|
|
8
|
+
import { MeterProvider, PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';
|
|
9
|
+
import { SEMRESATTRS_SERVICE_NAME, SEMRESATTRS_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';
|
|
10
|
+
|
|
11
|
+
import { type OtelOptions } from './otel';
|
|
12
|
+
|
|
13
|
+
const EXPORT_INTERVAL = 60 * 1000;
|
|
14
|
+
|
|
15
|
+
type SynchronousGauge = {
|
|
16
|
+
gauge: ObservableGauge<Attributes>;
|
|
17
|
+
nextValue: number;
|
|
18
|
+
nextTags?: any;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export class OtelMetrics {
|
|
22
|
+
private _meterProvider: MeterProvider;
|
|
23
|
+
private _gauges = new Map<string, SynchronousGauge>();
|
|
24
|
+
|
|
25
|
+
constructor(private readonly options: OtelOptions) {
|
|
26
|
+
// TODO: improve error handling/logging
|
|
27
|
+
// https://github.com/open-telemetry/opentelemetry-js/issues/4823
|
|
28
|
+
const resource = Resource.default().merge(
|
|
29
|
+
new Resource({
|
|
30
|
+
[SEMRESATTRS_SERVICE_NAME]: this.options.serviceName,
|
|
31
|
+
[SEMRESATTRS_SERVICE_VERSION]: this.options.serviceVersion,
|
|
32
|
+
}),
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
const grafanaMetricReader = new PeriodicExportingMetricReader({
|
|
36
|
+
exporter: new OTLPMetricExporter({
|
|
37
|
+
url: this.options.endpoint + '/v1/metrics',
|
|
38
|
+
headers: {
|
|
39
|
+
Authorization: this.options.authorizationHeader,
|
|
40
|
+
},
|
|
41
|
+
}),
|
|
42
|
+
exportIntervalMillis: EXPORT_INTERVAL,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
this._meterProvider = new MeterProvider({
|
|
46
|
+
resource,
|
|
47
|
+
readers: [grafanaMetricReader],
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
gauge(name: string, value: number, tags?: any) {
|
|
52
|
+
const meter = this._meterProvider.getMeter('dxos-observability');
|
|
53
|
+
const observableGauge = this._gauges.get(name);
|
|
54
|
+
|
|
55
|
+
const mergedTags = { ...this.options.getTags(), ...tags };
|
|
56
|
+
if (!observableGauge) {
|
|
57
|
+
const synchronousGauge = {
|
|
58
|
+
gauge: meter.createObservableGauge(name),
|
|
59
|
+
nextValue: value,
|
|
60
|
+
nextTags: mergedTags,
|
|
61
|
+
};
|
|
62
|
+
synchronousGauge.gauge.addCallback((observerResult) => {
|
|
63
|
+
observerResult.observe(synchronousGauge.nextValue, synchronousGauge.nextTags);
|
|
64
|
+
});
|
|
65
|
+
this._gauges.set(name, synchronousGauge);
|
|
66
|
+
} else {
|
|
67
|
+
observableGauge.nextTags = mergedTags;
|
|
68
|
+
observableGauge.nextValue = value;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
flush() {
|
|
73
|
+
return this._meterProvider.forceFlush();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
close() {
|
|
77
|
+
return this._meterProvider.shutdown();
|
|
78
|
+
}
|
|
79
|
+
}
|
package/src/otel/otel.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
export type OtelOptions = {
|
|
6
|
+
endpoint: string;
|
|
7
|
+
authorizationHeader: string;
|
|
8
|
+
serviceName: string; // For the Otel API, the name of the entity for which signals (metrics or trace) are collected.
|
|
9
|
+
serviceVersion: string; // For the Otel API, The name of the entity for which signals (metrics or trace) are collected.
|
|
10
|
+
getTags: () => { [key: string]: string };
|
|
11
|
+
};
|