@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.
Files changed (112) hide show
  1. package/.env.example +7 -12
  2. package/dist/cjs/config/bootConfig.cjs +1 -4
  3. package/dist/cjs/config/config.cjs +8 -0
  4. package/dist/cjs/docs/openapi.yaml +12 -12
  5. package/dist/cjs/telemetry/custom-implementations/exporters/DiskLogExporter.cjs +121 -0
  6. package/dist/cjs/telemetry/custom-implementations/exporters/DiskMetricExporter.cjs +101 -0
  7. package/dist/cjs/telemetry/custom-implementations/exporters/DiskTraceExporter.cjs +103 -0
  8. package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbLogExporter.cjs +14 -19
  9. package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.cjs +26 -80
  10. package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.cjs +25 -23
  11. package/dist/cjs/telemetry/custom-implementations/exporters/MultiMetricExporter.cjs +57 -0
  12. package/dist/cjs/telemetry/custom-implementations/metrics/tsdb/SeriesRegistry.cjs +17 -14
  13. package/dist/cjs/telemetry/custom-implementations/wrappers.cjs +72 -4
  14. package/dist/cjs/telemetry/persistence/DiskImporter.cjs +85 -0
  15. package/dist/cjs/telemetry/persistence/DiskUtils.cjs +61 -0
  16. package/dist/cjs/telemetry/persistence/DiskWriter.cjs +66 -0
  17. package/dist/cjs/telemetry/telemetryConfigurator.cjs +74 -5
  18. package/dist/cjs/tlm-log/logController.cjs +26 -62
  19. package/dist/cjs/tlm-log/logRoutes.cjs +1 -2
  20. package/dist/cjs/tlm-log/logService.cjs +29 -0
  21. package/dist/cjs/tlm-metric/metricsController.cjs +39 -97
  22. package/dist/cjs/tlm-metric/metricsRoutes.cjs +1 -2
  23. package/dist/cjs/tlm-metric/metricsService.cjs +26 -0
  24. package/dist/cjs/tlm-trace/traceController.cjs +32 -67
  25. package/dist/cjs/tlm-trace/traceRoutes.cjs +1 -2
  26. package/dist/cjs/tlm-trace/traceService.cjs +29 -0
  27. package/dist/esm/config/bootConfig.js +1 -4
  28. package/dist/esm/config/config.js +8 -0
  29. package/dist/esm/docs/openapi.yaml +12 -12
  30. package/dist/esm/telemetry/custom-implementations/exporters/DiskLogExporter.js +114 -0
  31. package/dist/esm/telemetry/custom-implementations/exporters/DiskMetricExporter.js +94 -0
  32. package/dist/esm/telemetry/custom-implementations/exporters/DiskTraceExporter.js +96 -0
  33. package/dist/esm/telemetry/custom-implementations/exporters/InMemoryDbLogExporter.js +14 -19
  34. package/dist/esm/telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.js +26 -80
  35. package/dist/esm/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.js +25 -23
  36. package/dist/esm/telemetry/custom-implementations/exporters/MultiMetricExporter.js +53 -0
  37. package/dist/esm/telemetry/custom-implementations/metrics/tsdb/SeriesRegistry.js +17 -14
  38. package/dist/esm/telemetry/custom-implementations/wrappers.js +72 -4
  39. package/dist/esm/telemetry/persistence/DiskImporter.js +78 -0
  40. package/dist/esm/telemetry/persistence/DiskUtils.js +51 -0
  41. package/dist/esm/telemetry/persistence/DiskWriter.js +59 -0
  42. package/dist/esm/telemetry/telemetryConfigurator.js +74 -5
  43. package/dist/esm/tlm-log/logController.js +26 -62
  44. package/dist/esm/tlm-log/logRoutes.js +2 -3
  45. package/dist/esm/tlm-log/logService.js +25 -0
  46. package/dist/esm/tlm-metric/metricsController.js +38 -95
  47. package/dist/esm/tlm-metric/metricsRoutes.js +2 -3
  48. package/dist/esm/tlm-metric/metricsService.js +22 -0
  49. package/dist/esm/tlm-trace/traceController.js +32 -67
  50. package/dist/esm/tlm-trace/traceRoutes.js +2 -3
  51. package/dist/esm/tlm-trace/traceService.js +25 -0
  52. package/dist/types/config/bootConfig.d.ts +0 -1
  53. package/dist/types/config/config.d.ts +12 -0
  54. package/dist/types/config/config.types.d.ts +1 -0
  55. package/dist/types/telemetry/custom-implementations/exporters/DiskLogExporter.d.ts +24 -0
  56. package/dist/types/telemetry/custom-implementations/exporters/DiskMetricExporter.d.ts +23 -0
  57. package/dist/types/telemetry/custom-implementations/exporters/DiskTraceExporter.d.ts +23 -0
  58. package/dist/types/telemetry/custom-implementations/exporters/InMemoryDbLogExporter.d.ts +1 -1
  59. package/dist/types/telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.d.ts +7 -10
  60. package/dist/types/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.d.ts +1 -1
  61. package/dist/types/telemetry/custom-implementations/exporters/MultiMetricExporter.d.ts +9 -0
  62. package/dist/types/telemetry/custom-implementations/metrics/tsdb/SeriesRegistry.d.ts +6 -6
  63. package/dist/types/telemetry/custom-implementations/wrappers.d.ts +1 -0
  64. package/dist/types/telemetry/persistence/DiskImporter.d.ts +17 -0
  65. package/dist/types/telemetry/persistence/DiskUtils.d.ts +11 -0
  66. package/dist/types/telemetry/persistence/DiskWriter.d.ts +21 -0
  67. package/dist/types/tlm-log/logService.d.ts +4 -0
  68. package/dist/types/tlm-metric/metricsController.d.ts +0 -5
  69. package/dist/types/tlm-metric/metricsService.d.ts +6 -0
  70. package/dist/types/tlm-trace/traceController.d.ts +6 -6
  71. package/dist/types/tlm-trace/traceService.d.ts +4 -0
  72. package/dist/ui/assets/{ApiDocsPage-BFUrXE5F.js → ApiDocsPage-BAZE-zL3.js} +1 -1
  73. package/dist/ui/assets/{CollapsibleCard-STA1GVQO.js → CollapsibleCard-Dyp3VGPU.js} +1 -1
  74. package/dist/ui/assets/{DevToolsPage-BRSfZqO_.js → DevToolsPage-D6WvJgfI.js} +1 -1
  75. package/dist/ui/assets/{LandingPage-DzeDy7q7.js → LandingPage-DgZmfiO1.js} +1 -1
  76. package/dist/ui/assets/{LogsPage-BeiFrV2X.js → LogsPage-CcCa1wCS.js} +1 -1
  77. package/dist/ui/assets/{NotFoundPage-fRNOatbM.js → NotFoundPage-D-XZVon_.js} +1 -1
  78. package/dist/ui/assets/{PluginCreatePage-Ch_RXsdf.js → PluginCreatePage-CSlmgA5Z.js} +1 -1
  79. package/dist/ui/assets/{PluginPage-Cl65ZZ_n.js → PluginPage-CUFe2cVr.js} +1 -1
  80. package/dist/ui/assets/TraceSpansPage-BqwuoD4T.js +6 -0
  81. package/dist/ui/assets/{VirtualizedListPanel-zcj0v7DL.js → VirtualizedListPanel-C0oG8Dkc.js} +1 -1
  82. package/dist/ui/assets/{alert-BkNVKxJN.js → alert-CvCDsfT9.js} +1 -1
  83. package/dist/ui/assets/{badge-CN7FeufU.js → badge-iri4YLiT.js} +1 -1
  84. package/dist/ui/assets/{chevron-down-CG--ounh.js → chevron-down-Dze6JQWQ.js} +1 -1
  85. package/dist/ui/assets/{chevron-up-B6tzMAOm.js → chevron-up-BOgWUK-m.js} +1 -1
  86. package/dist/ui/assets/{circle-alert-BDF8Tq9y.js → circle-alert-DNqNwGYC.js} +1 -1
  87. package/dist/ui/assets/{dialog-BrpWNk36.js → dialog-BbBXMqd9.js} +1 -1
  88. package/dist/ui/assets/{index-6xOVKwKn.js → index-Bak7-IjV.js} +2 -2
  89. package/dist/ui/assets/{index-D96rVSkR.js → index-gwOdQdDr.js} +1 -1
  90. package/dist/ui/assets/{info-99kuqpbx.js → info-CEPnfukj.js} +1 -1
  91. package/dist/ui/assets/{input-B-01QDg_.js → input-DIJScMC5.js} +1 -1
  92. package/dist/ui/assets/{label-CQLeZjM1.js → label-C-VVLc4C.js} +1 -1
  93. package/dist/ui/assets/{loader-circle-BoDGk-BO.js → loader-circle-Cd1Edf_o.js} +1 -1
  94. package/dist/ui/assets/{loginPage-8F4EEd1B.js → loginPage-CwnoByhF.js} +1 -1
  95. package/dist/ui/assets/metrics-page-BY5ijZjD.js +31 -0
  96. package/dist/ui/assets/{popover-DS_8DYYt.js → popover-2XBYXBkN.js} +2 -2
  97. package/dist/ui/assets/{select-DYjegiXi.js → select-CNQVyoVV.js} +1 -1
  98. package/dist/ui/assets/{separator-DGsRxIrl.js → separator-jwB4ekGy.js} +1 -1
  99. package/dist/ui/assets/severityOptions-w0EiAFxM.js +11 -0
  100. package/dist/ui/assets/{square-pen-DPhgYz6O.js → square-pen-BkIfvdtf.js} +1 -1
  101. package/dist/ui/assets/{switch-Di9NJH2A.js → switch-Dgtlsp4F.js} +1 -1
  102. package/dist/ui/assets/{upload-BiLTpCnX.js → upload-BE0Mp5Zk.js} +1 -1
  103. package/dist/ui/assets/{utilService-CNZOmadC.js → utilService-BN13pIJg.js} +1 -1
  104. package/dist/ui/assets/{wand-sparkles-CPoBNFFg.js → wand-sparkles-Df82iOpL.js} +1 -1
  105. package/dist/ui/index.html +1 -1
  106. package/package.json +2 -3
  107. package/dist/cjs/telemetry/custom-implementations/utils/storagePath.cjs +0 -39
  108. package/dist/esm/telemetry/custom-implementations/utils/storagePath.js +0 -33
  109. package/dist/types/telemetry/custom-implementations/utils/storagePath.d.ts +0 -12
  110. package/dist/ui/assets/TraceSpansPage-BoK4M5Hh.js +0 -6
  111. package/dist/ui/assets/metrics-page-DPtteXqY.js +0 -31
  112. 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 of your application or service | Default: "SERVICE-<random-uuid>"
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 || `SERVICE-${(0, crypto_1.randomUUID)().slice(0, 8).toUpperCase()}`,
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 NDJSON format
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/x-ndjson:
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 NDJSON format
348
+ description: Import traces from line-delimited JSON format
349
349
  requestBody:
350
350
  required: true
351
351
  content:
352
- application/x-ndjson:
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 NDJSON format
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/x-ndjson:
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 NDJSON format
608
+ description: Import metrics from line-delimited JSON format
609
609
  requestBody:
610
610
  required: true
611
611
  content:
612
- application/x-ndjson:
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 NDJSON format
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/x-ndjson:
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 NDJSON format
806
+ description: Import logs from line-delimited JSON format
807
807
  requestBody:
808
808
  required: true
809
809
  content:
810
- application/x-ndjson:
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(this._storagePath ? { filename: this._storagePath, timestampData: true, autoload: true } : { timestampData: true });
33
- this._db.ensureIndex({ fieldName: 'createdAt' });
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
- if (this._storagePath) {
40
- logger_js_1.default.info(`[LogExporter] Disk storage enabled at: ${this._storagePath}`);
41
- }
42
- else {
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 database but keep persistence enabled
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(`[LogExporter] Error during reset: ${err.message}`);
75
+ logger_js_1.default.error(`[InMemoryDbLogExporter] Error during reset: ${err.message}`);
81
76
  }
82
77
  else {
83
- logger_js_1.default.info(`[LogExporter] Reset - all logs cleared`);
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 retention time set to ${this._retentionTimeInSeconds} seconds`);
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: removed ${numRemoved} expired logs`);
200
+ logger_js_1.default.debug(`[InMemoryDbLogExporter] TTL cleanup removed ${numRemoved} expired logs`);
206
201
  }
207
202
  });
208
203
  }, interval);