@oas-tools/oas-telemetry 0.8.0-alpha.0 → 0.8.0-alpha.2
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 +7 -12
- package/dist/cjs/config/bootConfig.cjs +1 -4
- package/dist/cjs/config/config.cjs +8 -0
- package/dist/cjs/docs/openapi.yaml +12 -12
- package/dist/cjs/telemetry/custom-implementations/exporters/DiskLogExporter.cjs +121 -0
- package/dist/cjs/telemetry/custom-implementations/exporters/DiskMetricExporter.cjs +101 -0
- package/dist/cjs/telemetry/custom-implementations/exporters/DiskTraceExporter.cjs +103 -0
- package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbLogExporter.cjs +14 -19
- package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.cjs +26 -80
- package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.cjs +25 -23
- package/dist/cjs/telemetry/custom-implementations/exporters/MultiMetricExporter.cjs +57 -0
- package/dist/cjs/telemetry/custom-implementations/metrics/tsdb/SeriesRegistry.cjs +17 -14
- package/dist/cjs/telemetry/custom-implementations/wrappers.cjs +72 -4
- package/dist/cjs/telemetry/persistence/DiskImporter.cjs +85 -0
- package/dist/cjs/telemetry/persistence/DiskUtils.cjs +61 -0
- package/dist/cjs/telemetry/persistence/DiskWriter.cjs +66 -0
- package/dist/cjs/telemetry/telemetryConfigurator.cjs +74 -5
- package/dist/cjs/tlm-log/logController.cjs +26 -62
- package/dist/cjs/tlm-log/logRoutes.cjs +1 -2
- package/dist/cjs/tlm-log/logService.cjs +29 -0
- package/dist/cjs/tlm-metric/metricsController.cjs +39 -97
- package/dist/cjs/tlm-metric/metricsRoutes.cjs +1 -2
- package/dist/cjs/tlm-metric/metricsService.cjs +26 -0
- package/dist/cjs/tlm-trace/traceController.cjs +32 -67
- package/dist/cjs/tlm-trace/traceRoutes.cjs +1 -2
- package/dist/cjs/tlm-trace/traceService.cjs +29 -0
- package/dist/esm/config/bootConfig.js +1 -4
- package/dist/esm/config/config.js +8 -0
- package/dist/esm/docs/openapi.yaml +12 -12
- package/dist/esm/telemetry/custom-implementations/exporters/DiskLogExporter.js +114 -0
- package/dist/esm/telemetry/custom-implementations/exporters/DiskMetricExporter.js +94 -0
- package/dist/esm/telemetry/custom-implementations/exporters/DiskTraceExporter.js +96 -0
- package/dist/esm/telemetry/custom-implementations/exporters/InMemoryDbLogExporter.js +14 -19
- package/dist/esm/telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.js +26 -80
- package/dist/esm/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.js +25 -23
- package/dist/esm/telemetry/custom-implementations/exporters/MultiMetricExporter.js +53 -0
- package/dist/esm/telemetry/custom-implementations/metrics/tsdb/SeriesRegistry.js +17 -14
- package/dist/esm/telemetry/custom-implementations/wrappers.js +72 -4
- package/dist/esm/telemetry/persistence/DiskImporter.js +78 -0
- package/dist/esm/telemetry/persistence/DiskUtils.js +51 -0
- package/dist/esm/telemetry/persistence/DiskWriter.js +59 -0
- package/dist/esm/telemetry/telemetryConfigurator.js +74 -5
- package/dist/esm/tlm-log/logController.js +26 -62
- package/dist/esm/tlm-log/logRoutes.js +2 -3
- package/dist/esm/tlm-log/logService.js +25 -0
- package/dist/esm/tlm-metric/metricsController.js +38 -95
- package/dist/esm/tlm-metric/metricsRoutes.js +2 -3
- package/dist/esm/tlm-metric/metricsService.js +22 -0
- package/dist/esm/tlm-trace/traceController.js +32 -67
- package/dist/esm/tlm-trace/traceRoutes.js +2 -3
- package/dist/esm/tlm-trace/traceService.js +25 -0
- package/dist/types/config/bootConfig.d.ts +0 -1
- package/dist/types/config/config.d.ts +12 -0
- package/dist/types/config/config.types.d.ts +1 -0
- package/dist/types/telemetry/custom-implementations/exporters/DiskLogExporter.d.ts +24 -0
- package/dist/types/telemetry/custom-implementations/exporters/DiskMetricExporter.d.ts +23 -0
- package/dist/types/telemetry/custom-implementations/exporters/DiskTraceExporter.d.ts +23 -0
- package/dist/types/telemetry/custom-implementations/exporters/InMemoryDbLogExporter.d.ts +1 -1
- package/dist/types/telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.d.ts +7 -10
- package/dist/types/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.d.ts +1 -1
- package/dist/types/telemetry/custom-implementations/exporters/MultiMetricExporter.d.ts +9 -0
- package/dist/types/telemetry/custom-implementations/metrics/tsdb/SeriesRegistry.d.ts +6 -6
- package/dist/types/telemetry/custom-implementations/wrappers.d.ts +1 -0
- package/dist/types/telemetry/persistence/DiskImporter.d.ts +17 -0
- package/dist/types/telemetry/persistence/DiskUtils.d.ts +11 -0
- package/dist/types/telemetry/persistence/DiskWriter.d.ts +21 -0
- package/dist/types/tlm-log/logService.d.ts +4 -0
- package/dist/types/tlm-metric/metricsController.d.ts +0 -5
- package/dist/types/tlm-metric/metricsService.d.ts +6 -0
- package/dist/types/tlm-trace/traceController.d.ts +6 -6
- package/dist/types/tlm-trace/traceService.d.ts +4 -0
- package/dist/ui/assets/{ApiDocsPage-BFUrXE5F.js → ApiDocsPage-BAZE-zL3.js} +1 -1
- package/dist/ui/assets/{CollapsibleCard-STA1GVQO.js → CollapsibleCard-Dyp3VGPU.js} +1 -1
- package/dist/ui/assets/{DevToolsPage-BRSfZqO_.js → DevToolsPage-D6WvJgfI.js} +1 -1
- package/dist/ui/assets/{LandingPage-DzeDy7q7.js → LandingPage-DgZmfiO1.js} +1 -1
- package/dist/ui/assets/{LogsPage-BeiFrV2X.js → LogsPage-CcCa1wCS.js} +1 -1
- package/dist/ui/assets/{NotFoundPage-fRNOatbM.js → NotFoundPage-D-XZVon_.js} +1 -1
- package/dist/ui/assets/{PluginCreatePage-Ch_RXsdf.js → PluginCreatePage-CSlmgA5Z.js} +1 -1
- package/dist/ui/assets/{PluginPage-Cl65ZZ_n.js → PluginPage-CUFe2cVr.js} +1 -1
- package/dist/ui/assets/TraceSpansPage-BqwuoD4T.js +6 -0
- package/dist/ui/assets/{VirtualizedListPanel-zcj0v7DL.js → VirtualizedListPanel-C0oG8Dkc.js} +1 -1
- package/dist/ui/assets/{alert-BkNVKxJN.js → alert-CvCDsfT9.js} +1 -1
- package/dist/ui/assets/{badge-CN7FeufU.js → badge-iri4YLiT.js} +1 -1
- package/dist/ui/assets/{chevron-down-CG--ounh.js → chevron-down-Dze6JQWQ.js} +1 -1
- package/dist/ui/assets/{chevron-up-B6tzMAOm.js → chevron-up-BOgWUK-m.js} +1 -1
- package/dist/ui/assets/{circle-alert-BDF8Tq9y.js → circle-alert-DNqNwGYC.js} +1 -1
- package/dist/ui/assets/{dialog-BrpWNk36.js → dialog-BbBXMqd9.js} +1 -1
- package/dist/ui/assets/{index-6xOVKwKn.js → index-Bak7-IjV.js} +2 -2
- package/dist/ui/assets/{index-D96rVSkR.js → index-gwOdQdDr.js} +1 -1
- package/dist/ui/assets/{info-99kuqpbx.js → info-CEPnfukj.js} +1 -1
- package/dist/ui/assets/{input-B-01QDg_.js → input-DIJScMC5.js} +1 -1
- package/dist/ui/assets/{label-CQLeZjM1.js → label-C-VVLc4C.js} +1 -1
- package/dist/ui/assets/{loader-circle-BoDGk-BO.js → loader-circle-Cd1Edf_o.js} +1 -1
- package/dist/ui/assets/{loginPage-8F4EEd1B.js → loginPage-CwnoByhF.js} +1 -1
- package/dist/ui/assets/metrics-page-BY5ijZjD.js +31 -0
- package/dist/ui/assets/{popover-DS_8DYYt.js → popover-2XBYXBkN.js} +2 -2
- package/dist/ui/assets/{select-DYjegiXi.js → select-CNQVyoVV.js} +1 -1
- package/dist/ui/assets/{separator-DGsRxIrl.js → separator-jwB4ekGy.js} +1 -1
- package/dist/ui/assets/severityOptions-w0EiAFxM.js +11 -0
- package/dist/ui/assets/{square-pen-DPhgYz6O.js → square-pen-BkIfvdtf.js} +1 -1
- package/dist/ui/assets/{switch-Di9NJH2A.js → switch-Dgtlsp4F.js} +1 -1
- package/dist/ui/assets/{upload-BiLTpCnX.js → upload-BE0Mp5Zk.js} +1 -1
- package/dist/ui/assets/{utilService-CNZOmadC.js → utilService-BN13pIJg.js} +1 -1
- package/dist/ui/assets/{wand-sparkles-CPoBNFFg.js → wand-sparkles-Df82iOpL.js} +1 -1
- package/dist/ui/index.html +1 -1
- package/package.json +2 -3
- package/dist/cjs/telemetry/custom-implementations/utils/storagePath.cjs +0 -39
- package/dist/esm/telemetry/custom-implementations/utils/storagePath.js +0 -33
- package/dist/types/telemetry/custom-implementations/utils/storagePath.d.ts +0 -12
- package/dist/ui/assets/TraceSpansPage-BoK4M5Hh.js +0 -6
- package/dist/ui/assets/metrics-page-DPtteXqY.js +0 -31
- package/dist/ui/assets/severityOptions-DEOvJqC9.js +0 -11
package/.env.example
CHANGED
|
@@ -10,7 +10,7 @@ OASTLM_BOOT_ENV=
|
|
|
10
10
|
OASTLM_BOOT_MODULE_DISABLED=
|
|
11
11
|
# Logging level for the boot process | Possible values: "DEBUG", "INFO", "WARNING", "ERROR", "NONE" | Default: "INFO"
|
|
12
12
|
OASTLM_BOOT_LOG_LEVEL=
|
|
13
|
-
# The name
|
|
13
|
+
# The service name | Default: "UNKNOWN"
|
|
14
14
|
OASTLM_BOOT_SERVICE_NAME=
|
|
15
15
|
# Base URL path for telemetry endpoints (must be set at boot time, cannot be changed at runtime) | Default: "/oas-telemetry"
|
|
16
16
|
OASTLM_BOOT_BASE_URL=
|
|
@@ -23,17 +23,6 @@ OASTLM_BOOT_AUTOINSTRUMENTATIONS_NODE_DISABLED=
|
|
|
23
23
|
# Disable logs instrumentation auto-registration | Possible values: "true", "false" | Default: "false"
|
|
24
24
|
OASTLM_BOOT_AUTOINSTRUMENTATIONS_LOGS_DISABLED=
|
|
25
25
|
|
|
26
|
-
# BOOT-STORAGE CONFIGURATION ------------------------------------------------
|
|
27
|
-
# Storage configuration for telemetry data (set at startup, cannot be changed at runtime).
|
|
28
|
-
# If empty or not set: telemetry stored IN-MEMORY (default, lost on restart)
|
|
29
|
-
# If set: telemetry persisted to DISK at specified path
|
|
30
|
-
# Examples:
|
|
31
|
-
# OASTLM_BOOT_STORAGE_PATH= # empty = in-memory
|
|
32
|
-
# OASTLM_BOOT_STORAGE_PATH=data/telemetry # disk storage
|
|
33
|
-
# OASTLM_BOOT_STORAGE_PATH=/var/lib/telemetry # absolute path
|
|
34
|
-
# Default: empty (in-memory)
|
|
35
|
-
OASTLM_BOOT_STORAGE_PATH=
|
|
36
|
-
|
|
37
26
|
|
|
38
27
|
# CONFIGURATION --------------------------------------------------------
|
|
39
28
|
# These variables are used to override the configuration when oasTelemetry(config) is called.
|
|
@@ -42,6 +31,12 @@ OASTLM_BOOT_STORAGE_PATH=
|
|
|
42
31
|
# Specification file name | Default: null
|
|
43
32
|
OASTLM_CONFIG_GENERAL_SPEC_FILE_NAME=
|
|
44
33
|
|
|
34
|
+
# Storage path: empty string = in-memory, else = disk storage at specified path | Default: empty string (in-memory)
|
|
35
|
+
OASTLM_CONFIG_STORAGE_PATH=
|
|
36
|
+
# Optional override for startup disk import behavior
|
|
37
|
+
# Priority: OASTLM_CONFIG_STORAGE_LOAD_FROM_START > userConfig.storage.loadFromStart > defaultConfig
|
|
38
|
+
OASTLM_CONFIG_STORAGE_LOAD_FROM_START=
|
|
39
|
+
|
|
45
40
|
|
|
46
41
|
# Enable authentication | Possible values: "true", "false" | Default: "false"
|
|
47
42
|
OASTLM_CONFIG_AUTH_ENABLED=
|
|
@@ -5,7 +5,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.bootEnvVariables = void 0;
|
|
7
7
|
const dotenv_1 = __importDefault(require("dotenv"));
|
|
8
|
-
const crypto_1 = require("crypto");
|
|
9
8
|
if (process.env.NODE_ENV !== 'test') {
|
|
10
9
|
dotenv_1.default.config();
|
|
11
10
|
}
|
|
@@ -15,11 +14,9 @@ exports.bootEnvVariables = {
|
|
|
15
14
|
OASTLM_BOOT_ENV: process.env.OASTLM_BOOT_ENV || process.env.NODE_ENV || 'production',
|
|
16
15
|
OASTLM_BOOT_MODULE_DISABLED: process.env.OASTLM_BOOT_MODULE_DISABLED === 'true',
|
|
17
16
|
OASTLM_BOOT_LOG_LEVEL: process.env.OASTLM_BOOT_LOG_LEVEL || 'INFO',
|
|
18
|
-
OASTLM_BOOT_SERVICE_NAME: process.env.OASTLM_BOOT_SERVICE_NAME ||
|
|
17
|
+
OASTLM_BOOT_SERVICE_NAME: process.env.OASTLM_BOOT_SERVICE_NAME || 'UNKNOWN',
|
|
19
18
|
OASTLM_BOOT_BASE_URL: process.env.OASTLM_BOOT_BASE_URL || '/oas-telemetry',
|
|
20
19
|
OASTLM_BOOT_AUTOINSTRUMENTATIONS_NODE_DISABLED: process.env.OASTLM_BOOT_AUTOINSTRUMENTATIONS_NODE_DISABLED == 'true',
|
|
21
20
|
OASTLM_BOOT_AUTOINSTRUMENTATIONS_LOGS_DISABLED: process.env.OASTLM_BOOT_AUTOINSTRUMENTATIONS_LOGS_DISABLED == 'true',
|
|
22
|
-
// Storage path: empty string = in-memory, else = disk storage at specified path
|
|
23
|
-
OASTLM_BOOT_STORAGE_PATH: process.env.OASTLM_BOOT_STORAGE_PATH || '',
|
|
24
21
|
};
|
|
25
22
|
// REMEMBER TO UPDATE THE .env.example FILE WITH ANY NEW BOOT VARIABLE ADDED HERE.
|
|
@@ -14,6 +14,10 @@ const loadEnv = () => {
|
|
|
14
14
|
specFileName: getParsedEnvVar("OASTLM_CONFIG_GENERAL_SPEC_FILE_NAME"),
|
|
15
15
|
// spec Not settable via env
|
|
16
16
|
},
|
|
17
|
+
storage: {
|
|
18
|
+
path: getParsedEnvVar("OASTLM_CONFIG_STORAGE_PATH"),
|
|
19
|
+
loadFromStart: getParsedEnvVar("OASTLM_CONFIG_STORAGE_LOAD_FROM_START", (v) => v === "true"),
|
|
20
|
+
},
|
|
17
21
|
auth: {
|
|
18
22
|
enabled: getParsedEnvVar("OASTLM_CONFIG_AUTH_ENABLED", (v) => v === "true"),
|
|
19
23
|
password: getParsedEnvVar("OASTLM_CONFIG_AUTH_PASSWORD"),
|
|
@@ -64,6 +68,10 @@ exports.defaultConfig = {
|
|
|
64
68
|
spec: null, // e.g. JSON.stringify(oasSpec) or null if not provided,
|
|
65
69
|
uiPath: "/oas-telemetry-ui", // path to the UI, e.g. "/oas-telemetry-ui" WARN: This must match the UI package's App.tsx "oas-telemetry-ui" path
|
|
66
70
|
},
|
|
71
|
+
storage: {
|
|
72
|
+
path: null, // Optional disk persistence directory.
|
|
73
|
+
loadFromStart: true, // If true, import persisted telemetry into memory at startup.
|
|
74
|
+
},
|
|
67
75
|
auth: {
|
|
68
76
|
enabled: false,
|
|
69
77
|
password: "oas-telemetry-password",
|
|
@@ -331,12 +331,12 @@ paths:
|
|
|
331
331
|
tags:
|
|
332
332
|
- traces
|
|
333
333
|
summary: Export collected traces
|
|
334
|
-
description: Export all collected traces in
|
|
334
|
+
description: Export all collected traces in line-delimited JSON format
|
|
335
335
|
responses:
|
|
336
336
|
'200':
|
|
337
337
|
description: Traces exported successfully
|
|
338
338
|
content:
|
|
339
|
-
application/
|
|
339
|
+
application/json:
|
|
340
340
|
schema:
|
|
341
341
|
type: string
|
|
342
342
|
|
|
@@ -345,11 +345,11 @@ paths:
|
|
|
345
345
|
tags:
|
|
346
346
|
- traces
|
|
347
347
|
summary: Import traces
|
|
348
|
-
description: Import traces from
|
|
348
|
+
description: Import traces from line-delimited JSON format
|
|
349
349
|
requestBody:
|
|
350
350
|
required: true
|
|
351
351
|
content:
|
|
352
|
-
application/
|
|
352
|
+
application/json:
|
|
353
353
|
schema:
|
|
354
354
|
type: string
|
|
355
355
|
responses:
|
|
@@ -591,12 +591,12 @@ paths:
|
|
|
591
591
|
tags:
|
|
592
592
|
- metrics
|
|
593
593
|
summary: Export collected metrics
|
|
594
|
-
description: Export all collected metrics in
|
|
594
|
+
description: Export all collected metrics in line-delimited JSON format
|
|
595
595
|
responses:
|
|
596
596
|
'200':
|
|
597
597
|
description: Metrics exported successfully
|
|
598
598
|
content:
|
|
599
|
-
application/
|
|
599
|
+
application/json:
|
|
600
600
|
schema:
|
|
601
601
|
type: string
|
|
602
602
|
|
|
@@ -605,11 +605,11 @@ paths:
|
|
|
605
605
|
tags:
|
|
606
606
|
- metrics
|
|
607
607
|
summary: Import metrics
|
|
608
|
-
description: Import metrics from
|
|
608
|
+
description: Import metrics from line-delimited JSON format
|
|
609
609
|
requestBody:
|
|
610
610
|
required: true
|
|
611
611
|
content:
|
|
612
|
-
application/
|
|
612
|
+
application/json:
|
|
613
613
|
schema:
|
|
614
614
|
type: string
|
|
615
615
|
responses:
|
|
@@ -789,12 +789,12 @@ paths:
|
|
|
789
789
|
tags:
|
|
790
790
|
- logs
|
|
791
791
|
summary: Export collected logs
|
|
792
|
-
description: Export all collected logs in
|
|
792
|
+
description: Export all collected logs in line-delimited JSON format
|
|
793
793
|
responses:
|
|
794
794
|
'200':
|
|
795
795
|
description: Logs exported successfully
|
|
796
796
|
content:
|
|
797
|
-
application/
|
|
797
|
+
application/json:
|
|
798
798
|
schema:
|
|
799
799
|
type: string
|
|
800
800
|
|
|
@@ -803,11 +803,11 @@ paths:
|
|
|
803
803
|
tags:
|
|
804
804
|
- logs
|
|
805
805
|
summary: Import logs
|
|
806
|
-
description: Import logs from
|
|
806
|
+
description: Import logs from line-delimited JSON format
|
|
807
807
|
requestBody:
|
|
808
808
|
required: true
|
|
809
809
|
content:
|
|
810
|
-
application/
|
|
810
|
+
application/json:
|
|
811
811
|
schema:
|
|
812
812
|
type: string
|
|
813
813
|
responses:
|
|
@@ -0,0 +1,121 @@
|
|
|
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.DiskLogExporter = void 0;
|
|
7
|
+
const core_1 = require("@opentelemetry/core");
|
|
8
|
+
const circular_js_1 = require("../utils/circular.cjs");
|
|
9
|
+
const wrappers_js_1 = require("../wrappers.cjs");
|
|
10
|
+
const DiskWriter_js_1 = require("../../persistence/DiskWriter.cjs");
|
|
11
|
+
const logger_js_1 = __importDefault(require("../../../utils/logger.cjs"));
|
|
12
|
+
class DiskLogExporter extends wrappers_js_1.Enabler {
|
|
13
|
+
writer;
|
|
14
|
+
flushIntervalMs;
|
|
15
|
+
batchSize;
|
|
16
|
+
queuedLogs = [];
|
|
17
|
+
flushTimer = null;
|
|
18
|
+
flushing = false;
|
|
19
|
+
constructor(options) {
|
|
20
|
+
super();
|
|
21
|
+
this.flushIntervalMs = options.flushIntervalMs || 1000;
|
|
22
|
+
this.batchSize = options.batchSize || 500;
|
|
23
|
+
this.writer = new DiskWriter_js_1.DiskWriter({
|
|
24
|
+
directoryPath: options.directoryPath,
|
|
25
|
+
segmentPrefix: 'logs',
|
|
26
|
+
maxSegmentBytes: options.maxSegmentBytes,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
export(logs, resultCallback) {
|
|
30
|
+
if (!this.isEnabled()) {
|
|
31
|
+
resultCallback({ code: core_1.ExportResultCode.SUCCESS });
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const serializableLogs = logs
|
|
36
|
+
.map((logRecord) => this.formatLogRecord(logRecord))
|
|
37
|
+
.map((log) => (0, circular_js_1.removeCircularRefs)(log))
|
|
38
|
+
.map((log) => (0, circular_js_1.applyNesting)(log));
|
|
39
|
+
if (serializableLogs.length > 0) {
|
|
40
|
+
this.queuedLogs.push(...serializableLogs);
|
|
41
|
+
if (this.queuedLogs.length >= this.batchSize) {
|
|
42
|
+
void this.flushPending();
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
this.scheduleFlush();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
resultCallback({ code: core_1.ExportResultCode.SUCCESS });
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
logger_js_1.default.error(`[DiskLogExporter] Failed to queue logs: ${error?.message || error}`);
|
|
52
|
+
resultCallback({
|
|
53
|
+
code: core_1.ExportResultCode.FAILED,
|
|
54
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async shutdown() {
|
|
59
|
+
this.disable();
|
|
60
|
+
if (this.flushTimer) {
|
|
61
|
+
clearTimeout(this.flushTimer);
|
|
62
|
+
this.flushTimer = null;
|
|
63
|
+
}
|
|
64
|
+
await this.flushPending(true);
|
|
65
|
+
await this.writer.flush();
|
|
66
|
+
}
|
|
67
|
+
async forceFlush() {
|
|
68
|
+
await this.flushPending(true);
|
|
69
|
+
await this.writer.flush();
|
|
70
|
+
}
|
|
71
|
+
scheduleFlush() {
|
|
72
|
+
if (this.flushTimer)
|
|
73
|
+
return;
|
|
74
|
+
this.flushTimer = setTimeout(() => {
|
|
75
|
+
this.flushTimer = null;
|
|
76
|
+
void this.flushPending(true);
|
|
77
|
+
}, this.flushIntervalMs);
|
|
78
|
+
}
|
|
79
|
+
async flushPending(forceAll = false) {
|
|
80
|
+
if (this.flushing)
|
|
81
|
+
return;
|
|
82
|
+
if (this.queuedLogs.length === 0)
|
|
83
|
+
return;
|
|
84
|
+
this.flushing = true;
|
|
85
|
+
try {
|
|
86
|
+
while (this.queuedLogs.length > 0) {
|
|
87
|
+
if (!forceAll && this.queuedLogs.length < this.batchSize) {
|
|
88
|
+
this.scheduleFlush();
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
const size = forceAll ? this.queuedLogs.length : this.batchSize;
|
|
92
|
+
const batch = this.queuedLogs.splice(0, size);
|
|
93
|
+
await this.writer.appendRecords(batch);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
logger_js_1.default.error(`[DiskLogExporter] Failed writing logs to disk: ${error?.message || error}`);
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
this.flushing = false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
formatLogRecord(logRecord) {
|
|
104
|
+
return {
|
|
105
|
+
resource: {
|
|
106
|
+
attributes: logRecord.resource.attributes,
|
|
107
|
+
},
|
|
108
|
+
instrumentationScope: logRecord.instrumentationScope,
|
|
109
|
+
timestamp: (0, core_1.hrTimeToMicroseconds)(logRecord.hrTime) ?? Date.now(),
|
|
110
|
+
observedTimestamp: (0, core_1.hrTimeToMicroseconds)(logRecord.hrTimeObserved) ?? Date.now(),
|
|
111
|
+
traceId: logRecord.spanContext?.traceId,
|
|
112
|
+
spanId: logRecord.spanContext?.spanId,
|
|
113
|
+
traceFlags: logRecord.spanContext?.traceFlags,
|
|
114
|
+
severityText: logRecord.severityText,
|
|
115
|
+
severityNumber: logRecord.severityNumber,
|
|
116
|
+
body: logRecord.body,
|
|
117
|
+
attributes: logRecord.attributes,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
exports.DiskLogExporter = DiskLogExporter;
|
|
@@ -0,0 +1,101 @@
|
|
|
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.DiskMetricExporter = void 0;
|
|
7
|
+
const core_1 = require("@opentelemetry/core");
|
|
8
|
+
const circular_js_1 = require("../utils/circular.cjs");
|
|
9
|
+
const wrappers_js_1 = require("../wrappers.cjs");
|
|
10
|
+
const logger_js_1 = __importDefault(require("../../../utils/logger.cjs"));
|
|
11
|
+
const DiskWriter_js_1 = require("../../persistence/DiskWriter.cjs");
|
|
12
|
+
class DiskMetricExporter extends wrappers_js_1.Enabler {
|
|
13
|
+
writer;
|
|
14
|
+
flushIntervalMs;
|
|
15
|
+
batchSize;
|
|
16
|
+
queuedScopeMetrics = [];
|
|
17
|
+
flushTimer = null;
|
|
18
|
+
flushing = false;
|
|
19
|
+
constructor(options) {
|
|
20
|
+
super();
|
|
21
|
+
this.flushIntervalMs = options.flushIntervalMs || 1000;
|
|
22
|
+
this.batchSize = options.batchSize || 500;
|
|
23
|
+
this.writer = new DiskWriter_js_1.DiskWriter({
|
|
24
|
+
directoryPath: options.directoryPath,
|
|
25
|
+
segmentPrefix: 'metrics',
|
|
26
|
+
maxSegmentBytes: options.maxSegmentBytes,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
export(resourceMetrics, resultCallback) {
|
|
30
|
+
if (!this.isEnabled()) {
|
|
31
|
+
resultCallback({ code: core_1.ExportResultCode.SUCCESS });
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const scopeMetrics = (0, circular_js_1.removeCircularRefs)(resourceMetrics.scopeMetrics || []);
|
|
36
|
+
if (Array.isArray(scopeMetrics) && scopeMetrics.length > 0) {
|
|
37
|
+
this.queuedScopeMetrics.push(...scopeMetrics);
|
|
38
|
+
if (this.queuedScopeMetrics.length >= this.batchSize) {
|
|
39
|
+
void this.flushPending();
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
this.scheduleFlush();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
resultCallback({ code: core_1.ExportResultCode.SUCCESS });
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
logger_js_1.default.error(`[DiskMetricExporter] Failed to queue scope metrics: ${error?.message || error}`);
|
|
49
|
+
resultCallback({
|
|
50
|
+
code: core_1.ExportResultCode.FAILED,
|
|
51
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async shutdown() {
|
|
56
|
+
this.disable();
|
|
57
|
+
if (this.flushTimer) {
|
|
58
|
+
clearTimeout(this.flushTimer);
|
|
59
|
+
this.flushTimer = null;
|
|
60
|
+
}
|
|
61
|
+
await this.flushPending(true);
|
|
62
|
+
await this.writer.flush();
|
|
63
|
+
}
|
|
64
|
+
async forceFlush() {
|
|
65
|
+
await this.flushPending(true);
|
|
66
|
+
await this.writer.flush();
|
|
67
|
+
}
|
|
68
|
+
scheduleFlush() {
|
|
69
|
+
if (this.flushTimer)
|
|
70
|
+
return;
|
|
71
|
+
this.flushTimer = setTimeout(() => {
|
|
72
|
+
this.flushTimer = null;
|
|
73
|
+
void this.flushPending(true);
|
|
74
|
+
}, this.flushIntervalMs);
|
|
75
|
+
}
|
|
76
|
+
async flushPending(forceAll = false) {
|
|
77
|
+
if (this.flushing)
|
|
78
|
+
return;
|
|
79
|
+
if (this.queuedScopeMetrics.length === 0)
|
|
80
|
+
return;
|
|
81
|
+
this.flushing = true;
|
|
82
|
+
try {
|
|
83
|
+
while (this.queuedScopeMetrics.length > 0) {
|
|
84
|
+
if (!forceAll && this.queuedScopeMetrics.length < this.batchSize) {
|
|
85
|
+
this.scheduleFlush();
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
const size = forceAll ? this.queuedScopeMetrics.length : this.batchSize;
|
|
89
|
+
const batch = this.queuedScopeMetrics.splice(0, size);
|
|
90
|
+
await this.writer.appendRecords(batch);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
logger_js_1.default.error(`[DiskMetricExporter] Failed writing metrics to disk: ${error?.message || error}`);
|
|
95
|
+
}
|
|
96
|
+
finally {
|
|
97
|
+
this.flushing = false;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
exports.DiskMetricExporter = DiskMetricExporter;
|
|
@@ -0,0 +1,103 @@
|
|
|
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.DiskTraceExporter = void 0;
|
|
7
|
+
const core_1 = require("@opentelemetry/core");
|
|
8
|
+
const logger_js_1 = __importDefault(require("../../../utils/logger.cjs"));
|
|
9
|
+
const circular_js_1 = require("../utils/circular.cjs");
|
|
10
|
+
const DiskWriter_js_1 = require("../../persistence/DiskWriter.cjs");
|
|
11
|
+
const wrappers_js_1 = require("../wrappers.cjs");
|
|
12
|
+
class DiskTraceExporter extends wrappers_js_1.Enabler {
|
|
13
|
+
writer;
|
|
14
|
+
flushIntervalMs;
|
|
15
|
+
batchSize;
|
|
16
|
+
queuedSpans = [];
|
|
17
|
+
flushTimer = null;
|
|
18
|
+
flushing = false;
|
|
19
|
+
constructor(options) {
|
|
20
|
+
super();
|
|
21
|
+
this.flushIntervalMs = options.flushIntervalMs || 1000;
|
|
22
|
+
this.batchSize = options.batchSize || 500;
|
|
23
|
+
this.writer = new DiskWriter_js_1.DiskWriter({
|
|
24
|
+
directoryPath: options.directoryPath,
|
|
25
|
+
segmentPrefix: 'traces',
|
|
26
|
+
maxSegmentBytes: options.maxSegmentBytes,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
export(spans, resultCallback) {
|
|
30
|
+
if (!this.isEnabled()) {
|
|
31
|
+
resultCallback({ code: core_1.ExportResultCode.SUCCESS });
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const serializableSpans = spans
|
|
36
|
+
.map((span) => (0, circular_js_1.removeCircularRefs)(span))
|
|
37
|
+
.map((span) => (0, circular_js_1.applyNesting)(span));
|
|
38
|
+
if (serializableSpans.length > 0) {
|
|
39
|
+
this.queuedSpans.push(...serializableSpans);
|
|
40
|
+
if (this.queuedSpans.length >= this.batchSize) {
|
|
41
|
+
void this.flushPending();
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
this.scheduleFlush();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
resultCallback({ code: core_1.ExportResultCode.SUCCESS });
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
logger_js_1.default.error(`[DiskTraceExporter] Failed to queue spans: ${error?.message || error}`);
|
|
51
|
+
resultCallback({
|
|
52
|
+
code: core_1.ExportResultCode.FAILED,
|
|
53
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async shutdown() {
|
|
58
|
+
this.disable();
|
|
59
|
+
if (this.flushTimer) {
|
|
60
|
+
clearTimeout(this.flushTimer);
|
|
61
|
+
this.flushTimer = null;
|
|
62
|
+
}
|
|
63
|
+
await this.flushPending(true);
|
|
64
|
+
await this.writer.flush();
|
|
65
|
+
}
|
|
66
|
+
async forceFlush() {
|
|
67
|
+
await this.flushPending(true);
|
|
68
|
+
await this.writer.flush();
|
|
69
|
+
}
|
|
70
|
+
scheduleFlush() {
|
|
71
|
+
if (this.flushTimer)
|
|
72
|
+
return;
|
|
73
|
+
this.flushTimer = setTimeout(() => {
|
|
74
|
+
this.flushTimer = null;
|
|
75
|
+
void this.flushPending(true);
|
|
76
|
+
}, this.flushIntervalMs);
|
|
77
|
+
}
|
|
78
|
+
async flushPending(forceAll = false) {
|
|
79
|
+
if (this.flushing)
|
|
80
|
+
return;
|
|
81
|
+
if (this.queuedSpans.length === 0)
|
|
82
|
+
return;
|
|
83
|
+
this.flushing = true;
|
|
84
|
+
try {
|
|
85
|
+
while (this.queuedSpans.length > 0) {
|
|
86
|
+
if (!forceAll && this.queuedSpans.length < this.batchSize) {
|
|
87
|
+
this.scheduleFlush();
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
const size = forceAll ? this.queuedSpans.length : this.batchSize;
|
|
91
|
+
const batch = this.queuedSpans.splice(0, size);
|
|
92
|
+
await this.writer.appendRecords(batch);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
logger_js_1.default.error(`[DiskTraceExporter] Failed writing spans to disk: ${error?.message || error}`);
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
this.flushing = false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
exports.DiskTraceExporter = DiskTraceExporter;
|
|
@@ -12,36 +12,31 @@ const circular_js_1 = require("../utils/circular.cjs");
|
|
|
12
12
|
const wrappers_js_1 = require("../wrappers.cjs");
|
|
13
13
|
const logger_js_1 = __importDefault(require("../../../utils/logger.cjs"));
|
|
14
14
|
const pluginService_js_1 = require("../../../tlm-plugin/pluginService.cjs");
|
|
15
|
-
const storagePath_js_1 = require("../utils/storagePath.cjs");
|
|
16
15
|
class InMemoryDbLogExporter extends wrappers_js_1.Enabler {
|
|
17
16
|
_db = null;
|
|
18
17
|
_miniSearch = null;
|
|
19
18
|
_retentionTimeInSeconds;
|
|
20
|
-
_storagePath = null;
|
|
21
19
|
_initialized = false;
|
|
22
20
|
constructor(retentionTimeInSeconds = 3600) {
|
|
23
21
|
super();
|
|
24
22
|
this._retentionTimeInSeconds = retentionTimeInSeconds;
|
|
25
|
-
this._storagePath = (0, storagePath_js_1.getStoragePath)('logs');
|
|
26
23
|
this._startCleanupJob();
|
|
27
24
|
}
|
|
28
25
|
_ensureInitialized() {
|
|
29
26
|
if (this._initialized)
|
|
30
27
|
return;
|
|
31
28
|
this._initialized = true;
|
|
32
|
-
this._db = new nedb_1.default(
|
|
33
|
-
this._db.ensureIndex({ fieldName: '
|
|
29
|
+
this._db = new nedb_1.default();
|
|
30
|
+
this._db.ensureIndex({ fieldName: 'timestamp' });
|
|
34
31
|
this._miniSearch = new minisearch_1.default({
|
|
35
32
|
fields: ['body'],
|
|
36
33
|
storeFields: ['_id'],
|
|
37
34
|
idField: '_id',
|
|
38
35
|
});
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
logger_js_1.default.info(`[LogExporter] Using in-memory storage`);
|
|
44
|
-
}
|
|
36
|
+
logger_js_1.default.info(`[InMemoryDbLogExporter] In-memory storage created`);
|
|
37
|
+
}
|
|
38
|
+
initializeStorage() {
|
|
39
|
+
this._ensureInitialized();
|
|
45
40
|
}
|
|
46
41
|
/*
|
|
47
42
|
* SUPER WARNING:
|
|
@@ -74,13 +69,13 @@ class InMemoryDbLogExporter extends wrappers_js_1.Enabler {
|
|
|
74
69
|
}
|
|
75
70
|
reset() {
|
|
76
71
|
this._ensureInitialized();
|
|
77
|
-
// Remove all logs from
|
|
72
|
+
// Remove all logs from the in-memory database.
|
|
78
73
|
this._db.remove({}, { multi: true }, (err) => {
|
|
79
74
|
if (err) {
|
|
80
|
-
logger_js_1.default.error(`[
|
|
75
|
+
logger_js_1.default.error(`[InMemoryDbLogExporter] Error during reset: ${err.message}`);
|
|
81
76
|
}
|
|
82
77
|
else {
|
|
83
|
-
logger_js_1.default.info(`[
|
|
78
|
+
logger_js_1.default.info(`[InMemoryDbLogExporter] Reset - all logs cleared`);
|
|
84
79
|
}
|
|
85
80
|
});
|
|
86
81
|
// Clear mini search index
|
|
@@ -106,7 +101,7 @@ class InMemoryDbLogExporter extends wrappers_js_1.Enabler {
|
|
|
106
101
|
if (messageSearch) {
|
|
107
102
|
const searchResults = this._miniSearch.search(messageSearch, { prefix: true, fuzzy: 0.2 });
|
|
108
103
|
const ids = searchResults.map((result) => result._id);
|
|
109
|
-
logger_js_1.default.debug(`MiniSearch found ${ids.length} results for search term "${messageSearch}"`, { depth: 3 });
|
|
104
|
+
logger_js_1.default.debug(`[InMemoryDbLogExporter] MiniSearch found ${ids.length} results for search term "${messageSearch}"`, { depth: 3 });
|
|
110
105
|
finalQuery._id = { $in: ids };
|
|
111
106
|
}
|
|
112
107
|
const docs = await new Promise((resolve, reject) => {
|
|
@@ -130,7 +125,7 @@ class InMemoryDbLogExporter extends wrappers_js_1.Enabler {
|
|
|
130
125
|
if (result.code === core_2.ExportResultCode.SUCCESS) {
|
|
131
126
|
this._db.find({}, (err, docs) => {
|
|
132
127
|
if (err) {
|
|
133
|
-
logger_js_1.default.debug(err);
|
|
128
|
+
logger_js_1.default.debug('[InMemoryDbLogExporter] Error fetching inserted logs', err);
|
|
134
129
|
callback(err, []);
|
|
135
130
|
return;
|
|
136
131
|
}
|
|
@@ -171,7 +166,7 @@ class InMemoryDbLogExporter extends wrappers_js_1.Enabler {
|
|
|
171
166
|
}
|
|
172
167
|
set retentionTimeInSeconds(retentionTimeInSeconds) {
|
|
173
168
|
this._retentionTimeInSeconds = retentionTimeInSeconds;
|
|
174
|
-
logger_js_1.default.info(`InMemoryDbLogExporter
|
|
169
|
+
logger_js_1.default.info(`[InMemoryDbLogExporter] Retention time set to ${this._retentionTimeInSeconds} seconds`);
|
|
175
170
|
}
|
|
176
171
|
get retentionTimeInSeconds() {
|
|
177
172
|
return this._retentionTimeInSeconds;
|
|
@@ -199,10 +194,10 @@ class InMemoryDbLogExporter extends wrappers_js_1.Enabler {
|
|
|
199
194
|
const expirationDate = new Date(Date.now() - this._retentionTimeInSeconds * 1000);
|
|
200
195
|
this._db.remove({ createdAt: { $lt: expirationDate } }, { multi: true }, (err, numRemoved) => {
|
|
201
196
|
if (err) {
|
|
202
|
-
logger_js_1.default.error('Error in TTL cleanup:', err);
|
|
197
|
+
logger_js_1.default.error('[InMemoryDbLogExporter] Error in TTL cleanup:', err);
|
|
203
198
|
}
|
|
204
199
|
else if (numRemoved > 0) {
|
|
205
|
-
logger_js_1.default.debug(`TTL cleanup
|
|
200
|
+
logger_js_1.default.debug(`[InMemoryDbLogExporter] TTL cleanup removed ${numRemoved} expired logs`);
|
|
206
201
|
}
|
|
207
202
|
});
|
|
208
203
|
}, interval);
|