@oas-tools/oas-telemetry 0.6.2 → 0.7.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 (131) hide show
  1. package/README.md +442 -442
  2. package/dist/{config.cjs → cjs/config.cjs} +6 -7
  3. package/dist/{exporters → cjs/exporters}/InMemoryDBMetricsExporter.cjs +5 -40
  4. package/dist/cjs/exporters/InMemoryDbExporter.cjs +87 -0
  5. package/dist/cjs/exporters/InMemoryLogRecordExporter.cjs +110 -0
  6. package/dist/{exporters → cjs/exporters}/consoleExporter.cjs +2 -7
  7. package/dist/{exporters → cjs/exporters}/dynamicExporter.cjs +12 -19
  8. package/dist/cjs/index.cjs +43 -0
  9. package/dist/cjs/instrumentation/index.cjs +28 -0
  10. package/dist/cjs/instrumentation/logs.cjs +46 -0
  11. package/dist/cjs/instrumentation/metrics.cjs +27 -0
  12. package/dist/cjs/instrumentation/traces.cjs +19 -0
  13. package/dist/{openTelemetry.cjs → cjs/openTelemetry.cjs} +6 -8
  14. package/dist/{systemMetrics.cjs → cjs/systemMetrics.cjs} +7 -7
  15. package/dist/cjs/tlm-ai/agent.cjs +79 -0
  16. package/dist/cjs/tlm-ai/aiController.cjs +69 -0
  17. package/dist/cjs/tlm-ai/aiRoutes.cjs +13 -0
  18. package/dist/cjs/tlm-ai/knownMicroservices.cjs +13 -0
  19. package/dist/cjs/tlm-ai/tools.cjs +504 -0
  20. package/dist/{routes/authRoutes.cjs → cjs/tlm-auth/authController.cjs} +21 -28
  21. package/dist/{middleware → cjs/tlm-auth}/authMiddleware.cjs +1 -1
  22. package/dist/cjs/tlm-auth/authRoutes.cjs +14 -0
  23. package/dist/cjs/tlm-log/logController.cjs +55 -0
  24. package/dist/cjs/tlm-log/logRoutes.cjs +13 -0
  25. package/dist/{routes → cjs/tlm-metric}/metricsRoutes.cjs +1 -2
  26. package/dist/{controllers → cjs/tlm-plugin}/pluginController.cjs +31 -41
  27. package/dist/cjs/tlm-plugin/pluginRoutes.cjs +13 -0
  28. package/dist/{controllers/telemetryController.cjs → cjs/tlm-trace/traceController.cjs} +8 -19
  29. package/dist/cjs/tlm-trace/traceRoutes.cjs +17 -0
  30. package/dist/cjs/tlm-ui/uiController.cjs +27 -0
  31. package/dist/cjs/tlm-ui/uiRoutes.cjs +31 -0
  32. package/dist/cjs/tlm-util/utilController.cjs +63 -0
  33. package/dist/cjs/tlm-util/utilRoutes.cjs +12 -0
  34. package/dist/cjs/tlmRoutes.cjs +79 -0
  35. package/dist/cjs/types/index.cjs +8 -0
  36. package/dist/cjs/utils/circular.cjs +90 -0
  37. package/dist/cjs/utils/logger.cjs +28 -0
  38. package/{src → dist/esm}/config.js +20 -23
  39. package/{src → dist/esm}/exporters/InMemoryDBMetricsExporter.js +57 -111
  40. package/dist/esm/exporters/InMemoryDbExporter.js +87 -0
  41. package/dist/esm/exporters/InMemoryLogRecordExporter.js +95 -0
  42. package/{src → dist/esm}/exporters/consoleExporter.js +38 -47
  43. package/{src → dist/esm}/exporters/dynamicExporter.js +50 -62
  44. package/dist/esm/index.js +39 -0
  45. package/dist/esm/instrumentation/index.js +26 -0
  46. package/dist/esm/instrumentation/logs.js +34 -0
  47. package/dist/esm/instrumentation/metrics.js +18 -0
  48. package/dist/esm/instrumentation/traces.js +12 -0
  49. package/{src → dist/esm}/openTelemetry.js +50 -58
  50. package/dist/esm/systemMetrics.js +82 -0
  51. package/dist/esm/tlm-ai/agent.js +68 -0
  52. package/dist/esm/tlm-ai/aiController.js +45 -0
  53. package/dist/esm/tlm-ai/aiRoutes.js +7 -0
  54. package/dist/esm/tlm-ai/knownMicroservices.js +5 -0
  55. package/dist/esm/tlm-ai/tools.js +490 -0
  56. package/dist/esm/tlm-auth/authController.js +41 -0
  57. package/{src/middleware → dist/esm/tlm-auth}/authMiddleware.js +12 -14
  58. package/dist/esm/tlm-auth/authRoutes.js +7 -0
  59. package/dist/esm/tlm-log/logController.js +36 -0
  60. package/dist/esm/tlm-log/logRoutes.js +7 -0
  61. package/{src/controllers → dist/esm/tlm-metric}/metricsController.js +28 -30
  62. package/{src/routes → dist/esm/tlm-metric}/metricsRoutes.js +8 -15
  63. package/{src/controllers → dist/esm/tlm-plugin}/pluginController.js +103 -115
  64. package/dist/esm/tlm-plugin/pluginRoutes.js +7 -0
  65. package/dist/esm/tlm-trace/traceController.js +54 -0
  66. package/dist/esm/tlm-trace/traceRoutes.js +11 -0
  67. package/dist/esm/tlm-ui/uiController.js +20 -0
  68. package/dist/esm/tlm-ui/uiRoutes.js +23 -0
  69. package/dist/esm/tlm-util/utilController.js +57 -0
  70. package/dist/esm/tlm-util/utilRoutes.js +6 -0
  71. package/dist/esm/tlmRoutes.js +72 -0
  72. package/dist/esm/types/index.js +4 -0
  73. package/dist/esm/utils/circular.js +84 -0
  74. package/dist/esm/utils/logger.js +19 -0
  75. package/dist/types/config.d.ts +6 -0
  76. package/dist/types/exporters/InMemoryDBMetricsExporter.d.ts +15 -0
  77. package/dist/types/exporters/InMemoryDbExporter.d.ts +24 -0
  78. package/dist/types/exporters/InMemoryLogRecordExporter.d.ts +27 -0
  79. package/dist/types/exporters/consoleExporter.d.ts +13 -0
  80. package/dist/types/exporters/dynamicExporter.d.ts +25 -0
  81. package/dist/types/index.d.ts +8 -0
  82. package/dist/types/instrumentation/index.d.ts +1 -0
  83. package/dist/types/instrumentation/logs.d.ts +1 -0
  84. package/dist/types/instrumentation/metrics.d.ts +1 -0
  85. package/dist/types/instrumentation/traces.d.ts +1 -0
  86. package/dist/types/openTelemetry.d.ts +1 -0
  87. package/dist/types/systemMetrics.d.ts +26 -0
  88. package/dist/types/tlm-ai/agent.d.ts +1 -0
  89. package/dist/types/tlm-ai/aiController.d.ts +4 -0
  90. package/dist/types/tlm-ai/aiRoutes.d.ts +2 -0
  91. package/dist/types/tlm-ai/knownMicroservices.d.ts +6 -0
  92. package/dist/types/tlm-ai/tools.d.ts +45 -0
  93. package/dist/types/tlm-auth/authController.d.ts +4 -0
  94. package/dist/types/tlm-auth/authMiddleware.d.ts +2 -0
  95. package/dist/types/tlm-auth/authRoutes.d.ts +2 -0
  96. package/dist/types/tlm-log/logController.d.ts +4 -0
  97. package/dist/types/tlm-log/logRoutes.d.ts +2 -0
  98. package/dist/types/tlm-metric/metricsController.d.ts +4 -0
  99. package/dist/types/tlm-metric/metricsRoutes.d.ts +2 -0
  100. package/dist/types/tlm-plugin/pluginController.d.ts +3 -0
  101. package/dist/types/tlm-plugin/pluginRoutes.d.ts +2 -0
  102. package/dist/types/tlm-trace/traceController.d.ts +7 -0
  103. package/dist/types/tlm-trace/traceRoutes.d.ts +2 -0
  104. package/dist/types/tlm-ui/uiController.d.ts +8 -0
  105. package/dist/types/tlm-ui/uiRoutes.d.ts +2 -0
  106. package/dist/types/tlm-util/utilController.d.ts +3 -0
  107. package/dist/types/tlm-util/utilRoutes.d.ts +2 -0
  108. package/dist/types/tlmRoutes.d.ts +2 -0
  109. package/dist/types/types/index.d.ts +56 -0
  110. package/dist/types/utils/circular.d.ts +31 -0
  111. package/dist/types/utils/logger.d.ts +9 -0
  112. package/dist/ui/assets/index-BNhZBPi2.css +1 -0
  113. package/dist/ui/assets/index-DxGAMrAl.js +401 -0
  114. package/dist/ui/index.html +14 -0
  115. package/dist/ui/vite.svg +1 -0
  116. package/package.json +80 -77
  117. package/dist/controllers/uiController.cjs +0 -78
  118. package/dist/exporters/InMemoryDbExporter.cjs +0 -178
  119. package/dist/index.cjs +0 -110
  120. package/dist/routes/telemetryRoutes.cjs +0 -31
  121. package/dist/services/uiService.cjs +0 -1520
  122. package/src/controllers/telemetryController.js +0 -69
  123. package/src/controllers/uiController.js +0 -69
  124. package/src/dev/ui/login.html +0 -32
  125. package/src/exporters/InMemoryDbExporter.js +0 -181
  126. package/src/index.js +0 -121
  127. package/src/routes/authRoutes.js +0 -53
  128. package/src/routes/telemetryRoutes.js +0 -38
  129. package/src/services/uiService.js +0 -1520
  130. package/src/systemMetrics.js +0 -102
  131. /package/dist/{controllers → cjs/tlm-metric}/metricsController.cjs +0 -0
@@ -0,0 +1,490 @@
1
+ import axios from 'axios';
2
+ import { globalOasTlmConfig } from '../config.js';
3
+ import logger from '../utils/logger.js';
4
+ import { getKnownMicroservices } from './knownMicroservices.js';
5
+ const getTraces = async (searchInput) => {
6
+ logger.debug("getTraces called with searchInput:", searchInput);
7
+ try {
8
+ const search = searchInput || {};
9
+ const traces = await new Promise((resolve, reject) => {
10
+ globalOasTlmConfig.dynamicSpanExporter.exporter.find(search, (err, docs) => {
11
+ if (err)
12
+ reject(err);
13
+ else
14
+ resolve(docs);
15
+ });
16
+ });
17
+ const simplifiedTraces = getSimplifiedTraces(traces);
18
+ logger.debug(`Searching for traces with searchInput: ${JSON.stringify(search)}`);
19
+ logger.debug(`Traces found: ${JSON.stringify(simplifiedTraces.length)}`);
20
+ return { traces: simplifiedTraces };
21
+ }
22
+ catch (error) {
23
+ logger.error('Error fetching traces:', error);
24
+ throw error;
25
+ }
26
+ };
27
+ const getLogs = async (startDate, endDate) => {
28
+ logger.debug("getLogs called with startDate:", startDate, "endDate:", endDate);
29
+ try {
30
+ let nedbQuery = {};
31
+ if (!startDate && !endDate) {
32
+ logger.debug("No date range provided, fetching all logs.");
33
+ }
34
+ else {
35
+ logger.debug(`Fetching logs from ${startDate} to ${endDate}`);
36
+ nedbQuery = {
37
+ timestamp: {
38
+ $gte: startDate ? new Date(startDate).getTime() : 0, // Epoch ms
39
+ $lte: endDate ? new Date(endDate).getTime() : Date.now() // Epoch ms
40
+ }
41
+ };
42
+ }
43
+ const logs = [];
44
+ await new Promise((resolve, reject) => {
45
+ globalOasTlmConfig.debugExporter.find(nedbQuery, null, (err, docs) => {
46
+ if (err) {
47
+ reject(err);
48
+ }
49
+ else {
50
+ logs.push(...docs);
51
+ logger.debug(`Found ${logs.length} logs in the specified range.`);
52
+ resolve();
53
+ }
54
+ });
55
+ });
56
+ const simplifiedLogs = getSimplifiedLogs(logs);
57
+ return { logs: simplifiedLogs };
58
+ }
59
+ catch (error) {
60
+ logger.error('Error fetching logs:', error);
61
+ throw error;
62
+ }
63
+ };
64
+ const getMetrics = async (searchInput) => {
65
+ logger.debug("getMetrics called with searchInput:", searchInput);
66
+ try {
67
+ const search = searchInput || {};
68
+ const metrics = await new Promise((resolve, reject) => {
69
+ globalOasTlmConfig.metricsExporter.find(search, (err, docs) => {
70
+ if (err)
71
+ reject(err);
72
+ else
73
+ resolve(docs || []);
74
+ });
75
+ });
76
+ const simplifiedMetrics = getSimplifiedMetrics(metrics);
77
+ logger.debug(`Searching for metrics with searchInput: ${JSON.stringify(search)}`);
78
+ logger.debug(`Metrics found: ${JSON.stringify(simplifiedMetrics.length)}`);
79
+ return { metrics: simplifiedMetrics };
80
+ }
81
+ catch (error) {
82
+ logger.error('Error fetching metrics:', error);
83
+ throw error;
84
+ }
85
+ };
86
+ const getCurrentTimestampInEpoch = () => {
87
+ logger.debug("Getting the current timestamp in epoch format...");
88
+ const now = new Date();
89
+ return { currentTimestampInEpoch: now.getTime(), currentTimestampInEpochSeconds: Math.floor(now.getTime() / 1000) };
90
+ };
91
+ const startTelemetry = () => {
92
+ logger.debug("Starting telemetry...");
93
+ globalOasTlmConfig.dynamicSpanExporter.exporter.start();
94
+ };
95
+ const stopTelemetry = () => {
96
+ logger.debug("Stopping telemetry...");
97
+ globalOasTlmConfig.dynamicSpanExporter.exporter.stop();
98
+ };
99
+ const resetTelemetry = () => {
100
+ logger.debug("Resetting telemetry...");
101
+ globalOasTlmConfig.dynamicSpanExporter.exporter.reset();
102
+ };
103
+ const getTelemetryStatus = () => {
104
+ logger.debug("Getting telemetry status...");
105
+ const isRunning = globalOasTlmConfig.dynamicSpanExporter.exporter.isRunning() || false;
106
+ return { active: isRunning };
107
+ };
108
+ const talkToExternalMicroserviceAgent = async (message, microserviceId) => {
109
+ logger.debug("talkToExternalMicroserviceAgent called with question:", message, "microservice:", microserviceId);
110
+ const knownMicroservices = getKnownMicroservices();
111
+ const identifiedMicroservice = knownMicroservices.find(m => m.id === microserviceId);
112
+ if (!identifiedMicroservice) {
113
+ logger.error(`Agent tried to call an unknown microservice: ${microserviceId}, available microservices: ${knownMicroservices.map(m => m.id).join(', ')}`);
114
+ return {
115
+ microservice: microserviceId,
116
+ response: `I cannot help with that. The microservice ${microserviceId} is not recognized. Available microservices are: ${knownMicroservices.map(m => m.id).join(', ')}`
117
+ };
118
+ }
119
+ const microserviceResponse = await axios.post(identifiedMicroservice.url, {
120
+ question: message
121
+ });
122
+ return {
123
+ microservice: microserviceId,
124
+ response: microserviceResponse.data
125
+ };
126
+ };
127
+ const getMicroserviceAgents = () => {
128
+ logger.debug("Getting microservice agents...");
129
+ return getKnownMicroservices();
130
+ };
131
+ const tools = [
132
+ {
133
+ type: "function",
134
+ function: {
135
+ name: "getTraces",
136
+ description: `Fetches trace data for the microservice.
137
+ Traces provide detailed information about requests and their lifecycle, including HTTP attributes (e.g., URL, method, status code),
138
+ network details (e.g., peer IP, port), and timing information.
139
+ The 'searchInput' parameter is an object used to filter traces based on specific criteria.
140
+ This is a NeDB query using MongoDB-like syntax (neDB). If 'searchInput' is null, all traces will be fetched.
141
+ Providing specific filters improves performance.
142
+
143
+ Available properties for filtering:
144
+ {
145
+ "name": "GET", // Name of the span
146
+ "kind": 1, // 1 for incoming requests, 2 for outgoing requests
147
+ "attributes": {
148
+ "http": {
149
+ "url": "http://localhost:3002/api/v1/greet",
150
+ "host": "localhost:3002",
151
+ "method": "GET",
152
+ "scheme": "http",
153
+ "target": "/api/v1/greet",
154
+ "user_agent": "PostmanRuntime/7.44.0",
155
+ "request_content_length_uncompressed": 39,
156
+ "flavor": "1.1",
157
+ "status_code": 200,
158
+ "status_text": "OK"
159
+ },
160
+ "net": {
161
+ "host": {
162
+ "name": "localhost",
163
+ "ip": "::1",
164
+ "port": 3002
165
+ },
166
+ "transport": "ip_tcp",
167
+ "peer": {
168
+ "ip": "::1",
169
+ "port": 50361
170
+ }
171
+ }
172
+ },
173
+ "traceId": "5f7df252eb00e873bbd6441f86b71dac",
174
+ "spanId": "fbd8ea558dd6ac32",
175
+ "service": "oas-telemetry-service",
176
+ "startTime": { "0": 1747666254, "1": 333000000 },
177
+ "endTime": { "0": 1747666254, "1": 335071700 },
178
+ "_duration": { "0": 0, "1": 2071700 }
179
+ }
180
+
181
+
182
+ you can use $or, or $gte or operators like that if needed never > or similar.
183
+ Take into account that startTime.0 and endTime.0 are in epoch SECONDS format not milliseconds.
184
+ For time search ALWAYS use "endTime.0": { "$gte": number } or similar with other operators and startTime.0.
185
+ Common filters include HTTP attributes (e.g., method, status code, URL), timestamps (e.g., 'endTime.0'), or duration ('_duration').
186
+
187
+ Example 'query':
188
+ {
189
+ "attributes.http.method": "GET",
190
+ "attributes.http.status_code": 200, //when asked for ANY error you can use $gte : 400 operator
191
+ "attributes.http.url": "http://localhost:3002/api/v1/greet",
192
+ "_duration": { "$lte": 5000000 },
193
+ "endTime.0": { "$gte": 1747666254 },
194
+ }
195
+ you must give a {searchInput: query} object to the function
196
+
197
+ `,
198
+ parameters: {
199
+ type: "object",
200
+ properties: {
201
+ searchInput: {
202
+ type: "object",
203
+ description: `Optional search criteria for filtering traces.
204
+ This is a NeDB query using MongoDB-like (neDB) syntax.
205
+ For example, you can filter by HTTP attributes, timestamps, or duration.
206
+ If null, all traces will be returned.`,
207
+ additionalProperties: true
208
+ }
209
+ },
210
+ required: ["searchInput"]
211
+ }
212
+ }
213
+ },
214
+ {
215
+ type: "function",
216
+ function: {
217
+ name: "getLogs",
218
+ description: `Fetches log data for the microservice.
219
+ Logs provide information about system events, including timestamps, log levels (e.g., info, error), and messages.
220
+ The 'startDate' and 'endDate' parameters define the time range for fetching logs.
221
+ If don't provide a range, all logs will be fetched. Providing a specific range improves performance.
222
+ Example 'startDate' and 'endDate':
223
+ {
224
+ "startDate": "2023-10-01T00:00:00Z",
225
+ "endDate": "2023-10-02T00:00:00Z"
226
+ }
227
+ Common filters include timestamps or log levels.`,
228
+ parameters: {
229
+ type: "object",
230
+ properties: {
231
+ startDate: {
232
+ type: "string"
233
+ },
234
+ endDate: {
235
+ type: "string"
236
+ }
237
+ },
238
+ }
239
+ }
240
+ },
241
+ {
242
+ type: "function",
243
+ function: {
244
+ name: "getMetrics",
245
+ description: `Fetches metrics data for the microservice.
246
+ Metrics provide performance-related data, such as CPU usage, memory usage, and process-specific metrics.
247
+ The 'searchInput' parameter is an object used to filter metrics based on specific criteria.
248
+ This is a NeDB query using MongoDB-like (NeDB) syntax. If 'searchInput' is null, all metrics will be fetched. Providing specific filters improves performance.
249
+
250
+ Example 'searchInput':
251
+ {
252
+ "timestamp": { "$gte": 1747651105757, "$lte": 1747651200935 }
253
+ }
254
+
255
+ Common filters include timestamps.`,
256
+ parameters: {
257
+ type: "object",
258
+ properties: {
259
+ searchInput: {
260
+ type: "object",
261
+ description: `Optional search criteria for filtering metrics.
262
+ This is a NeDB query using MongoDB-like (NeDB) syntax.
263
+ For example, you can filter by timestamps.
264
+ If null, all metrics will be returned.`,
265
+ properties: {
266
+ "timestamp": { type: "object", properties: { "$gte": { type: "integer" }, "$lte": { type: "integer" } } },
267
+ "cpuUsageData.cpuNumber": { type: "string" },
268
+ "memoryData.used": { type: "integer" }
269
+ }
270
+ }
271
+ },
272
+ required: ["searchInput"]
273
+ }
274
+ }
275
+ },
276
+ {
277
+ type: "function",
278
+ function: {
279
+ name: "startTelemetry",
280
+ description: `Starts the telemetry data collection process.
281
+ This function initializes the telemetry system and begins capturing trace, log, and metric data.`,
282
+ parameters: {}
283
+ }
284
+ },
285
+ {
286
+ type: "function",
287
+ function: {
288
+ name: "stopTelemetry",
289
+ description: `Stops the telemetry data collection process.
290
+ This function halts the telemetry system and stops capturing trace, log, and metric data.`,
291
+ parameters: {}
292
+ }
293
+ },
294
+ {
295
+ type: "function",
296
+ function: {
297
+ name: "resetTelemetry",
298
+ description: `Resets the telemetry data collection process.
299
+ This function clears any existing telemetry data and prepares the system for a fresh start.`,
300
+ parameters: {}
301
+ }
302
+ },
303
+ {
304
+ type: "function",
305
+ function: {
306
+ name: "getTelemetryStatus",
307
+ description: `Retrieves the current status of the telemetry system.
308
+ This function checks whether the telemetry system is currently active or inactive.`,
309
+ parameters: {}
310
+ }
311
+ },
312
+ {
313
+ type: "function",
314
+ function: {
315
+ name: "getCurrentTimestampInEpoch",
316
+ description: `Retrieves the current timestamp in epoch format (miliseconds or seconds).
317
+ This function calculates the timestamp for the current moment in milliseconds since the Unix epoch.in .currentTimestampInEpoch. Also returns the current timestamp in seconds in .currentTimestampInEpochSeconds.`,
318
+ parameters: {}
319
+ }
320
+ },
321
+ {
322
+ type: "function",
323
+ function: {
324
+ name: "talkToExternalMicroserviceAgent",
325
+ description: `Use this function to communicate with external microservice agent.
326
+ if you want to talk to a microservice agent, you must provide the message and the microservice you want to talk to.
327
+ When you call this function, it will send the message to the specified microservice and return the response.
328
+
329
+ Example 'message':
330
+ {
331
+ "message": "What is the status of the service?",
332
+ "microservice": "Reporter"
333
+ }
334
+
335
+ Microservices Availables (by ID):
336
+ ${getKnownMicroservices().map(m => m.id).join(", ")}
337
+ `,
338
+ parameters: {
339
+ type: "object",
340
+ properties: {
341
+ message: {
342
+ type: "string",
343
+ description: `The message to be sent to the external microservice agent.`
344
+ },
345
+ microservice: {
346
+ type: "string"
347
+ }
348
+ },
349
+ required: ["message", "microservice"]
350
+ }
351
+ }
352
+ },
353
+ {
354
+ type: "function",
355
+ function: {
356
+ name: "getMicroserviceAgents",
357
+ description: `Retrieves the list of available microservice agents.
358
+ This function provides information about the microservices that can be communicated with.`,
359
+ parameters: {}
360
+ }
361
+ }
362
+ ];
363
+ const availableTools = {
364
+ getTraces,
365
+ getLogs,
366
+ getMetrics,
367
+ startTelemetry,
368
+ stopTelemetry,
369
+ resetTelemetry,
370
+ getTelemetryStatus,
371
+ getCurrentTimestampInEpoch,
372
+ talkToExternalMicroserviceAgent,
373
+ getMicroserviceAgents
374
+ };
375
+ export { tools, availableTools, };
376
+ function getSimplifiedMetrics(metrics) {
377
+ return metrics.map(resourceMetric => {
378
+ const serviceName = resourceMetric.resource?._memoizedAttributes?.service?.name || 'unknown-service';
379
+ const cpuUtilization = {};
380
+ let cpuCount = 0;
381
+ const memoryUsageMB = { used: 0, free: 0 };
382
+ const memoryUtilizationPercent = { used: 0, free: 0 };
383
+ const networkIO = { transmit: 0, receive: 0 };
384
+ const processCPU = {};
385
+ let processMemoryUsage = 0;
386
+ for (const scopeMetric of resourceMetric.scopeMetrics) {
387
+ for (const metric of scopeMetric.metrics) {
388
+ const name = metric.descriptor.name;
389
+ if (name === 'system.cpu.utilization') {
390
+ const stateSums = {};
391
+ const stateCounts = {};
392
+ for (const dp of metric.dataPoints) {
393
+ const state = dp.attributes?.system?.cpu?.state;
394
+ if (!state)
395
+ continue;
396
+ // @ts-expect-error index signature
397
+ stateSums[state] = (stateSums[state] || 0) + dp.value;
398
+ // @ts-expect-error index signature
399
+ stateCounts[state] = (stateCounts[state] || 0) + 1;
400
+ }
401
+ for (const state in stateSums) {
402
+ // @ts-expect-error index signature
403
+ cpuUtilization[state] = stateSums[state] / stateCounts[state];
404
+ }
405
+ cpuCount = Math.max(...metric.dataPoints.map((dp) => parseInt(dp.attributes?.system?.cpu?.debugical_number || 0, 10))) + 1;
406
+ }
407
+ if (name === 'system.memory.usage') {
408
+ for (const dp of metric.dataPoints) {
409
+ const state = dp.attributes?.system?.memory?.state;
410
+ // @ts-expect-error index signature
411
+ if (state)
412
+ memoryUsageMB[state] = dp.value;
413
+ }
414
+ }
415
+ if (name === 'system.memory.utilization') {
416
+ for (const dp of metric.dataPoints) {
417
+ const state = dp.attributes?.system?.memory?.state;
418
+ // @ts-expect-error index signature
419
+ if (state)
420
+ memoryUtilizationPercent[state] = dp.value;
421
+ }
422
+ }
423
+ if (name === 'system.network.io') {
424
+ for (const dp of metric.dataPoints) {
425
+ const direction = dp.attributes?.network?.io?.direction;
426
+ // @ts-expect-error index signature
427
+ if (direction)
428
+ networkIO[direction] += dp.value;
429
+ }
430
+ }
431
+ if (name === 'process.cpu.time') {
432
+ for (const dp of metric.dataPoints) {
433
+ const state = dp.attributes?.process?.cpu?.state;
434
+ // @ts-expect-error index signature
435
+ if (state)
436
+ processCPU[state] = dp.value;
437
+ }
438
+ }
439
+ if (name === 'process.memory.usage') {
440
+ processMemoryUsage = metric.dataPoints[0]?.value || 0;
441
+ }
442
+ }
443
+ }
444
+ return {
445
+ service: serviceName,
446
+ cpu: {
447
+ avgUtilization: cpuUtilization,
448
+ cores: cpuCount,
449
+ },
450
+ memory: {
451
+ usedGB: (memoryUsageMB.used || 0) / (1024 ** 3),
452
+ freeGB: (memoryUsageMB.free || 0) / (1024 ** 3),
453
+ usedPercent: (memoryUtilizationPercent.used || 0) * 100,
454
+ freePercent: (1 - (memoryUtilizationPercent.used || 0)) * 100,
455
+ },
456
+ network: {
457
+ transmittedMB: networkIO.transmit / (1024 ** 2),
458
+ receivedMB: networkIO.receive / (1024 ** 2),
459
+ },
460
+ process: {
461
+ cpuTimeSec: processCPU,
462
+ memoryUsageMB: processMemoryUsage / (1024 ** 2),
463
+ }
464
+ };
465
+ });
466
+ }
467
+ function getSimplifiedTraces(spans) {
468
+ return spans.map((span) => {
469
+ return {
470
+ name: span.name,
471
+ kind: span.kind,
472
+ attributes: span.attributes,
473
+ resource: span.resource,
474
+ _spanContext: span._spanContext,
475
+ startTime: span.startTime,
476
+ endTime: span.endTime,
477
+ _duration: span._duration
478
+ };
479
+ });
480
+ }
481
+ function getSimplifiedLogs(logs) {
482
+ return logs.map((log) => ({
483
+ service: log.resource?.attributes?.service?.name || undefined,
484
+ timestamp: log.timestamp,
485
+ message: log.body,
486
+ traceId: log.traceId,
487
+ spanId: log.spanId,
488
+ source: log.attributes?.source?.source || undefined,
489
+ }));
490
+ }
@@ -0,0 +1,41 @@
1
+ import { globalOasTlmConfig } from '../config.js';
2
+ import jwt from 'jsonwebtoken';
3
+ import logger from '../utils/logger.js';
4
+ export const login = (req, res) => {
5
+ try {
6
+ const { password } = req.body;
7
+ if (password === globalOasTlmConfig.password) {
8
+ const options = {
9
+ maxAge: globalOasTlmConfig.apiKeyMaxAge,
10
+ httpOnly: true,
11
+ secure: true,
12
+ signed: false
13
+ };
14
+ const apiKey = jwt.sign({ password: globalOasTlmConfig.password }, globalOasTlmConfig.jwtSecret);
15
+ res.cookie('apiKey', apiKey, options);
16
+ res.status(200).json({ valid: true, message: 'API Key is valid' });
17
+ return;
18
+ }
19
+ res.status(400).json({ valid: false, message: 'Invalid API Key' });
20
+ }
21
+ catch (error) {
22
+ logger.log("Error: ", error);
23
+ res.status(500).json({ valid: false, message: 'Internal server error' });
24
+ }
25
+ };
26
+ export const logout = (req, res) => {
27
+ res.clearCookie('apiKey');
28
+ res.redirect(globalOasTlmConfig.baseURL + '/login');
29
+ };
30
+ export const check = (req, res) => {
31
+ if (!req.cookies.apiKey) {
32
+ res.status(200).json({ valid: false, message: 'API Key is invalid' });
33
+ return;
34
+ }
35
+ const decoded = jwt.verify(req.cookies.apiKey, globalOasTlmConfig.jwtSecret);
36
+ if (decoded.password === globalOasTlmConfig.password) {
37
+ res.status(200).json({ valid: true, message: 'API Key is valid' });
38
+ return;
39
+ }
40
+ res.status(200).json({ valid: false, message: 'Invalid API Key' });
41
+ };
@@ -1,14 +1,12 @@
1
- import { globalOasTlmConfig } from "../config.js";
2
- import jwt from 'jsonwebtoken';
3
-
4
- export function authMiddleware(req, res, next) {
5
- const apiKey = req.cookies.apiKey;
6
- if (apiKey) {
7
- const decoded = jwt.verify(apiKey, globalOasTlmConfig.jwtSecret);
8
- if (decoded.password === globalOasTlmConfig.password) {
9
- return next();
10
- }
11
- }
12
- res.status(401).redirect(globalOasTlmConfig.baseURL + '/login');
13
-
14
- }
1
+ import { globalOasTlmConfig } from "../config.js";
2
+ import jwt from 'jsonwebtoken';
3
+ export function authMiddleware(req, res, next) {
4
+ const apiKey = req.cookies.apiKey;
5
+ if (apiKey) {
6
+ const decoded = jwt.verify(apiKey, globalOasTlmConfig.jwtSecret);
7
+ if (decoded.password === globalOasTlmConfig.password) {
8
+ return next();
9
+ }
10
+ }
11
+ res.status(401).redirect(globalOasTlmConfig.baseURL + '/login');
12
+ }
@@ -0,0 +1,7 @@
1
+ import { Router } from 'express';
2
+ import { login, logout, check } from './authController.js';
3
+ const router = Router();
4
+ router.post('/login', login);
5
+ router.get('/logout', logout);
6
+ router.get('/check', check);
7
+ export default router;
@@ -0,0 +1,36 @@
1
+ import { globalOasTlmConfig } from '../config.js';
2
+ export const listLogs = async (req, res) => {
3
+ try {
4
+ const logs = globalOasTlmConfig.logExporter.getFinishedSpans();
5
+ res.send({ logsCount: logs.length, logs: logs });
6
+ }
7
+ catch (err) {
8
+ console.error(err);
9
+ res.status(500).send({ error: 'Failed to list log data' });
10
+ }
11
+ };
12
+ export const findLogs = async (req, res) => {
13
+ const body = req.body;
14
+ const messageSearch = body?.search || null; // Search term for MiniSearch
15
+ const findQuery = body?.find || {}; // Query for NeDB
16
+ console.dir(`findLogs called with query: ${JSON.stringify(findQuery)} and search ${messageSearch}`, { depth: 3 });
17
+ try {
18
+ const results = await new Promise((resolve, reject) => {
19
+ globalOasTlmConfig.logExporter.find(findQuery, messageSearch, (err, docs) => {
20
+ if (err)
21
+ return reject(err);
22
+ resolve(docs);
23
+ });
24
+ });
25
+ const typedResults = results;
26
+ res.send({ logsCount: typedResults.length, logs: typedResults });
27
+ }
28
+ catch (err) {
29
+ console.error(err);
30
+ res.status(500).send({ error: 'Failed to find logs', details: err.message });
31
+ }
32
+ };
33
+ export const resetLogs = (req, res) => {
34
+ globalOasTlmConfig.logExporter.reset();
35
+ res.send('Logs reset');
36
+ };
@@ -0,0 +1,7 @@
1
+ import { Router } from 'express';
2
+ import { listLogs, findLogs, resetLogs } from './logController.js';
3
+ export const logRoutes = Router();
4
+ logRoutes.get('/', listLogs);
5
+ logRoutes.post('/find', findLogs);
6
+ logRoutes.get('/reset', resetLogs);
7
+ export default logRoutes;
@@ -1,30 +1,28 @@
1
- import { globalOasTlmConfig } from '../config.js';
2
-
3
- export const listMetrics = async (req, res) => {
4
- try {
5
- const metrics = await globalOasTlmConfig.metricsExporter.getFinishedMetrics();
6
- res.send({ metricsCount: metrics.length, metrics: metrics });
7
- } catch (err) {
8
- console.error(err);
9
- res.status(500).send({ error: 'Failed to list metrics data' });
10
- }
11
- }
12
-
13
- export const findMetrics = (req, res) => {
14
- const body = req.body;
15
- const search = body?.search ? body.search : {};
16
- globalOasTlmConfig.metricsExporter.find(search, (err, docs) => {
17
- if (err) {
18
- console.error(err);
19
- res.status(404).send({ metricsCount: 0, metrics: [], error: err });
20
- return;
21
- }
22
- const metrics = docs;
23
- res.send({ metricsCount: metrics.length, metrics: metrics });
24
- });
25
- }
26
-
27
- export const resetMetrics = (req, res) => {
28
- globalOasTlmConfig.metricsExporter.reset();
29
- res.send('Metrics reset');
30
- }
1
+ import { globalOasTlmConfig } from '../config.js';
2
+ export const listMetrics = async (req, res) => {
3
+ try {
4
+ const metrics = await globalOasTlmConfig.metricsExporter.getFinishedMetrics();
5
+ res.send({ metricsCount: metrics.length, metrics: metrics });
6
+ }
7
+ catch (err) {
8
+ console.error(err);
9
+ res.status(500).send({ error: 'Failed to list metrics data' });
10
+ }
11
+ };
12
+ export const findMetrics = (req, res) => {
13
+ const body = req.body;
14
+ const search = body?.search ? body.search : {};
15
+ globalOasTlmConfig.metricsExporter.find(search, (err, docs) => {
16
+ if (err) {
17
+ console.error(err);
18
+ res.status(404).send({ metricsCount: 0, metrics: [], error: err });
19
+ return;
20
+ }
21
+ const metrics = docs;
22
+ res.send({ metricsCount: metrics.length, metrics: metrics });
23
+ });
24
+ };
25
+ export const resetMetrics = (req, res) => {
26
+ globalOasTlmConfig.metricsExporter.reset();
27
+ res.send('Metrics reset');
28
+ };