@oas-tools/oas-telemetry 0.7.1 → 0.8.0-alpha.0
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/.env.example +21 -2
- package/README.md +1 -2
- package/dist/cjs/config/bootConfig.cjs +19 -14
- package/dist/cjs/config/config.cjs +112 -125
- package/dist/cjs/config/config.types.cjs +1 -4
- package/dist/cjs/docs/openapi.yaml +158 -4
- package/dist/cjs/index.cjs +27 -30
- package/dist/cjs/routesManager.cjs +62 -70
- package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbLogExporter.cjs +202 -190
- package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.cjs +204 -99
- package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.cjs +152 -116
- package/dist/cjs/telemetry/custom-implementations/instrumentations/logsInstrumentation.cjs +92 -0
- package/dist/cjs/telemetry/custom-implementations/metrics/tsdb/Chunk.cjs +159 -0
- package/dist/cjs/telemetry/custom-implementations/metrics/tsdb/Series.cjs +168 -0
- package/dist/cjs/telemetry/custom-implementations/metrics/tsdb/SeriesRegistry.cjs +389 -0
- package/dist/cjs/telemetry/custom-implementations/metrics/tsdb/types.cjs +2 -0
- package/dist/cjs/telemetry/custom-implementations/metrics/tsdb/utils.cjs +77 -0
- package/dist/cjs/telemetry/custom-implementations/processors/dynamicMultiLogProcessor.cjs +65 -63
- package/dist/cjs/telemetry/custom-implementations/processors/dynamicMultiSpanProcessor.cjs +63 -62
- package/dist/cjs/telemetry/custom-implementations/utils/circular.cjs +47 -47
- package/dist/cjs/telemetry/custom-implementations/utils/storagePath.cjs +39 -0
- package/dist/cjs/telemetry/custom-implementations/wrappers.cjs +141 -138
- package/dist/cjs/telemetry/initializeTelemetry.cjs +35 -91
- package/dist/cjs/telemetry/telemetryConfigurator.cjs +70 -72
- package/dist/cjs/telemetry/telemetryRegistry.cjs +45 -31
- package/dist/cjs/tlm-ai/agent.cjs +49 -64
- package/dist/cjs/tlm-ai/aiController.cjs +54 -76
- package/dist/cjs/tlm-ai/aiRoutes.cjs +17 -20
- package/dist/cjs/tlm-ai/aiService.cjs +91 -95
- package/dist/cjs/tlm-ai/tools.cjs +177 -174
- package/dist/cjs/tlm-auth/authController.cjs +80 -123
- package/dist/cjs/tlm-auth/authMiddleware.cjs +25 -30
- package/dist/cjs/tlm-auth/authRoutes.cjs +11 -14
- package/dist/cjs/tlm-log/logController.cjs +171 -116
- package/dist/cjs/tlm-log/logRoutes.cjs +20 -20
- package/dist/cjs/tlm-metric/metricsController.cjs +211 -121
- package/dist/cjs/tlm-metric/metricsRoutes.cjs +23 -20
- package/dist/cjs/tlm-plugin/pluginController.cjs +128 -140
- package/dist/cjs/tlm-plugin/pluginProcess.cjs +89 -94
- package/dist/cjs/tlm-plugin/pluginRoutes.cjs +11 -14
- package/dist/cjs/tlm-plugin/pluginService.cjs +73 -74
- package/dist/cjs/tlm-trace/traceController.cjs +169 -117
- package/dist/cjs/tlm-trace/traceRoutes.cjs +20 -20
- package/dist/cjs/tlm-ui/uiRoutes.cjs +63 -32
- package/dist/cjs/tlm-util/utilController.cjs +68 -70
- package/dist/cjs/tlm-util/utilRoutes.cjs +51 -63
- package/dist/cjs/types/index.cjs +2 -5
- package/dist/cjs/utils/logger.cjs +38 -43
- package/dist/cjs/utils/regexUtils.cjs +22 -22
- package/dist/esm/config/bootConfig.js +6 -0
- package/dist/esm/config/config.js +1 -2
- package/dist/esm/docs/openapi.yaml +158 -4
- package/dist/esm/index.js +9 -8
- package/dist/esm/routesManager.js +6 -10
- package/dist/esm/telemetry/custom-implementations/exporters/InMemoryDbLogExporter.js +47 -8
- package/dist/esm/telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.js +164 -48
- package/dist/esm/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.js +69 -29
- package/dist/esm/telemetry/custom-implementations/instrumentations/logsInstrumentation.js +85 -0
- package/dist/esm/telemetry/custom-implementations/metrics/tsdb/Chunk.js +155 -0
- package/dist/esm/telemetry/custom-implementations/metrics/tsdb/Series.js +164 -0
- package/dist/esm/telemetry/custom-implementations/metrics/tsdb/SeriesRegistry.js +382 -0
- package/dist/esm/telemetry/custom-implementations/metrics/tsdb/types.js +1 -0
- package/dist/esm/telemetry/custom-implementations/metrics/tsdb/utils.js +74 -0
- package/dist/esm/telemetry/custom-implementations/processors/dynamicMultiLogProcessor.js +2 -1
- package/dist/esm/telemetry/custom-implementations/processors/dynamicMultiSpanProcessor.js +1 -1
- package/dist/esm/telemetry/custom-implementations/utils/storagePath.js +33 -0
- package/dist/esm/telemetry/custom-implementations/wrappers.js +5 -2
- package/dist/esm/telemetry/initializeTelemetry.js +27 -69
- package/dist/esm/telemetry/telemetryConfigurator.js +42 -40
- package/dist/esm/telemetry/telemetryRegistry.js +12 -1
- package/dist/esm/tlm-ai/agent.js +5 -3
- package/dist/esm/tlm-ai/aiController.js +3 -3
- package/dist/esm/tlm-ai/aiService.js +6 -2
- package/dist/esm/tlm-ai/tools.js +5 -9
- package/dist/esm/tlm-auth/authController.js +3 -2
- package/dist/esm/tlm-log/logController.js +84 -4
- package/dist/esm/tlm-log/logRoutes.js +5 -2
- package/dist/esm/tlm-metric/metricsController.js +172 -49
- package/dist/esm/tlm-metric/metricsRoutes.js +10 -4
- package/dist/esm/tlm-plugin/pluginController.js +6 -11
- package/dist/esm/tlm-plugin/pluginService.js +2 -4
- package/dist/esm/tlm-trace/traceController.js +102 -16
- package/dist/esm/tlm-trace/traceRoutes.js +5 -2
- package/dist/esm/tlm-ui/uiRoutes.js +5 -5
- package/dist/esm/tlm-util/utilController.js +3 -9
- package/dist/esm/tlm-util/utilRoutes.js +2 -2
- package/dist/types/config/bootConfig.d.ts +4 -0
- package/dist/types/config/config.d.ts +36 -7
- package/dist/types/config/config.types.d.ts +6 -0
- package/dist/types/index.d.ts +2 -3
- package/dist/types/telemetry/custom-implementations/exporters/InMemoryDbLogExporter.d.ts +4 -1
- package/dist/types/telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.d.ts +60 -15
- package/dist/types/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.d.ts +9 -4
- package/dist/types/telemetry/custom-implementations/instrumentations/logsInstrumentation.d.ts +23 -0
- package/dist/types/telemetry/custom-implementations/metrics/tsdb/Chunk.d.ts +49 -0
- package/dist/types/telemetry/custom-implementations/metrics/tsdb/Series.d.ts +67 -0
- package/dist/types/telemetry/custom-implementations/metrics/tsdb/SeriesRegistry.d.ts +69 -0
- package/dist/types/telemetry/custom-implementations/metrics/tsdb/types.d.ts +68 -0
- package/dist/types/telemetry/custom-implementations/metrics/tsdb/utils.d.ts +21 -0
- package/dist/types/telemetry/custom-implementations/processors/dynamicMultiLogProcessor.d.ts +2 -2
- package/dist/types/telemetry/custom-implementations/utils/storagePath.d.ts +12 -0
- package/dist/types/telemetry/custom-implementations/wrappers.d.ts +1 -1
- package/dist/types/telemetry/telemetryConfigurator.d.ts +1 -1
- package/dist/types/telemetry/telemetryRegistry.d.ts +8 -0
- package/dist/types/tlm-ai/agent.d.ts +1 -1
- package/dist/types/tlm-ai/aiService.d.ts +1 -1
- package/dist/types/tlm-log/logController.d.ts +2 -0
- package/dist/types/tlm-metric/metricsController.d.ts +16 -2
- package/dist/types/tlm-trace/traceController.d.ts +3 -1
- package/dist/types/types/index.d.ts +2 -2
- package/dist/ui/assets/{ApiDocsPage-C_VVPPHa.js → ApiDocsPage-BFUrXE5F.js} +2 -2
- package/dist/ui/assets/CollapsibleCard-STA1GVQO.js +1 -0
- package/dist/ui/assets/DevToolsPage-BRSfZqO_.js +1 -0
- package/dist/ui/assets/LandingPage-DzeDy7q7.js +6 -0
- package/dist/ui/assets/LogsPage-BeiFrV2X.js +1 -0
- package/dist/ui/assets/{NotFoundPage-B3quk3P1.js → NotFoundPage-fRNOatbM.js} +1 -1
- package/dist/ui/assets/PluginCreatePage-Ch_RXsdf.js +50 -0
- package/dist/ui/assets/PluginPage-Cl65ZZ_n.js +27 -0
- package/dist/ui/assets/TraceSpansPage-BoK4M5Hh.js +6 -0
- package/dist/ui/assets/VirtualizedListPanel-zcj0v7DL.js +16 -0
- package/dist/ui/assets/alert-BkNVKxJN.js +1133 -0
- package/dist/ui/assets/badge-CN7FeufU.js +1 -0
- package/dist/ui/assets/{chevron-down-CPsvsmqj.js → chevron-down-CG--ounh.js} +1 -1
- package/dist/ui/assets/{chevron-up-Df9jMo1X.js → chevron-up-B6tzMAOm.js} +1 -1
- package/dist/ui/assets/{circle-alert-DOPQPvU8.js → circle-alert-BDF8Tq9y.js} +1 -1
- package/dist/ui/assets/dialog-BrpWNk36.js +15 -0
- package/dist/ui/assets/index-6xOVKwKn.js +305 -0
- package/dist/ui/assets/index-D6f1KjWV.css +1 -0
- package/dist/ui/assets/index-D96rVSkR.js +1 -0
- package/dist/ui/assets/info-99kuqpbx.js +6 -0
- package/dist/ui/assets/{input-Dzvg_ZEZ.js → input-B-01QDg_.js} +1 -1
- package/dist/ui/assets/label-CQLeZjM1.js +1 -0
- package/dist/ui/assets/{loader-circle-CrvlRy5o.js → loader-circle-BoDGk-BO.js} +1 -1
- package/dist/ui/assets/{loginPage-qa4V-B70.js → loginPage-8F4EEd1B.js} +1 -1
- package/dist/ui/assets/metrics-page-D1GxaB_c.css +1 -0
- package/dist/ui/assets/metrics-page-DPtteXqY.js +31 -0
- package/dist/ui/assets/popover-DS_8DYYt.js +11 -0
- package/dist/ui/assets/select-DYjegiXi.js +6 -0
- package/dist/ui/assets/separator-DGsRxIrl.js +6 -0
- package/dist/ui/assets/severityOptions-DEOvJqC9.js +11 -0
- package/dist/ui/assets/square-pen-DPhgYz6O.js +6 -0
- package/dist/ui/assets/switch-Di9NJH2A.js +1 -0
- package/dist/ui/assets/trace-DJq1miYa.js +1 -0
- package/dist/ui/assets/upload-BiLTpCnX.js +11 -0
- package/dist/ui/assets/{utilService-DNyqzwj0.js → utilService-CNZOmadC.js} +1 -1
- package/dist/ui/assets/wand-sparkles-CPoBNFFg.js +6 -0
- package/dist/ui/index.html +2 -2
- package/package.json +44 -48
- package/dist/ui/assets/CollapsibleCard-B3KR_8mL.js +0 -1
- package/dist/ui/assets/DevToolsPage-OyZcDcmw.js +0 -1
- package/dist/ui/assets/LandingPage-CppFBA6K.js +0 -6
- package/dist/ui/assets/LogsPage-9Fq8GArS.js +0 -26
- package/dist/ui/assets/PluginCreatePage-X_aCH4t4.js +0 -50
- package/dist/ui/assets/PluginPage-DMDSihrZ.js +0 -27
- package/dist/ui/assets/alert-jQ9HCPIf.js +0 -1133
- package/dist/ui/assets/badge-CNq0-mH5.js +0 -1
- package/dist/ui/assets/card-DFAwwhN3.js +0 -1
- package/dist/ui/assets/index-BkD6DijD.js +0 -15
- package/dist/ui/assets/index-CERGVYZK.js +0 -292
- package/dist/ui/assets/index-CSIPf9qw.css +0 -1
- package/dist/ui/assets/label-DuVnkZ4q.js +0 -1
- package/dist/ui/assets/select-DhS8YUtJ.js +0 -1
- package/dist/ui/assets/separator-isK4chBP.js +0 -6
- package/dist/ui/assets/severityOptions-O38dSOfk.js +0 -11
- package/dist/ui/assets/switch-Z3mImG9n.js +0 -1
- package/dist/ui/assets/tabs-_77MUUQe.js +0 -16
- package/dist/ui/assets/upload-C1LT4Gkb.js +0 -16
|
@@ -1,105 +1,210 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
});
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.InMemoryDbMetricExporter = void 0;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
7
|
+
const core_1 = require("@opentelemetry/core");
|
|
8
|
+
const wrappers_js_1 = require("../wrappers.cjs");
|
|
9
|
+
const logger_js_1 = __importDefault(require("../../../utils/logger.cjs"));
|
|
10
|
+
const pluginService_js_1 = require("../../../tlm-plugin/pluginService.cjs");
|
|
11
|
+
const utils_js_1 = require("../metrics/tsdb/utils.cjs");
|
|
12
|
+
const SeriesRegistry_js_1 = require("../metrics/tsdb/SeriesRegistry.cjs");
|
|
13
|
+
const storagePath_js_1 = require("../utils/storagePath.cjs");
|
|
14
|
+
const fs_1 = __importDefault(require("fs"));
|
|
15
|
+
/**
|
|
16
|
+
* In-Memory TSDB Metric Exporter
|
|
17
|
+
* Series identified by: scope + metricName + attributes
|
|
18
|
+
*/
|
|
19
|
+
class InMemoryDbMetricExporter extends wrappers_js_1.Enabler {
|
|
20
|
+
static DEFAULT_CONFIG = {
|
|
21
|
+
retentionTimeInSeconds: 3600,
|
|
22
|
+
chunkSize: 120,
|
|
23
|
+
maxChunks: 60
|
|
24
|
+
};
|
|
25
|
+
registry;
|
|
26
|
+
config;
|
|
27
|
+
cachedResource = null;
|
|
28
|
+
_storageFilePath = null;
|
|
29
|
+
_autoSaveInterval = null;
|
|
30
|
+
_storageLogged = false; // Track if we've logged storage info
|
|
31
|
+
get rawDataDB() {
|
|
32
|
+
// For debug/inspection only - metrics are stored in registry chunks
|
|
33
|
+
const stats = this.registry.getStats();
|
|
34
|
+
return stats.totalSamples > 0 ? [`[${stats.totalSamples} samples in registry]`] : [];
|
|
35
|
+
}
|
|
36
|
+
constructor(config) {
|
|
37
|
+
super();
|
|
38
|
+
this.config = { ...InMemoryDbMetricExporter.DEFAULT_CONFIG, ...config };
|
|
39
|
+
this.registry = new SeriesRegistry_js_1.SeriesRegistry(this.config.chunkSize, this.config.maxChunks);
|
|
40
|
+
// Load persisted metrics if disk storage is enabled
|
|
41
|
+
this._storageFilePath = (0, storagePath_js_1.getStoragePath)('metrics');
|
|
42
|
+
if (this._storageFilePath) {
|
|
43
|
+
this._loadMetricsFromDisk();
|
|
44
|
+
this._startAutoSave();
|
|
45
|
+
}
|
|
46
|
+
this._startCleanupJob();
|
|
47
|
+
}
|
|
48
|
+
_loadMetricsFromDisk() {
|
|
49
|
+
if (!this._storageFilePath)
|
|
50
|
+
return;
|
|
51
|
+
try {
|
|
52
|
+
if (fs_1.default.existsSync(this._storageFilePath)) {
|
|
53
|
+
const ndjsonData = fs_1.default.readFileSync(this._storageFilePath, 'utf-8');
|
|
54
|
+
this.registry.deserializeFromNDJSON(ndjsonData);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// Silently fail during boot
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
_startAutoSave() {
|
|
62
|
+
if (!this._storageFilePath)
|
|
63
|
+
return;
|
|
64
|
+
// Save every 30 seconds
|
|
65
|
+
this._autoSaveInterval = setInterval(() => {
|
|
66
|
+
this._saveMetricsToDisk();
|
|
67
|
+
}, 30000);
|
|
68
|
+
}
|
|
69
|
+
_saveMetricsToDisk() {
|
|
70
|
+
if (!this._storageFilePath)
|
|
38
71
|
return;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
setTimeout(() => resultCallback({
|
|
43
|
-
code: _core.ExportResultCode.SUCCESS
|
|
44
|
-
}), 0);
|
|
45
|
-
} catch (error) {
|
|
46
|
-
_logger.default.error('Error exporting metrics\n' + error.message + '\n' + error.stack);
|
|
47
|
-
return resultCallback({
|
|
48
|
-
code: _core.ExportResultCode.FAILED,
|
|
49
|
-
error: new Error('Error exporting metrics\n' + error.message + '\n' + error.stack)
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
shutdown() {
|
|
54
|
-
this._enabled = false;
|
|
55
|
-
this._metrics = new _nedb.default();
|
|
56
|
-
return this.forceFlush();
|
|
57
|
-
}
|
|
58
|
-
forceFlush() {
|
|
59
|
-
return Promise.resolve();
|
|
60
|
-
}
|
|
61
|
-
find(search, callback) {
|
|
62
|
-
this._metrics.find(search, callback);
|
|
63
|
-
}
|
|
64
|
-
reset() {
|
|
65
|
-
this._metrics = new _nedb.default();
|
|
66
|
-
}
|
|
67
|
-
getFinishedMetrics() {
|
|
68
|
-
return this._metrics.getAllData();
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Inserts metrics into the in-memory database.
|
|
72
|
-
* @param metrics - The metrics to insert.
|
|
73
|
-
* @param callback - The callback to execute after insertion.
|
|
74
|
-
*/
|
|
75
|
-
insert(metrics, callback) {
|
|
76
|
-
this._metrics.insert(metrics, callback);
|
|
77
|
-
}
|
|
78
|
-
set retentionTimeInSeconds(retentionTimeInSeconds) {
|
|
79
|
-
this._retentionTimeInSeconds = retentionTimeInSeconds;
|
|
80
|
-
_logger.default.info(`InMemoryDbMetricExporter retention time set to ${this._retentionTimeInSeconds} seconds`);
|
|
81
|
-
}
|
|
82
|
-
get retentionTimeInSeconds() {
|
|
83
|
-
return this._retentionTimeInSeconds;
|
|
84
|
-
}
|
|
85
|
-
_startCleanupJob() {
|
|
86
|
-
const interval = 1000;
|
|
87
|
-
setInterval(() => {
|
|
88
|
-
const expirationDate = new Date(Date.now() - this._retentionTimeInSeconds * 1000);
|
|
89
|
-
this._metrics.remove({
|
|
90
|
-
createdAt: {
|
|
91
|
-
$lt: expirationDate
|
|
72
|
+
try {
|
|
73
|
+
const ndjsonData = this.registry.serializeToNDJSON();
|
|
74
|
+
fs_1.default.writeFileSync(this._storageFilePath, ndjsonData);
|
|
92
75
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}, (err, numRemoved) => {
|
|
96
|
-
if (err) {
|
|
97
|
-
_logger.default.error('Error in TTL cleanup:', err);
|
|
98
|
-
} else if (numRemoved > 0) {
|
|
99
|
-
_logger.default.debug(`TTL cleanup: removed ${numRemoved} expired metrics`);
|
|
76
|
+
catch {
|
|
77
|
+
// Silently fail to avoid logging issues
|
|
100
78
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
79
|
+
}
|
|
80
|
+
export(resourceMetrics, resultCallback) {
|
|
81
|
+
// Log storage info on first export (when logger is ready)
|
|
82
|
+
if (!this._storageLogged) {
|
|
83
|
+
this._storageLogged = true;
|
|
84
|
+
if (this._storageFilePath) {
|
|
85
|
+
logger_js_1.default.info(`[MetricExporter] Disk storage enabled at: ${this._storageFilePath} (auto-save every 30s)`);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
logger_js_1.default.info(`[MetricExporter] Using in-memory storage`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
// Cache resource (unique per exporter instance)
|
|
93
|
+
if (!this.cachedResource) {
|
|
94
|
+
this.cachedResource = resourceMetrics.resource;
|
|
95
|
+
}
|
|
96
|
+
const scopeMetrics = resourceMetrics.scopeMetrics;
|
|
97
|
+
// Broadcast to plugins
|
|
98
|
+
scopeMetrics?.forEach((metric) => {
|
|
99
|
+
pluginService_js_1.pluginService.broadcastMetric(metric);
|
|
100
|
+
});
|
|
101
|
+
// Store if enabled - use new storeScopeMetrics method
|
|
102
|
+
if (this.isEnabled() && scopeMetrics) {
|
|
103
|
+
this.registry.storeScopeMetrics(scopeMetrics);
|
|
104
|
+
}
|
|
105
|
+
setTimeout(() => resultCallback({ code: core_1.ExportResultCode.SUCCESS }), 0);
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
logger_js_1.default.error('Error exporting metrics\n' + error.message + '\n' + error.stack);
|
|
109
|
+
return resultCallback({
|
|
110
|
+
code: core_1.ExportResultCode.FAILED,
|
|
111
|
+
error: new Error('Error exporting metrics\n' + error.message + '\n' + error.stack),
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
shutdown() {
|
|
116
|
+
this._enabled = false;
|
|
117
|
+
// Stop auto-save and save one final time
|
|
118
|
+
if (this._autoSaveInterval) {
|
|
119
|
+
clearInterval(this._autoSaveInterval);
|
|
120
|
+
this._autoSaveInterval = null;
|
|
121
|
+
}
|
|
122
|
+
if (this._storageFilePath) {
|
|
123
|
+
this._saveMetricsToDisk();
|
|
124
|
+
logger_js_1.default.info(`[MetricExporter] Metrics saved to disk at shutdown`);
|
|
125
|
+
}
|
|
126
|
+
this.registry.reset();
|
|
127
|
+
return this.forceFlush();
|
|
128
|
+
}
|
|
129
|
+
reset() {
|
|
130
|
+
// Clear metrics but save empty state to disk
|
|
131
|
+
this.registry.reset();
|
|
132
|
+
if (this._storageFilePath) {
|
|
133
|
+
this._saveMetricsToDisk();
|
|
134
|
+
logger_js_1.default.info(`[MetricExporter] Reset - all metrics cleared and saved to disk`);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
logger_js_1.default.info(`[MetricExporter] Reset - all metrics cleared`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
forceFlush() {
|
|
141
|
+
return Promise.resolve();
|
|
142
|
+
}
|
|
143
|
+
getCachedResource() {
|
|
144
|
+
return this.cachedResource;
|
|
145
|
+
}
|
|
146
|
+
set retentionTimeInSeconds(value) {
|
|
147
|
+
this.config.retentionTimeInSeconds = value;
|
|
148
|
+
logger_js_1.default.info(`Retention time set to ${value} seconds`);
|
|
149
|
+
}
|
|
150
|
+
get retentionTimeInSeconds() {
|
|
151
|
+
return this.config.retentionTimeInSeconds;
|
|
152
|
+
}
|
|
153
|
+
getStats() {
|
|
154
|
+
return this.registry.getStats();
|
|
155
|
+
}
|
|
156
|
+
_startCleanupJob() {
|
|
157
|
+
setInterval(() => {
|
|
158
|
+
const retentionTimeNs = this.config.retentionTimeInSeconds * 1_000_000_000;
|
|
159
|
+
const result = this.registry.evictOldData(retentionTimeNs);
|
|
160
|
+
if (result.evictedChunks > 0 || result.evictedSeries > 0) {
|
|
161
|
+
logger_js_1.default.debug(`Cleanup: evicted ${result.evictedChunks} chunks, ${result.evictedSeries} series`);
|
|
162
|
+
}
|
|
163
|
+
}, 5000);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Find metrics by scope+metric queries with filters
|
|
167
|
+
* Supports both raw and otel formats
|
|
168
|
+
*/
|
|
169
|
+
find(request) {
|
|
170
|
+
const format = request.format || 'raw';
|
|
171
|
+
// Get raw results from registry using new unified query method
|
|
172
|
+
const rawResults = this.registry.query(request.scopeMetrics, request.from, request.to);
|
|
173
|
+
// Convert format if needed
|
|
174
|
+
if (format === 'otel') {
|
|
175
|
+
return { results: (0, utils_js_1.rawToOtel)(rawResults) };
|
|
176
|
+
}
|
|
177
|
+
return { results: rawResults };
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Export all metrics to NDJSON format (one chunk per line)
|
|
181
|
+
*/
|
|
182
|
+
exportToNDJSON() {
|
|
183
|
+
return this.registry.serializeToNDJSON();
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Import metrics from NDJSON format
|
|
187
|
+
*/
|
|
188
|
+
importFromNDJSON(ndjsonData) {
|
|
189
|
+
this.registry.deserializeFromNDJSON(ndjsonData);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Insert metrics in OpenTelemetry (OTEL) format directly into the registry
|
|
193
|
+
* @param scopeMetrics Array of ScopeMetrics (OTEL format)
|
|
194
|
+
*/
|
|
195
|
+
insertOtel(scopeMetrics) {
|
|
196
|
+
// Store only in registry (chunks) - no duplication
|
|
197
|
+
if (this.isEnabled()) {
|
|
198
|
+
this.registry.storeScopeMetrics(scopeMetrics);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Insert metrics in raw format (MetricQueryResult[]), converts to OTEL and delegates to insertOtel
|
|
203
|
+
* @param rawScopeMetrics Array of MetricQueryResult (raw format)
|
|
204
|
+
*/
|
|
205
|
+
insertRaw(rawScopeMetrics) {
|
|
206
|
+
const otelScopeMetrics = (0, utils_js_1.rawToOtel)(rawScopeMetrics);
|
|
207
|
+
this.insertOtel(otelScopeMetrics);
|
|
208
|
+
}
|
|
104
209
|
}
|
|
105
|
-
exports.InMemoryDbMetricExporter = InMemoryDbMetricExporter;
|
|
210
|
+
exports.InMemoryDbMetricExporter = InMemoryDbMetricExporter;
|
|
@@ -1,123 +1,159 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
});
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.InMemoryDbSpanExporter = void 0;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class InMemoryDbSpanExporter extends
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
this._baseUrl = baseUrl;
|
|
29
|
-
}
|
|
30
|
-
set retentionTimeInSeconds(retentionTimeInSeconds) {
|
|
31
|
-
this._retentionTimeInSeconds = retentionTimeInSeconds;
|
|
32
|
-
_logger.default.info(`InMemoryDbSpanExporter retention time set to ${this._retentionTimeInSeconds} seconds`);
|
|
33
|
-
}
|
|
34
|
-
get retentionTimeInSeconds() {
|
|
35
|
-
return this._retentionTimeInSeconds;
|
|
36
|
-
}
|
|
37
|
-
export(readableSpans, resultCallback) {
|
|
38
|
-
_logger.default.debug('InMemoryDbSpanExporter.export called with spans: ', readableSpans.length);
|
|
39
|
-
try {
|
|
40
|
-
// Prepare spans to be inserted into the in-memory database (remove circular references and convert to nested objects)
|
|
41
|
-
const cleanSpans = readableSpans.map(nestedSpan => (0, _circular.removeCircularRefs)(nestedSpan)) // to avoid JSON parsing error
|
|
42
|
-
.map(span => (0, _circular.applyNesting)(span)) // to avoid dot notation in keys (neDB does not support dot notation in keys)
|
|
43
|
-
.filter(span => {
|
|
44
|
-
const target = span?.attributes?.http?.target;
|
|
45
|
-
// Exclude spans where target includes 'telemetry' but NOT 'telemetry/utils/generate-log' or 'telemetry/utils/generate-wait'
|
|
46
|
-
if (target && target.includes(this._baseUrl)) {
|
|
47
|
-
return target.includes("generate");
|
|
48
|
-
}
|
|
49
|
-
return true;
|
|
50
|
-
});
|
|
51
|
-
cleanSpans.forEach(span => {
|
|
52
|
-
_pluginService.pluginService.broadcastTrace(span);
|
|
53
|
-
});
|
|
54
|
-
//
|
|
55
|
-
if (this.isEnabled()) {
|
|
56
|
-
// Insert spans into the in-memory database
|
|
57
|
-
this._spans.insert(cleanSpans, (err, _newDoc) => {
|
|
58
|
-
if (err) {
|
|
59
|
-
_logger.default.error(err);
|
|
7
|
+
const core_1 = require("@opentelemetry/core");
|
|
8
|
+
const nedb_1 = __importDefault(require("@seald-io/nedb"));
|
|
9
|
+
const logger_js_1 = __importDefault(require("../../../utils/logger.cjs"));
|
|
10
|
+
const circular_js_1 = require("../utils/circular.cjs");
|
|
11
|
+
const wrappers_js_1 = require("../wrappers.cjs");
|
|
12
|
+
const pluginService_js_1 = require("../../../tlm-plugin/pluginService.cjs");
|
|
13
|
+
const storagePath_js_1 = require("../utils/storagePath.cjs");
|
|
14
|
+
class InMemoryDbSpanExporter extends wrappers_js_1.Enabler {
|
|
15
|
+
_spans = null;
|
|
16
|
+
_retentionTimeInSeconds;
|
|
17
|
+
_storagePath = null;
|
|
18
|
+
_initialized = false;
|
|
19
|
+
constructor(retentionTimeInSeconds = 3600) {
|
|
20
|
+
super();
|
|
21
|
+
this._retentionTimeInSeconds = retentionTimeInSeconds;
|
|
22
|
+
this._storagePath = (0, storagePath_js_1.getStoragePath)('traces');
|
|
23
|
+
this._startCleanupJob();
|
|
24
|
+
}
|
|
25
|
+
;
|
|
26
|
+
_ensureInitialized() {
|
|
27
|
+
if (this._initialized)
|
|
60
28
|
return;
|
|
61
|
-
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
code: _core.ExportResultCode.FAILED,
|
|
71
|
-
error: new Error('Error exporting spans\n' + error.message + '\n' + error.stack)
|
|
72
|
-
});
|
|
29
|
+
this._initialized = true;
|
|
30
|
+
this._spans = new nedb_1.default(this._storagePath ? { filename: this._storagePath, timestampData: true, autoload: true } : { timestampData: true });
|
|
31
|
+
this._spans.ensureIndex({ fieldName: 'createdAt' });
|
|
32
|
+
if (this._storagePath) {
|
|
33
|
+
logger_js_1.default.info(`[SpanExporter] Disk storage enabled at: ${this._storagePath}`);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
logger_js_1.default.info(`[SpanExporter] Using in-memory storage`);
|
|
37
|
+
}
|
|
73
38
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const interval = 1000;
|
|
105
|
-
setInterval(() => {
|
|
106
|
-
const expirationDate = new Date(Date.now() - this._retentionTimeInSeconds * 1000);
|
|
107
|
-
this._spans.remove({
|
|
108
|
-
createdAt: {
|
|
109
|
-
$lt: expirationDate
|
|
39
|
+
set retentionTimeInSeconds(retentionTimeInSeconds) {
|
|
40
|
+
this._retentionTimeInSeconds = retentionTimeInSeconds;
|
|
41
|
+
logger_js_1.default.info(`InMemoryDbSpanExporter retention time set to ${this._retentionTimeInSeconds} seconds`);
|
|
42
|
+
}
|
|
43
|
+
get retentionTimeInSeconds() {
|
|
44
|
+
return this._retentionTimeInSeconds;
|
|
45
|
+
}
|
|
46
|
+
export(readableSpans, resultCallback) {
|
|
47
|
+
this._ensureInitialized();
|
|
48
|
+
logger_js_1.default.debug('InMemoryDbSpanExporter.export called with spans: ', readableSpans.length);
|
|
49
|
+
try {
|
|
50
|
+
// Prepare spans to be inserted into the in-memory database (remove circular references and convert to nested objects)
|
|
51
|
+
const cleanSpans = readableSpans
|
|
52
|
+
.map(nestedSpan => (0, circular_js_1.removeCircularRefs)(nestedSpan)) // to avoid JSON parsing error
|
|
53
|
+
.map(span => (0, circular_js_1.applyNesting)(span)); // to avoid dot notation in keys (neDB does not support dot notation in keys)
|
|
54
|
+
cleanSpans.forEach(span => {
|
|
55
|
+
pluginService_js_1.pluginService.broadcastTrace(span);
|
|
56
|
+
});
|
|
57
|
+
if (this.isEnabled()) {
|
|
58
|
+
// Insert spans into the in-memory database
|
|
59
|
+
if (this._spans) {
|
|
60
|
+
this._spans.insert(cleanSpans, (err, _newDoc) => {
|
|
61
|
+
if (err) {
|
|
62
|
+
logger_js_1.default.error(err);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return resultCallback({ code: core_1.ExportResultCode.SUCCESS });
|
|
110
69
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
70
|
+
catch (error) {
|
|
71
|
+
logger_js_1.default.error('Error exporting spans\n' + error.message + '\n' + error.stack);
|
|
72
|
+
return resultCallback({
|
|
73
|
+
code: core_1.ExportResultCode.FAILED,
|
|
74
|
+
error: new Error('Error exporting spans\n' + error.message + '\n' + error.stack),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
;
|
|
79
|
+
shutdown() {
|
|
80
|
+
this._spans = null;
|
|
81
|
+
return this.forceFlush();
|
|
82
|
+
}
|
|
83
|
+
;
|
|
84
|
+
reset() {
|
|
85
|
+
this._ensureInitialized();
|
|
86
|
+
// Remove all spans from database but keep persistence enabled
|
|
87
|
+
this._spans.remove({}, { multi: true }, (err) => {
|
|
88
|
+
if (err) {
|
|
89
|
+
logger_js_1.default.error(`[SpanExporter] Error during reset: ${err.message}`);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
logger_js_1.default.info(`[SpanExporter] Reset - all spans cleared`);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Exports any pending spans in the exporter
|
|
98
|
+
*/
|
|
99
|
+
forceFlush() {
|
|
100
|
+
return Promise.resolve();
|
|
101
|
+
}
|
|
102
|
+
;
|
|
103
|
+
async find(findConfig) {
|
|
104
|
+
this._ensureInitialized();
|
|
105
|
+
const { query, limit, sortOrder } = findConfig;
|
|
106
|
+
const effectiveSortOrder = sortOrder || { timestamp: -1 };
|
|
107
|
+
const docs = await new Promise((resolve, reject) => {
|
|
108
|
+
let query_exec = this._spans.find(query)
|
|
109
|
+
.sort(effectiveSortOrder);
|
|
110
|
+
// Only apply limit if provided
|
|
111
|
+
if (limit !== undefined) {
|
|
112
|
+
query_exec = query_exec.limit(limit);
|
|
113
|
+
}
|
|
114
|
+
query_exec.exec((err, docs) => {
|
|
115
|
+
if (err)
|
|
116
|
+
reject(err);
|
|
117
|
+
else
|
|
118
|
+
resolve(docs);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
return docs;
|
|
122
|
+
}
|
|
123
|
+
getFinishedSpans() {
|
|
124
|
+
this._ensureInitialized();
|
|
125
|
+
if (!this._spans)
|
|
126
|
+
return [];
|
|
127
|
+
return this._spans.getAllData();
|
|
128
|
+
}
|
|
129
|
+
;
|
|
130
|
+
/**
|
|
131
|
+
* Inserts spans into the in-memory database.
|
|
132
|
+
* @param spans - The spans to insert.
|
|
133
|
+
* @param callback - The callback to execute after insertion.
|
|
134
|
+
*/
|
|
135
|
+
insert(spans, callback) {
|
|
136
|
+
this._ensureInitialized();
|
|
137
|
+
if (!this._spans) {
|
|
138
|
+
return callback(new Error('Spans database not initialized'), []);
|
|
118
139
|
}
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
|
|
140
|
+
this._spans.insert(spans, callback);
|
|
141
|
+
}
|
|
142
|
+
_startCleanupJob() {
|
|
143
|
+
const interval = 1000;
|
|
144
|
+
setInterval(() => {
|
|
145
|
+
if (!this._spans)
|
|
146
|
+
return; // Safety check - not initialized yet
|
|
147
|
+
const expirationDate = new Date(Date.now() - this._retentionTimeInSeconds * 1000);
|
|
148
|
+
this._spans.remove({ createdAt: { $lt: expirationDate } }, { multi: true }, (err, numRemoved) => {
|
|
149
|
+
if (err) {
|
|
150
|
+
logger_js_1.default.error('Error in TTL cleanup:', err);
|
|
151
|
+
}
|
|
152
|
+
else if (numRemoved > 0) {
|
|
153
|
+
logger_js_1.default.debug(`TTL cleanup: removed ${numRemoved} expired spans`);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}, interval);
|
|
157
|
+
}
|
|
122
158
|
}
|
|
123
|
-
exports.InMemoryDbSpanExporter = InMemoryDbSpanExporter;
|
|
159
|
+
exports.InMemoryDbSpanExporter = InMemoryDbSpanExporter;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.LogsInstrumentation = void 0;
|
|
7
|
+
const instrumentation_1 = require("@opentelemetry/instrumentation");
|
|
8
|
+
const api_logs_1 = require("@opentelemetry/api-logs");
|
|
9
|
+
const util_1 = __importDefault(require("util"));
|
|
10
|
+
const telemetryRegistry_js_1 = require("../../telemetryRegistry.cjs");
|
|
11
|
+
class LogsInstrumentation extends instrumentation_1.InstrumentationBase {
|
|
12
|
+
_loggerProvider;
|
|
13
|
+
_otelLogger;
|
|
14
|
+
constructor(config = {}) {
|
|
15
|
+
super('@oas-telemetry/logs-instrumentation', '1.0.0', config);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* No-op: this instrumentation does not patch modules loaded via require().
|
|
19
|
+
*/
|
|
20
|
+
init() {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Called by the SDK when the LoggerProvider is available.
|
|
25
|
+
* This is the correct way for an instrumentation to receive a logger provider.
|
|
26
|
+
*/
|
|
27
|
+
setLoggerProvider(provider) {
|
|
28
|
+
this._loggerProvider = provider;
|
|
29
|
+
this._otelLogger = provider.getLogger(this.instrumentationName);
|
|
30
|
+
// If already enabled, re-apply patches with the new logger provider.
|
|
31
|
+
if (this.isEnabled()) {
|
|
32
|
+
this._unpatchConsole();
|
|
33
|
+
this._patchConsole();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Called by the SDK after all providers have been registered.
|
|
38
|
+
*/
|
|
39
|
+
enable() {
|
|
40
|
+
super.enable();
|
|
41
|
+
// Fallback: if no logger provider has been set yet, we do nothing.
|
|
42
|
+
if (!this._loggerProvider) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
this._patchConsole();
|
|
46
|
+
}
|
|
47
|
+
disable() {
|
|
48
|
+
super.disable();
|
|
49
|
+
this._unpatchConsole();
|
|
50
|
+
}
|
|
51
|
+
_patchConsole() {
|
|
52
|
+
if (!this._otelLogger)
|
|
53
|
+
return;
|
|
54
|
+
Object.keys(telemetryRegistry_js_1.originalConsoleMethods).forEach((method) => {
|
|
55
|
+
const original = telemetryRegistry_js_1.originalConsoleMethods[method];
|
|
56
|
+
console[method] = (...args) => {
|
|
57
|
+
const { number, text } = getSeverityForMethod(method);
|
|
58
|
+
this._otelLogger.emit({
|
|
59
|
+
severityNumber: number,
|
|
60
|
+
severityText: text,
|
|
61
|
+
body: util_1.default.format(...args),
|
|
62
|
+
attributes: {
|
|
63
|
+
source: `console.${method}`,
|
|
64
|
+
library: this.instrumentationName,
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
original(...args);
|
|
68
|
+
};
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
_unpatchConsole() {
|
|
72
|
+
Object.keys(telemetryRegistry_js_1.originalConsoleMethods).forEach((method) => {
|
|
73
|
+
console[method] = telemetryRegistry_js_1.originalConsoleMethods[method];
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
exports.LogsInstrumentation = LogsInstrumentation;
|
|
78
|
+
function getSeverityForMethod(method) {
|
|
79
|
+
switch (method) {
|
|
80
|
+
case "log":
|
|
81
|
+
case "info":
|
|
82
|
+
return { number: api_logs_1.SeverityNumber.INFO, text: "INFO" };
|
|
83
|
+
case "debug":
|
|
84
|
+
return { number: api_logs_1.SeverityNumber.DEBUG, text: "DEBUG" };
|
|
85
|
+
case "warn":
|
|
86
|
+
return { number: api_logs_1.SeverityNumber.WARN, text: "WARN" };
|
|
87
|
+
case "error":
|
|
88
|
+
return { number: api_logs_1.SeverityNumber.ERROR, text: "ERROR" };
|
|
89
|
+
default:
|
|
90
|
+
return { number: api_logs_1.SeverityNumber.INFO, text: "INFO" };
|
|
91
|
+
}
|
|
92
|
+
}
|