@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.
Files changed (167) hide show
  1. package/.env.example +21 -2
  2. package/README.md +1 -2
  3. package/dist/cjs/config/bootConfig.cjs +19 -14
  4. package/dist/cjs/config/config.cjs +112 -125
  5. package/dist/cjs/config/config.types.cjs +1 -4
  6. package/dist/cjs/docs/openapi.yaml +158 -4
  7. package/dist/cjs/index.cjs +27 -30
  8. package/dist/cjs/routesManager.cjs +62 -70
  9. package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbLogExporter.cjs +202 -190
  10. package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.cjs +204 -99
  11. package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.cjs +152 -116
  12. package/dist/cjs/telemetry/custom-implementations/instrumentations/logsInstrumentation.cjs +92 -0
  13. package/dist/cjs/telemetry/custom-implementations/metrics/tsdb/Chunk.cjs +159 -0
  14. package/dist/cjs/telemetry/custom-implementations/metrics/tsdb/Series.cjs +168 -0
  15. package/dist/cjs/telemetry/custom-implementations/metrics/tsdb/SeriesRegistry.cjs +389 -0
  16. package/dist/cjs/telemetry/custom-implementations/metrics/tsdb/types.cjs +2 -0
  17. package/dist/cjs/telemetry/custom-implementations/metrics/tsdb/utils.cjs +77 -0
  18. package/dist/cjs/telemetry/custom-implementations/processors/dynamicMultiLogProcessor.cjs +65 -63
  19. package/dist/cjs/telemetry/custom-implementations/processors/dynamicMultiSpanProcessor.cjs +63 -62
  20. package/dist/cjs/telemetry/custom-implementations/utils/circular.cjs +47 -47
  21. package/dist/cjs/telemetry/custom-implementations/utils/storagePath.cjs +39 -0
  22. package/dist/cjs/telemetry/custom-implementations/wrappers.cjs +141 -138
  23. package/dist/cjs/telemetry/initializeTelemetry.cjs +35 -91
  24. package/dist/cjs/telemetry/telemetryConfigurator.cjs +70 -72
  25. package/dist/cjs/telemetry/telemetryRegistry.cjs +45 -31
  26. package/dist/cjs/tlm-ai/agent.cjs +49 -64
  27. package/dist/cjs/tlm-ai/aiController.cjs +54 -76
  28. package/dist/cjs/tlm-ai/aiRoutes.cjs +17 -20
  29. package/dist/cjs/tlm-ai/aiService.cjs +91 -95
  30. package/dist/cjs/tlm-ai/tools.cjs +177 -174
  31. package/dist/cjs/tlm-auth/authController.cjs +80 -123
  32. package/dist/cjs/tlm-auth/authMiddleware.cjs +25 -30
  33. package/dist/cjs/tlm-auth/authRoutes.cjs +11 -14
  34. package/dist/cjs/tlm-log/logController.cjs +171 -116
  35. package/dist/cjs/tlm-log/logRoutes.cjs +20 -20
  36. package/dist/cjs/tlm-metric/metricsController.cjs +211 -121
  37. package/dist/cjs/tlm-metric/metricsRoutes.cjs +23 -20
  38. package/dist/cjs/tlm-plugin/pluginController.cjs +128 -140
  39. package/dist/cjs/tlm-plugin/pluginProcess.cjs +89 -94
  40. package/dist/cjs/tlm-plugin/pluginRoutes.cjs +11 -14
  41. package/dist/cjs/tlm-plugin/pluginService.cjs +73 -74
  42. package/dist/cjs/tlm-trace/traceController.cjs +169 -117
  43. package/dist/cjs/tlm-trace/traceRoutes.cjs +20 -20
  44. package/dist/cjs/tlm-ui/uiRoutes.cjs +63 -32
  45. package/dist/cjs/tlm-util/utilController.cjs +68 -70
  46. package/dist/cjs/tlm-util/utilRoutes.cjs +51 -63
  47. package/dist/cjs/types/index.cjs +2 -5
  48. package/dist/cjs/utils/logger.cjs +38 -43
  49. package/dist/cjs/utils/regexUtils.cjs +22 -22
  50. package/dist/esm/config/bootConfig.js +6 -0
  51. package/dist/esm/config/config.js +1 -2
  52. package/dist/esm/docs/openapi.yaml +158 -4
  53. package/dist/esm/index.js +9 -8
  54. package/dist/esm/routesManager.js +6 -10
  55. package/dist/esm/telemetry/custom-implementations/exporters/InMemoryDbLogExporter.js +47 -8
  56. package/dist/esm/telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.js +164 -48
  57. package/dist/esm/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.js +69 -29
  58. package/dist/esm/telemetry/custom-implementations/instrumentations/logsInstrumentation.js +85 -0
  59. package/dist/esm/telemetry/custom-implementations/metrics/tsdb/Chunk.js +155 -0
  60. package/dist/esm/telemetry/custom-implementations/metrics/tsdb/Series.js +164 -0
  61. package/dist/esm/telemetry/custom-implementations/metrics/tsdb/SeriesRegistry.js +382 -0
  62. package/dist/esm/telemetry/custom-implementations/metrics/tsdb/types.js +1 -0
  63. package/dist/esm/telemetry/custom-implementations/metrics/tsdb/utils.js +74 -0
  64. package/dist/esm/telemetry/custom-implementations/processors/dynamicMultiLogProcessor.js +2 -1
  65. package/dist/esm/telemetry/custom-implementations/processors/dynamicMultiSpanProcessor.js +1 -1
  66. package/dist/esm/telemetry/custom-implementations/utils/storagePath.js +33 -0
  67. package/dist/esm/telemetry/custom-implementations/wrappers.js +5 -2
  68. package/dist/esm/telemetry/initializeTelemetry.js +27 -69
  69. package/dist/esm/telemetry/telemetryConfigurator.js +42 -40
  70. package/dist/esm/telemetry/telemetryRegistry.js +12 -1
  71. package/dist/esm/tlm-ai/agent.js +5 -3
  72. package/dist/esm/tlm-ai/aiController.js +3 -3
  73. package/dist/esm/tlm-ai/aiService.js +6 -2
  74. package/dist/esm/tlm-ai/tools.js +5 -9
  75. package/dist/esm/tlm-auth/authController.js +3 -2
  76. package/dist/esm/tlm-log/logController.js +84 -4
  77. package/dist/esm/tlm-log/logRoutes.js +5 -2
  78. package/dist/esm/tlm-metric/metricsController.js +172 -49
  79. package/dist/esm/tlm-metric/metricsRoutes.js +10 -4
  80. package/dist/esm/tlm-plugin/pluginController.js +6 -11
  81. package/dist/esm/tlm-plugin/pluginService.js +2 -4
  82. package/dist/esm/tlm-trace/traceController.js +102 -16
  83. package/dist/esm/tlm-trace/traceRoutes.js +5 -2
  84. package/dist/esm/tlm-ui/uiRoutes.js +5 -5
  85. package/dist/esm/tlm-util/utilController.js +3 -9
  86. package/dist/esm/tlm-util/utilRoutes.js +2 -2
  87. package/dist/types/config/bootConfig.d.ts +4 -0
  88. package/dist/types/config/config.d.ts +36 -7
  89. package/dist/types/config/config.types.d.ts +6 -0
  90. package/dist/types/index.d.ts +2 -3
  91. package/dist/types/telemetry/custom-implementations/exporters/InMemoryDbLogExporter.d.ts +4 -1
  92. package/dist/types/telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.d.ts +60 -15
  93. package/dist/types/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.d.ts +9 -4
  94. package/dist/types/telemetry/custom-implementations/instrumentations/logsInstrumentation.d.ts +23 -0
  95. package/dist/types/telemetry/custom-implementations/metrics/tsdb/Chunk.d.ts +49 -0
  96. package/dist/types/telemetry/custom-implementations/metrics/tsdb/Series.d.ts +67 -0
  97. package/dist/types/telemetry/custom-implementations/metrics/tsdb/SeriesRegistry.d.ts +69 -0
  98. package/dist/types/telemetry/custom-implementations/metrics/tsdb/types.d.ts +68 -0
  99. package/dist/types/telemetry/custom-implementations/metrics/tsdb/utils.d.ts +21 -0
  100. package/dist/types/telemetry/custom-implementations/processors/dynamicMultiLogProcessor.d.ts +2 -2
  101. package/dist/types/telemetry/custom-implementations/utils/storagePath.d.ts +12 -0
  102. package/dist/types/telemetry/custom-implementations/wrappers.d.ts +1 -1
  103. package/dist/types/telemetry/telemetryConfigurator.d.ts +1 -1
  104. package/dist/types/telemetry/telemetryRegistry.d.ts +8 -0
  105. package/dist/types/tlm-ai/agent.d.ts +1 -1
  106. package/dist/types/tlm-ai/aiService.d.ts +1 -1
  107. package/dist/types/tlm-log/logController.d.ts +2 -0
  108. package/dist/types/tlm-metric/metricsController.d.ts +16 -2
  109. package/dist/types/tlm-trace/traceController.d.ts +3 -1
  110. package/dist/types/types/index.d.ts +2 -2
  111. package/dist/ui/assets/{ApiDocsPage-C_VVPPHa.js → ApiDocsPage-BFUrXE5F.js} +2 -2
  112. package/dist/ui/assets/CollapsibleCard-STA1GVQO.js +1 -0
  113. package/dist/ui/assets/DevToolsPage-BRSfZqO_.js +1 -0
  114. package/dist/ui/assets/LandingPage-DzeDy7q7.js +6 -0
  115. package/dist/ui/assets/LogsPage-BeiFrV2X.js +1 -0
  116. package/dist/ui/assets/{NotFoundPage-B3quk3P1.js → NotFoundPage-fRNOatbM.js} +1 -1
  117. package/dist/ui/assets/PluginCreatePage-Ch_RXsdf.js +50 -0
  118. package/dist/ui/assets/PluginPage-Cl65ZZ_n.js +27 -0
  119. package/dist/ui/assets/TraceSpansPage-BoK4M5Hh.js +6 -0
  120. package/dist/ui/assets/VirtualizedListPanel-zcj0v7DL.js +16 -0
  121. package/dist/ui/assets/alert-BkNVKxJN.js +1133 -0
  122. package/dist/ui/assets/badge-CN7FeufU.js +1 -0
  123. package/dist/ui/assets/{chevron-down-CPsvsmqj.js → chevron-down-CG--ounh.js} +1 -1
  124. package/dist/ui/assets/{chevron-up-Df9jMo1X.js → chevron-up-B6tzMAOm.js} +1 -1
  125. package/dist/ui/assets/{circle-alert-DOPQPvU8.js → circle-alert-BDF8Tq9y.js} +1 -1
  126. package/dist/ui/assets/dialog-BrpWNk36.js +15 -0
  127. package/dist/ui/assets/index-6xOVKwKn.js +305 -0
  128. package/dist/ui/assets/index-D6f1KjWV.css +1 -0
  129. package/dist/ui/assets/index-D96rVSkR.js +1 -0
  130. package/dist/ui/assets/info-99kuqpbx.js +6 -0
  131. package/dist/ui/assets/{input-Dzvg_ZEZ.js → input-B-01QDg_.js} +1 -1
  132. package/dist/ui/assets/label-CQLeZjM1.js +1 -0
  133. package/dist/ui/assets/{loader-circle-CrvlRy5o.js → loader-circle-BoDGk-BO.js} +1 -1
  134. package/dist/ui/assets/{loginPage-qa4V-B70.js → loginPage-8F4EEd1B.js} +1 -1
  135. package/dist/ui/assets/metrics-page-D1GxaB_c.css +1 -0
  136. package/dist/ui/assets/metrics-page-DPtteXqY.js +31 -0
  137. package/dist/ui/assets/popover-DS_8DYYt.js +11 -0
  138. package/dist/ui/assets/select-DYjegiXi.js +6 -0
  139. package/dist/ui/assets/separator-DGsRxIrl.js +6 -0
  140. package/dist/ui/assets/severityOptions-DEOvJqC9.js +11 -0
  141. package/dist/ui/assets/square-pen-DPhgYz6O.js +6 -0
  142. package/dist/ui/assets/switch-Di9NJH2A.js +1 -0
  143. package/dist/ui/assets/trace-DJq1miYa.js +1 -0
  144. package/dist/ui/assets/upload-BiLTpCnX.js +11 -0
  145. package/dist/ui/assets/{utilService-DNyqzwj0.js → utilService-CNZOmadC.js} +1 -1
  146. package/dist/ui/assets/wand-sparkles-CPoBNFFg.js +6 -0
  147. package/dist/ui/index.html +2 -2
  148. package/package.json +44 -48
  149. package/dist/ui/assets/CollapsibleCard-B3KR_8mL.js +0 -1
  150. package/dist/ui/assets/DevToolsPage-OyZcDcmw.js +0 -1
  151. package/dist/ui/assets/LandingPage-CppFBA6K.js +0 -6
  152. package/dist/ui/assets/LogsPage-9Fq8GArS.js +0 -26
  153. package/dist/ui/assets/PluginCreatePage-X_aCH4t4.js +0 -50
  154. package/dist/ui/assets/PluginPage-DMDSihrZ.js +0 -27
  155. package/dist/ui/assets/alert-jQ9HCPIf.js +0 -1133
  156. package/dist/ui/assets/badge-CNq0-mH5.js +0 -1
  157. package/dist/ui/assets/card-DFAwwhN3.js +0 -1
  158. package/dist/ui/assets/index-BkD6DijD.js +0 -15
  159. package/dist/ui/assets/index-CERGVYZK.js +0 -292
  160. package/dist/ui/assets/index-CSIPf9qw.css +0 -1
  161. package/dist/ui/assets/label-DuVnkZ4q.js +0 -1
  162. package/dist/ui/assets/select-DhS8YUtJ.js +0 -1
  163. package/dist/ui/assets/separator-isK4chBP.js +0 -6
  164. package/dist/ui/assets/severityOptions-O38dSOfk.js +0 -11
  165. package/dist/ui/assets/switch-Z3mImG9n.js +0 -1
  166. package/dist/ui/assets/tabs-_77MUUQe.js +0 -16
  167. package/dist/ui/assets/upload-C1LT4Gkb.js +0 -16
@@ -0,0 +1,389 @@
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.SeriesRegistry = void 0;
7
+ const Series_js_1 = require("./Series.cjs");
8
+ const Chunk_js_1 = require("./Chunk.cjs");
9
+ /*
10
+ OTEL export = Resource (unchanged) + SCOPE METRICS
11
+ scopeMetrics: {
12
+ scope: {name: library, version: 1.0.0},; //repeated for each metric
13
+ metrics: [
14
+ {
15
+ //Metadata (Repeated for each dataPoint)
16
+ descriptor: {name: metricName, unit, description, ...},
17
+ aggregationTemporality,
18
+ dataPointType,
19
+ // Actual dataPoints are stored in Series
20
+ dataPoints: []
21
+ }
22
+ ]
23
+ }
24
+ */
25
+ // Import fs at top level for disk operations
26
+ const fs_1 = __importDefault(require("fs"));
27
+ class SeriesRegistry {
28
+ // Main storage
29
+ series = new Map(); // seriesId (scopeId:metricName:attributesId) -> Series
30
+ // Cached repeated data
31
+ scopes = new Map(); // scopeId -> scope
32
+ metricMetadataMap = new Map(); // "scopeId:metricName" -> MetricMetadata
33
+ // Faster lookup index
34
+ metricIdIndex = new Map(); // "scopeId:metricName" -> Set<seriesId>
35
+ chunkSize;
36
+ maxChunks;
37
+ constructor(chunkSize = 120, maxChunks = 60) {
38
+ this.chunkSize = chunkSize;
39
+ this.maxChunks = maxChunks;
40
+ }
41
+ /**
42
+ * Store entire ScopeMetrics array efficiently
43
+ * Replaces addSample - processes all metrics in one batch
44
+ */
45
+ storeScopeMetrics(scopeMetrics) {
46
+ for (const scopeMetric of scopeMetrics) {
47
+ const scope = scopeMetric.scope;
48
+ const scopeId = scopeToId(scope);
49
+ this.scopes.set(scopeId, scope);
50
+ for (const metricData of scopeMetric.metrics) {
51
+ const metricName = metricData.descriptor.name;
52
+ const metricId = makeMetricId(scopeId, metricName);
53
+ if (!this.metricMetadataMap.has(metricId)) {
54
+ const { dataPoints: _dataPoints, ...metadata } = metricData;
55
+ this.metricMetadataMap.set(metricId, metadata);
56
+ }
57
+ for (const dp of metricData.dataPoints) {
58
+ const startTime = dp.startTime[0] * 1_000_000_000 + dp.startTime[1];
59
+ const endTime = dp.endTime[0] * 1_000_000_000 + dp.endTime[1];
60
+ const attributes = dp.attributes;
61
+ const attributesId = attributesToId(attributes);
62
+ const seriesId = makeSeriesId(metricId, attributesId);
63
+ if (!this.series.has(seriesId)) {
64
+ this.series.set(seriesId, new Series_js_1.Series({ hash: 0, labels: attributes, originalAttributes: attributes }, this.metricMetadataMap.get(metricId), this.chunkSize, this.maxChunks));
65
+ (this.metricIdIndex.get(metricId) ?? this.metricIdIndex.set(metricId, new Set()).get(metricId)).add(seriesId);
66
+ }
67
+ this.series.get(seriesId).append(startTime, endTime, dp.value);
68
+ }
69
+ }
70
+ }
71
+ }
72
+ query(scopeMetrics, startTime, endTime) {
73
+ // If no queries provided, get all scopeMetrics
74
+ if (!scopeMetrics || scopeMetrics.length === 0) {
75
+ const queries = Array.from(this.metricIdIndex.keys()).map(indexKey => {
76
+ const [scopeId, metricName] = indexKey.split(':').slice(0, 2);
77
+ const scope = this.scopes.get(scopeId);
78
+ return {
79
+ scope,
80
+ descriptor: { name: metricName },
81
+ filters: undefined
82
+ };
83
+ });
84
+ return queries
85
+ .map(query => this._querySingle(query, startTime, endTime))
86
+ .filter((result) => result !== null);
87
+ }
88
+ return scopeMetrics
89
+ .map(query => this._querySingle(query, startTime, endTime))
90
+ .filter((result) => result !== null);
91
+ }
92
+ /**
93
+ * Query single metric with attribute filters
94
+ */
95
+ _querySingle(query, startTime, endTime) {
96
+ const scopeId = scopeToId(query.scope);
97
+ const indexKey = makeMetricId(scopeId, query.descriptor.name);
98
+ const seriesKeysInMetric = this.metricIdIndex.get(indexKey);
99
+ if (!seriesKeysInMetric || seriesKeysInMetric.size === 0) {
100
+ return null;
101
+ }
102
+ const scope = this.scopes.get(scopeId);
103
+ const metricData = this.metricMetadataMap.get(indexKey);
104
+ if (!scope || !metricData) {
105
+ return null;
106
+ }
107
+ // Filter by attributes if provided
108
+ const filteredSeriesKeys = query.filters
109
+ ? Array.from(seriesKeysInMetric).filter(key => {
110
+ const series = this.series.get(key);
111
+ return this._matchesAttributeFilters(series, query.filters);
112
+ })
113
+ : Array.from(seriesKeysInMetric);
114
+ if (filteredSeriesKeys.length === 0) {
115
+ return null;
116
+ }
117
+ const matchingSeries = filteredSeriesKeys
118
+ .map(key => {
119
+ const series = this.series.get(key);
120
+ const { startTimes, endTimes, values } = series.querySlices({ startTime, endTime, includeStartTimes: true });
121
+ return {
122
+ id: key,
123
+ attributes: series.getOriginalAttributes(),
124
+ startTimes: startTimes ? Array.from(startTimes) : undefined,
125
+ endTimes: Array.from(endTimes),
126
+ values: Array.isArray(values) ? values : Array.from(values)
127
+ };
128
+ })
129
+ .filter(s => s.endTimes.length > 0);
130
+ return {
131
+ scope,
132
+ descriptor: metricData.descriptor,
133
+ series: matchingSeries
134
+ };
135
+ }
136
+ /**
137
+ * Match series attributes against filters
138
+ * Supports exact match, negation (!), and regex (~)
139
+ */
140
+ _matchesAttributeFilters(series, filters) {
141
+ if (!filters || Object.keys(filters).length === 0) {
142
+ return true;
143
+ }
144
+ const attrs = series.getOriginalAttributes();
145
+ for (const [key, filterValue] of Object.entries(filters)) {
146
+ const attrValue = String(attrs[key] ?? '');
147
+ // Regex match: status=~4.*
148
+ if (filterValue.startsWith('~')) {
149
+ const pattern = filterValue.slice(1);
150
+ try {
151
+ const regex = new RegExp(pattern);
152
+ if (!regex.test(attrValue)) {
153
+ return false;
154
+ }
155
+ }
156
+ catch {
157
+ if (attrValue !== filterValue) {
158
+ return false;
159
+ }
160
+ }
161
+ }
162
+ // Negation: status=!200
163
+ else if (filterValue.startsWith('!')) {
164
+ const negatedValue = filterValue.slice(1);
165
+ if (attrValue === negatedValue) {
166
+ return false;
167
+ }
168
+ }
169
+ // Exact match: method=GET
170
+ else {
171
+ if (attrValue !== filterValue) {
172
+ return false;
173
+ }
174
+ }
175
+ }
176
+ return true;
177
+ }
178
+ evictOldData(retentionTimeNs) {
179
+ const thresholdTime = Date.now() * 1_000_000 - retentionTimeNs;
180
+ let evictedChunks = 0;
181
+ let evictedSeries = 0;
182
+ for (const [key, series] of this.series.entries()) {
183
+ evictedChunks += series.evictOldChunks(thresholdTime);
184
+ if (series.isEmpty()) {
185
+ this.series.delete(key);
186
+ evictedSeries++;
187
+ }
188
+ }
189
+ return { evictedChunks, evictedSeries };
190
+ }
191
+ getStats() {
192
+ const seriesStats = Array.from(this.series.values()).map(s => s.getStats());
193
+ const totalSamples = seriesStats.reduce((sum, s) => sum + s.samples, 0);
194
+ const totalMemory = seriesStats.reduce((sum, s) => sum + s.memoryBytes, 0);
195
+ return {
196
+ totalMetrics: this.metricMetadataMap.size,
197
+ totalScopes: this.scopes.size,
198
+ totalSeries: this.series.size,
199
+ totalSamples,
200
+ memoryUsageBytes: totalMemory
201
+ };
202
+ }
203
+ reset() {
204
+ this.series.clear();
205
+ this.scopes.clear();
206
+ this.metricMetadataMap.clear();
207
+ this.metricIdIndex.clear();
208
+ }
209
+ size() {
210
+ return this.series.size;
211
+ }
212
+ /**
213
+ * Serialize registry to NDJSON format (newline-delimited JSON)
214
+ * Each line is a complete record: metadata, scope, metric, or data point
215
+ * Format:
216
+ * {"type":"header","version":1,"timestamp":"...","stats":{...}}
217
+ * {"type":"scope","id":"...","data":{...}}
218
+ * {"type":"metric","id":"...","data":{...}}
219
+ * {"type":"series","id":"...","labelSet":{...},"chunks":[...]}
220
+ */
221
+ serializeToNDJSON() {
222
+ const lines = [];
223
+ // Header
224
+ lines.push(JSON.stringify({
225
+ type: 'header',
226
+ version: 1,
227
+ timestamp: new Date().toISOString(),
228
+ stats: this.getStats()
229
+ }));
230
+ // Scopes
231
+ for (const [scopeId, scope] of this.scopes.entries()) {
232
+ lines.push(JSON.stringify({
233
+ type: 'scope',
234
+ id: scopeId,
235
+ data: scope
236
+ }));
237
+ }
238
+ // Metric metadata
239
+ for (const [metricId, metadata] of this.metricMetadataMap.entries()) {
240
+ lines.push(JSON.stringify({
241
+ type: 'metric',
242
+ id: metricId,
243
+ data: metadata
244
+ }));
245
+ }
246
+ // Series headers + chunks (one chunk per line for streaming efficiency)
247
+ const serializedSeriesHeaders = new Set();
248
+ for (const [seriesId, series] of this.series.entries()) {
249
+ const seriesPrivate = series;
250
+ // Emit series header once per series
251
+ if (!serializedSeriesHeaders.has(seriesId)) {
252
+ lines.push(JSON.stringify({
253
+ type: 'series',
254
+ seriesId: seriesId,
255
+ labelSet: seriesPrivate.labelSet,
256
+ metadata: seriesPrivate.metadata
257
+ }));
258
+ serializedSeriesHeaders.add(seriesId);
259
+ }
260
+ (seriesPrivate.chunks || []).forEach((chunk, chunkIndex) => {
261
+ const slicedStartTimes = chunk.startTimes.slice(0, chunk.cursor);
262
+ const slicedEndTimes = chunk.endTimes.slice(0, chunk.cursor);
263
+ const slicedValues = chunk.values.slice(0, chunk.cursor);
264
+ const slicedHistograms = chunk.histograms.slice(0, chunk.cursor);
265
+ lines.push(JSON.stringify({
266
+ type: 'chunk',
267
+ seriesId: seriesId,
268
+ chunkIndex: chunkIndex,
269
+ startTimes: Array.from(slicedStartTimes),
270
+ endTimes: Array.from(slicedEndTimes),
271
+ values: Array.from(slicedValues),
272
+ histograms: Array.from(slicedHistograms),
273
+ cursor: chunk.cursor,
274
+ minEndTime: chunk.minEndTime,
275
+ maxEndTime: chunk.maxEndTime,
276
+ isHistogram: chunk.isHistogram
277
+ }));
278
+ });
279
+ }
280
+ // Metric ID index for fast lookup
281
+ for (const [metricId, seriesIdSet] of this.metricIdIndex.entries()) {
282
+ lines.push(JSON.stringify({
283
+ type: 'index',
284
+ id: metricId,
285
+ seriesIds: Array.from(seriesIdSet)
286
+ }));
287
+ }
288
+ return lines.join('\n');
289
+ }
290
+ /**
291
+ * Deserialize from NDJSON format - restore from chunk lines
292
+ */
293
+ deserializeFromNDJSON(ndjsonData) {
294
+ try {
295
+ const lines = ndjsonData.trim().split('\n');
296
+ for (const line of lines) {
297
+ if (!line.trim())
298
+ continue;
299
+ const record = JSON.parse(line);
300
+ switch (record.type) {
301
+ case 'header':
302
+ // Just metadata
303
+ break;
304
+ case 'scope':
305
+ this.scopes.set(record.id, record.data);
306
+ break;
307
+ case 'metric':
308
+ this.metricMetadataMap.set(record.id, record.data);
309
+ break;
310
+ case 'index':
311
+ this.metricIdIndex.set(record.id, new Set(record.seriesIds));
312
+ break;
313
+ case 'series': {
314
+ // Create series stub - will be populated by subsequent chunk lines
315
+ const metadata = this.metricMetadataMap.get(record.seriesId.substring(0, record.seriesId.lastIndexOf('$'))) || record.metadata;
316
+ if (metadata) {
317
+ const series = new Series_js_1.Series(record.labelSet, metadata, this.chunkSize, this.maxChunks);
318
+ this.series.set(record.seriesId, series);
319
+ }
320
+ break;
321
+ }
322
+ case 'chunk': {
323
+ // Restore chunk to series
324
+ const series = this.series.get(record.seriesId);
325
+ if (series) {
326
+ const chunk = new Chunk_js_1.Chunk(record.cursor || record.startTimes.length, record.isHistogram);
327
+ const chunkPrivate = chunk;
328
+ chunkPrivate.startTimes = new Float64Array(record.startTimes);
329
+ chunkPrivate.endTimes = new Float64Array(record.endTimes);
330
+ chunkPrivate.values = new Float64Array(record.values);
331
+ chunkPrivate.histograms = record.histograms;
332
+ chunkPrivate.cursor = record.cursor;
333
+ chunkPrivate.minEndTime = record.minEndTime;
334
+ chunkPrivate.maxEndTime = record.maxEndTime;
335
+ chunkPrivate.isHistogram = record.isHistogram;
336
+ const seriesPrivate = series;
337
+ seriesPrivate.chunks.push(chunk);
338
+ }
339
+ break;
340
+ }
341
+ }
342
+ }
343
+ }
344
+ catch {
345
+ // Silently fail if any parsing fails
346
+ }
347
+ }
348
+ /**
349
+ * Save registry to disk as NDJSON (one chunk per line)
350
+ */
351
+ saveToDisk(filePath) {
352
+ try {
353
+ const ndjsonData = this.serializeToNDJSON();
354
+ fs_1.default.writeFileSync(filePath, ndjsonData);
355
+ }
356
+ catch {
357
+ // Silently fail - don't interrupt operations
358
+ }
359
+ }
360
+ /**
361
+ * Load registry from disk (NDJSON format)
362
+ */
363
+ loadFromDisk(filePath) {
364
+ try {
365
+ if (!fs_1.default.existsSync(filePath)) {
366
+ return;
367
+ }
368
+ const ndjsonData = fs_1.default.readFileSync(filePath, 'utf-8');
369
+ this.deserializeFromNDJSON(ndjsonData);
370
+ }
371
+ catch {
372
+ // Silently fail during boot
373
+ }
374
+ }
375
+ }
376
+ exports.SeriesRegistry = SeriesRegistry;
377
+ // Utility: Create deterministic ID from attributes
378
+ function attributesToId(attributes) {
379
+ return Object.keys(attributes).sort().map(key => `${key}=${attributes[key]}`).join(',') || 'no_attrs';
380
+ }
381
+ function scopeToId(scope) {
382
+ return `${scope.name}@${scope.version ?? 'no_version'}`;
383
+ }
384
+ function makeMetricId(scopeId, metricName) {
385
+ return `${scopeId}:${metricName}`;
386
+ }
387
+ function makeSeriesId(metricId, attributesId) {
388
+ return `${metricId}$${attributesId}`;
389
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rawToOtel = rawToOtel;
4
+ /**
5
+ * Convert raw format to OpenTelemetry format
6
+ *
7
+ * Raw format structure (same for GET response and INSERT input):
8
+ * {
9
+ * scope: { name, version },
10
+ * descriptor: { unit, description, ... },
11
+ * series: [{ attributes, startTimes[], endTimes[], values[] }]
12
+ * }
13
+ *
14
+ * OTEL format structure:
15
+ * {
16
+ * scope: { name, version },
17
+ * metrics: [{ descriptor, dataPoints: [{ attributes, startTime, endTime, value }] }]
18
+ * }
19
+ *
20
+ * Groups dataPoints by endTime to reconstruct original exports
21
+ */
22
+ function rawToOtel(rawScopeMetrics) {
23
+ const groupedByScope = new Map();
24
+ for (const result of rawScopeMetrics) {
25
+ // Validate that result matches expected raw format
26
+ if (!result.scope) {
27
+ throw new Error(`Invalid metric format: Missing 'scope' property. ` +
28
+ `Expected format: {scope: {name, version}, descriptor: {name, ...}, series: [{attributes, startTimes, endTimes, values}]}. ` +
29
+ `Got: ${JSON.stringify(result).substring(0, 200)}`);
30
+ }
31
+ if (!result.descriptor) {
32
+ throw new Error(`Invalid metric format: Missing 'descriptor' property in metric. ` +
33
+ `Expected format: {scope: {name, version}, descriptor: {name, ...}, series: [{attributes, startTimes, endTimes, values}]}`);
34
+ }
35
+ if (!Array.isArray(result.series)) {
36
+ throw new Error(`Invalid metric format: 'series' must be an array. ` +
37
+ `Expected format: {scope: {name, version}, descriptor: {name, ...}, series: [{attributes, startTimes, endTimes, values}]}`);
38
+ }
39
+ const scopeId = result.scope.version
40
+ ? `${result.scope.name}@${result.scope.version}`
41
+ : `${result.scope.name}@none`;
42
+ if (!groupedByScope.has(scopeId)) {
43
+ groupedByScope.set(scopeId, {
44
+ scope: {
45
+ name: result.scope.name,
46
+ version: result.scope.version || ''
47
+ },
48
+ metrics: []
49
+ });
50
+ }
51
+ const scopeData = groupedByScope.get(scopeId);
52
+ const dataPoints = [];
53
+ for (const series of result.series) {
54
+ for (let i = 0; i < series.endTimes.length; i++) {
55
+ const startTimeNs = series.startTimes?.[i];
56
+ const endTimeNs = series.endTimes[i];
57
+ if (!startTimeNs)
58
+ continue;
59
+ const startSec = Math.floor(startTimeNs / 1_000_000_000);
60
+ const startNano = startTimeNs % 1_000_000_000;
61
+ const endSec = Math.floor(endTimeNs / 1_000_000_000);
62
+ const endNano = endTimeNs % 1_000_000_000;
63
+ dataPoints.push({
64
+ attributes: series.attributes,
65
+ startTime: [startSec, startNano],
66
+ endTime: [endSec, endNano],
67
+ value: series.values[i]
68
+ });
69
+ }
70
+ }
71
+ scopeData.metrics.push({
72
+ descriptor: result.descriptor,
73
+ dataPoints
74
+ });
75
+ }
76
+ return Array.from(groupedByScope.values());
77
+ }
@@ -1,70 +1,72 @@
1
1
  "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
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.DynamicMultiLogRecordProcessor = void 0;
7
- var _core = require("@opentelemetry/core");
8
- var _logger = _interopRequireDefault(require("../../../utils/logger.cjs"));
9
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
- // optional if you want logging
7
+ const core_1 = require("@opentelemetry/core");
8
+ const logger_js_1 = __importDefault(require("../../../utils/logger.cjs")); // optional if you want logging
11
9
  class DynamicMultiLogRecordProcessor {
12
- constructor(initialProcessors = [], forceFlushTimeoutMillis = 30000) {
13
- this._processors = [];
14
- this._processors = [...initialProcessors];
15
- this._forceFlushTimeoutMillis = forceFlushTimeoutMillis;
16
- }
17
- /**
18
- * Add a new LogRecordProcessor or an array of LogRecordProcessors at runtime.
19
- */
20
- addProcessors(processor) {
21
- if (Array.isArray(processor)) {
22
- this._processors.push(...processor);
23
- } else {
24
- this._processors.push(processor);
10
+ _processors = [];
11
+ _forceFlushTimeoutMillis;
12
+ constructor(initialProcessors = [], forceFlushTimeoutMillis = 30000) {
13
+ this._processors = [...initialProcessors];
14
+ this._forceFlushTimeoutMillis = forceFlushTimeoutMillis;
25
15
  }
26
- }
27
- /**
28
- * Remove a specific LogRecordProcessor.
29
- */
30
- removeProcessor(processor) {
31
- this._processors = this._processors.filter(p => p !== processor);
32
- }
33
- /**
34
- * Clear all LogRecordProcessors.
35
- */
36
- clearProcessors() {
37
- this._processors = [];
38
- }
39
- /**
40
- * Called when a log record is emitted.
41
- */
42
- onEmit(logRecord, context) {
43
- for (const processor of this._processors) {
44
- try {
45
- processor.onEmit(logRecord, context);
46
- } catch (error) {
47
- _logger.default?.error?.('Error in onEmit of LogRecordProcessor:', error);
48
- }
16
+ /**
17
+ * Add a new LogRecordProcessor or an array of LogRecordProcessors at runtime.
18
+ */
19
+ addProcessors(processor) {
20
+ if (Array.isArray(processor)) {
21
+ this._processors.push(...processor);
22
+ }
23
+ else {
24
+ this._processors.push(processor);
25
+ }
49
26
  }
50
- }
51
- /**
52
- * Force flush all processors with timeout.
53
- */
54
- async forceFlush() {
55
- const timeout = this._forceFlushTimeoutMillis;
56
- const promises = this._processors.map(p => (0, _core.callWithTimeout)(p.forceFlush(), timeout));
57
- try {
58
- await Promise.all(promises);
59
- } catch (error) {
60
- _logger.default?.error?.('Error during forceFlush in DynamicMultiLogRecordProcessor:', error);
27
+ /**
28
+ * Remove a specific LogRecordProcessor.
29
+ */
30
+ removeProcessor(processor) {
31
+ this._processors = this._processors.filter(p => p !== processor);
32
+ }
33
+ /**
34
+ * Clear all LogRecordProcessors.
35
+ */
36
+ clearProcessors() {
37
+ this._processors = [];
38
+ }
39
+ /**
40
+ * Called when a log record is emitted.
41
+ */
42
+ onEmit(logRecord, context) {
43
+ for (const processor of this._processors) {
44
+ try {
45
+ processor.onEmit(logRecord, context);
46
+ }
47
+ catch (error) {
48
+ logger_js_1.default?.error?.('Error in onEmit of LogRecordProcessor:', error);
49
+ }
50
+ }
51
+ }
52
+ /**
53
+ * Force flush all processors with timeout.
54
+ */
55
+ async forceFlush() {
56
+ const timeout = this._forceFlushTimeoutMillis;
57
+ const promises = this._processors.map(p => (0, core_1.callWithTimeout)(p.forceFlush(), timeout));
58
+ try {
59
+ await Promise.all(promises);
60
+ }
61
+ catch (error) {
62
+ logger_js_1.default?.error?.('Error during forceFlush in DynamicMultiLogRecordProcessor:', error);
63
+ }
64
+ }
65
+ /**
66
+ * Shutdown all processors.
67
+ */
68
+ async shutdown() {
69
+ await Promise.all(this._processors.map(p => p.shutdown()));
61
70
  }
62
- }
63
- /**
64
- * Shutdown all processors.
65
- */
66
- async shutdown() {
67
- await Promise.all(this._processors.map(p => p.shutdown()));
68
- }
69
71
  }
70
- exports.DynamicMultiLogRecordProcessor = DynamicMultiLogRecordProcessor;
72
+ exports.DynamicMultiLogRecordProcessor = DynamicMultiLogRecordProcessor;