@oas-tools/oas-telemetry 0.7.0-alpha.5 → 0.7.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 (106) hide show
  1. package/.env.example +2 -0
  2. package/README.md +35 -17
  3. package/dist/cjs/config/bootConfig.cjs +3 -1
  4. package/dist/cjs/docs/openapi.yaml +1399 -0
  5. package/dist/cjs/routesManager.cjs +1 -1
  6. package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbLogExporter.cjs +43 -13
  7. package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.cjs +10 -2
  8. package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.cjs +21 -16
  9. package/dist/cjs/telemetry/initializeTelemetry.cjs +39 -15
  10. package/dist/cjs/telemetry/telemetryConfigurator.cjs +6 -9
  11. package/dist/cjs/telemetry/telemetryRegistry.cjs +11 -8
  12. package/dist/cjs/tlm-ai/agent.cjs +54 -84
  13. package/dist/cjs/tlm-ai/aiController.cjs +69 -47
  14. package/dist/cjs/tlm-ai/aiRoutes.cjs +10 -3
  15. package/dist/cjs/tlm-ai/aiService.cjs +109 -0
  16. package/dist/cjs/tlm-ai/tools.cjs +30 -268
  17. package/dist/cjs/tlm-auth/authController.cjs +9 -9
  18. package/dist/cjs/tlm-auth/authMiddleware.cjs +1 -1
  19. package/dist/cjs/tlm-log/logController.cjs +30 -36
  20. package/dist/cjs/tlm-log/logRoutes.cjs +3 -2
  21. package/dist/cjs/tlm-metric/metricsController.cjs +15 -8
  22. package/dist/cjs/tlm-metric/metricsRoutes.cjs +2 -1
  23. package/dist/cjs/tlm-plugin/pluginController.cjs +11 -1
  24. package/dist/cjs/tlm-plugin/pluginProcess.cjs +4 -2
  25. package/dist/cjs/tlm-plugin/pluginService.cjs +3 -0
  26. package/dist/cjs/tlm-trace/traceController.cjs +16 -9
  27. package/dist/cjs/tlm-trace/traceRoutes.cjs +2 -1
  28. package/dist/cjs/tlm-util/utilController.cjs +23 -2
  29. package/dist/cjs/tlm-util/utilRoutes.cjs +44 -5
  30. package/dist/cjs/utils/logger.cjs +35 -13
  31. package/dist/esm/config/bootConfig.js +2 -0
  32. package/dist/esm/docs/openapi.yaml +1399 -0
  33. package/dist/esm/routesManager.js +1 -1
  34. package/dist/esm/telemetry/custom-implementations/exporters/InMemoryDbLogExporter.js +32 -11
  35. package/dist/esm/telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.js +10 -2
  36. package/dist/esm/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.js +20 -13
  37. package/dist/esm/telemetry/initializeTelemetry.js +22 -14
  38. package/dist/esm/telemetry/telemetryConfigurator.js +7 -10
  39. package/dist/esm/telemetry/telemetryRegistry.js +10 -7
  40. package/dist/esm/tlm-ai/agent.js +37 -78
  41. package/dist/esm/tlm-ai/aiController.js +56 -39
  42. package/dist/esm/tlm-ai/aiRoutes.js +11 -4
  43. package/dist/esm/tlm-ai/aiService.js +94 -0
  44. package/dist/esm/tlm-ai/tools.js +29 -255
  45. package/dist/esm/tlm-auth/authController.js +8 -8
  46. package/dist/esm/tlm-auth/authMiddleware.js +1 -1
  47. package/dist/esm/tlm-log/logController.js +26 -28
  48. package/dist/esm/tlm-log/logRoutes.js +4 -3
  49. package/dist/esm/tlm-metric/metricsController.js +10 -6
  50. package/dist/esm/tlm-metric/metricsRoutes.js +3 -2
  51. package/dist/esm/tlm-plugin/pluginController.js +2 -1
  52. package/dist/esm/tlm-plugin/pluginProcess.js +4 -2
  53. package/dist/esm/tlm-plugin/pluginService.js +4 -0
  54. package/dist/esm/tlm-trace/traceController.js +11 -7
  55. package/dist/esm/tlm-trace/traceRoutes.js +3 -2
  56. package/dist/esm/tlm-util/utilController.js +22 -0
  57. package/dist/esm/tlm-util/utilRoutes.js +40 -5
  58. package/dist/esm/utils/logger.js +35 -12
  59. package/dist/types/config/bootConfig.d.ts +1 -0
  60. package/dist/types/telemetry/custom-implementations/exporters/InMemoryDbLogExporter.d.ts +7 -1
  61. package/dist/types/telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.d.ts +1 -0
  62. package/dist/types/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.d.ts +1 -0
  63. package/dist/types/telemetry/telemetryRegistry.d.ts +22 -6
  64. package/dist/types/tlm-ai/agent.d.ts +2 -2
  65. package/dist/types/tlm-ai/aiController.d.ts +5 -4
  66. package/dist/types/tlm-ai/aiRoutes.d.ts +1 -1
  67. package/dist/types/tlm-ai/aiService.d.ts +38 -0
  68. package/dist/types/tlm-ai/tools.d.ts +5 -14
  69. package/dist/types/tlm-log/logController.d.ts +2 -2
  70. package/dist/types/tlm-metric/metricsController.d.ts +2 -1
  71. package/dist/types/tlm-plugin/pluginService.d.ts +2 -0
  72. package/dist/types/tlm-trace/traceController.d.ts +2 -1
  73. package/dist/types/tlm-util/utilController.d.ts +1 -0
  74. package/dist/types/utils/logger.d.ts +5 -5
  75. package/dist/ui/assets/ApiDocsPage-C_VVPPHa.js +16 -0
  76. package/dist/ui/assets/CollapsibleCard-B3KR_8mL.js +1 -0
  77. package/dist/ui/assets/DevToolsPage-OyZcDcmw.js +1 -0
  78. package/dist/ui/assets/LandingPage-CppFBA6K.js +6 -0
  79. package/dist/ui/assets/LogsPage-9Fq8GArS.js +26 -0
  80. package/dist/ui/assets/NotFoundPage-B3quk3P1.js +1 -0
  81. package/dist/ui/assets/PluginCreatePage-X_aCH4t4.js +50 -0
  82. package/dist/ui/assets/PluginPage-DMDSihrZ.js +27 -0
  83. package/dist/ui/assets/alert-jQ9HCPIf.js +1133 -0
  84. package/dist/ui/assets/badge-CNq0-mH5.js +1 -0
  85. package/dist/ui/assets/card-DFAwwhN3.js +1 -0
  86. package/dist/ui/assets/chevron-down-CPsvsmqj.js +6 -0
  87. package/dist/ui/assets/chevron-up-Df9jMo1X.js +6 -0
  88. package/dist/ui/assets/circle-alert-DOPQPvU8.js +6 -0
  89. package/dist/ui/assets/index-BkD6DijD.js +15 -0
  90. package/dist/ui/assets/index-CERGVYZK.js +292 -0
  91. package/dist/ui/assets/index-CSIPf9qw.css +1 -0
  92. package/dist/ui/assets/input-Dzvg_ZEZ.js +1 -0
  93. package/dist/ui/assets/label-DuVnkZ4q.js +1 -0
  94. package/dist/ui/assets/loader-circle-CrvlRy5o.js +6 -0
  95. package/dist/ui/assets/loginPage-qa4V-B70.js +6 -0
  96. package/dist/ui/assets/select-DhS8YUtJ.js +1 -0
  97. package/dist/ui/assets/separator-isK4chBP.js +6 -0
  98. package/dist/ui/assets/severityOptions-O38dSOfk.js +11 -0
  99. package/dist/ui/assets/switch-Z3mImG9n.js +1 -0
  100. package/dist/ui/assets/tabs-_77MUUQe.js +16 -0
  101. package/dist/ui/assets/upload-C1LT4Gkb.js +16 -0
  102. package/dist/ui/assets/utilService-DNyqzwj0.js +1 -0
  103. package/dist/ui/index.html +2 -2
  104. package/package.json +17 -6
  105. package/dist/ui/assets/index-Bgd7fFFH.js +0 -1743
  106. package/dist/ui/assets/index-Cz3N1n1Q.css +0 -1
@@ -0,0 +1,94 @@
1
+ import OpenAI from 'openai';
2
+ import { agent } from './agent.js';
3
+ class AIService {
4
+ constructor(config) {
5
+ this.config = config;
6
+ this.conversations = new Map();
7
+ this.openai = new OpenAI({
8
+ apiKey: this.config.apiKey,
9
+ });
10
+ this.model = config.model;
11
+ this.extraPrompts = config.extraPrompts || [];
12
+ }
13
+ createConversation() {
14
+ const id = Math.random().toString(36).substring(2, 15);
15
+ const conversation = { id, messages: [] };
16
+ this.conversations.set(id, conversation);
17
+ return conversation;
18
+ }
19
+ listConversations() {
20
+ return Array.from(this.conversations.values());
21
+ }
22
+ getConversation(id) {
23
+ return this.conversations.get(id);
24
+ }
25
+ deleteConversation(id) {
26
+ return this.conversations.delete(id);
27
+ }
28
+ async sendMessage(conversationId, content, model) {
29
+ const conversation = this.conversations.get(conversationId);
30
+ if (!conversation)
31
+ throw new Error('Conversation not found');
32
+ conversation.messages.push({
33
+ role: 'system',
34
+ timestamp: new Date().toISOString(),
35
+ content: "This is a telemetry chat. Focus your replies strictly on the topics and instructions defined by the system prompts and the available tools. Do not answer outside of these boundaries. Reply in the same language as the question."
36
+ });
37
+ if (this.extraPrompts.length > 0) {
38
+ this.extraPrompts.forEach(prompt => {
39
+ conversation.messages.push({ role: 'system', content: prompt, timestamp: new Date().toISOString() });
40
+ });
41
+ }
42
+ conversation.messages.push({ role: 'user', content, timestamp: new Date().toISOString() });
43
+ // Set conversation name if not set
44
+ if (!('name' in conversation) || !conversation.name) {
45
+ conversation.name = content.slice(0, 30);
46
+ }
47
+ // Use the agent function with tools
48
+ // Internaly pushes new messages to conversation.messages
49
+ const currentMessagesCount = conversation.messages.length;
50
+ await agent(this.openai, conversation.messages, model || this.model, this.extraPrompts);
51
+ // Return the last assistant message (the one just added by agent)
52
+ const generatedMessages = conversation.messages.slice(currentMessagesCount);
53
+ return generatedMessages;
54
+ }
55
+ listConversationsMinimal() {
56
+ return Array.from(this.conversations.values()).map(c => ({
57
+ id: c.id,
58
+ name: c.name,
59
+ }));
60
+ }
61
+ async listModels() {
62
+ const { data } = await this.openai.models.list();
63
+ return data
64
+ .map(m => m.id)
65
+ .sort();
66
+ }
67
+ async isValidModel(modelId) {
68
+ try {
69
+ await this.openai.models.retrieve(modelId);
70
+ return true;
71
+ }
72
+ catch {
73
+ return false;
74
+ }
75
+ }
76
+ }
77
+ let aiService;
78
+ export function configureAiService(config) {
79
+ const openAIKey = config.ai?.openAIKey;
80
+ const model = config.ai.openAIModel;
81
+ const extraPrompts = config.ai.extraContextPrompts;
82
+ if (!openAIKey)
83
+ throw new Error('OpenAI API key is required');
84
+ aiService = new AIService({
85
+ apiKey: openAIKey,
86
+ model,
87
+ extraPrompts
88
+ });
89
+ }
90
+ export function getAiService() {
91
+ if (!aiService)
92
+ throw new Error('AI Service not configured');
93
+ return aiService;
94
+ }
@@ -1,6 +1,4 @@
1
- import axios from 'axios';
2
1
  import logger from '../utils/logger.js';
3
- import { getKnownMicroservices } from './knownMicroservices.js';
4
2
  import { inMemoryDbLogExporter, inMemoryDbMetricExporter, inMemoryDbSpanExporter } from '../telemetry/telemetryRegistry.js';
5
3
  const getTraces = async (searchInput) => {
6
4
  logger.debug("getTraces called with searchInput:", searchInput);
@@ -27,32 +25,22 @@ const getTraces = async (searchInput) => {
27
25
  const getLogs = async (startDate, endDate) => {
28
26
  logger.debug("getLogs called with startDate:", startDate, "endDate:", endDate);
29
27
  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
- inMemoryDbLogExporter.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
- });
28
+ // Timestamps are stored in microseconds in the DB (must multiply by 1000)
29
+ const startEpoch = startDate ? new Date(startDate).getTime() * 1000 : 0;
30
+ const endEpoch = endDate ? new Date(endDate).getTime() * 1000 : Date.now() * 1000;
31
+ logger.debug(`Fetching logs from ${startEpoch} to ${endEpoch}`);
32
+ const nedbQuery = {
33
+ timestamp: {
34
+ $gte: startEpoch,
35
+ $lte: endEpoch
36
+ }
37
+ };
38
+ const logs = (await inMemoryDbLogExporter.find({
39
+ query: nedbQuery,
40
+ messageSearch: null,
41
+ limit: 50 // or any appropriate limit
42
+ })) || [];
43
+ logger.debug(`Found ${logs.length} logs in the specified range.`);
56
44
  const simplifiedLogs = getSimplifiedLogs(logs);
57
45
  return { logs: simplifiedLogs };
58
46
  }
@@ -61,33 +49,6 @@ const getLogs = async (startDate, endDate) => {
61
49
  throw error;
62
50
  }
63
51
  };
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
- inMemoryDbMetricExporter.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
52
  const startTelemetry = () => {
92
53
  logger.debug("Starting telemetry...");
93
54
  inMemoryDbSpanExporter.enable();
@@ -114,28 +75,10 @@ const getTelemetryStatus = () => {
114
75
  metricsEnabled: inMemoryDbMetricExporter.isEnabled()
115
76
  };
116
77
  };
117
- const talkToExternalMicroserviceAgent = async (message, microserviceId) => {
118
- logger.debug("talkToExternalMicroserviceAgent called with question:", message, "microservice:", microserviceId);
119
- const knownMicroservices = getKnownMicroservices();
120
- const identifiedMicroservice = knownMicroservices.find(m => m.id === microserviceId);
121
- if (!identifiedMicroservice) {
122
- logger.error(`Agent tried to call an unknown microservice: ${microserviceId}, available microservices: ${knownMicroservices.map(m => m.id).join(', ')}`);
123
- return {
124
- microservice: microserviceId,
125
- response: `I cannot help with that. The microservice ${microserviceId} is not recognized. Available microservices are: ${knownMicroservices.map(m => m.id).join(', ')}`
126
- };
127
- }
128
- const microserviceResponse = await axios.post(identifiedMicroservice.url, {
129
- question: message
130
- });
131
- return {
132
- microservice: microserviceId,
133
- response: microserviceResponse.data
134
- };
135
- };
136
- const getMicroserviceAgents = () => {
137
- logger.debug("Getting microservice agents...");
138
- return getKnownMicroservices();
78
+ const getCurrentDate = () => {
79
+ logger.debug("Getting the current date in ISO format...");
80
+ const now = new Date();
81
+ return { currentDateISO: now.toISOString() };
139
82
  };
140
83
  const tools = [
141
84
  {
@@ -227,7 +170,8 @@ const tools = [
227
170
  description: `Fetches log data for the microservice.
228
171
  Logs provide information about system events, including timestamps, log levels (e.g., info, error), and messages.
229
172
  The 'startDate' and 'endDate' parameters define the time range for fetching logs.
230
- If don't provide a range, all logs will be fetched. Providing a specific range improves performance.
173
+ If you need a date, you MUST first call the "getCurrentDate" tool to obtain the current date in ISO format, and then use it as a parameter.
174
+ If you don't provide a range, all logs will be fetched. Providing a specific range improves performance.
231
175
  Example 'startDate' and 'endDate':
232
176
  {
233
177
  "startDate": "2023-10-01T00:00:00Z",
@@ -247,41 +191,6 @@ const tools = [
247
191
  }
248
192
  }
249
193
  },
250
- {
251
- type: "function",
252
- function: {
253
- name: "getMetrics",
254
- description: `Fetches metrics data for the microservice.
255
- Metrics provide performance-related data, such as CPU usage, memory usage, and process-specific metrics.
256
- The 'searchInput' parameter is an object used to filter metrics based on specific criteria.
257
- This is a NeDB query using MongoDB-like (NeDB) syntax. If 'searchInput' is null, all metrics will be fetched. Providing specific filters improves performance.
258
-
259
- Example 'searchInput':
260
- {
261
- "timestamp": { "$gte": 1747651105757, "$lte": 1747651200935 }
262
- }
263
-
264
- Common filters include timestamps.`,
265
- parameters: {
266
- type: "object",
267
- properties: {
268
- searchInput: {
269
- type: "object",
270
- description: `Optional search criteria for filtering metrics.
271
- This is a NeDB query using MongoDB-like (NeDB) syntax.
272
- For example, you can filter by timestamps.
273
- If null, all metrics will be returned.`,
274
- properties: {
275
- "timestamp": { type: "object", properties: { "$gte": { type: "integer" }, "$lte": { type: "integer" } } },
276
- "cpuUsageData.cpuNumber": { type: "string" },
277
- "memoryData.used": { type: "integer" }
278
- }
279
- }
280
- },
281
- required: ["searchInput"]
282
- }
283
- }
284
- },
285
194
  {
286
195
  type: "function",
287
196
  function: {
@@ -321,50 +230,9 @@ const tools = [
321
230
  {
322
231
  type: "function",
323
232
  function: {
324
- name: "getCurrentTimestampInEpoch",
325
- description: `Retrieves the current timestamp in epoch format (miliseconds or seconds).
326
- 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.`,
327
- parameters: {}
328
- }
329
- },
330
- {
331
- type: "function",
332
- function: {
333
- name: "talkToExternalMicroserviceAgent",
334
- description: `Use this function to communicate with external microservice agent.
335
- if you want to talk to a microservice agent, you must provide the message and the microservice you want to talk to.
336
- When you call this function, it will send the message to the specified microservice and return the response.
337
-
338
- Example 'message':
339
- {
340
- "message": "What is the status of the service?",
341
- "microservice": "Reporter"
342
- }
343
-
344
- Microservices Availables (by ID):
345
- ${getKnownMicroservices().map(m => m.id).join(", ")}
346
- `,
347
- parameters: {
348
- type: "object",
349
- properties: {
350
- message: {
351
- type: "string",
352
- description: `The message to be sent to the external microservice agent.`
353
- },
354
- microservice: {
355
- type: "string"
356
- }
357
- },
358
- required: ["message", "microservice"]
359
- }
360
- }
361
- },
362
- {
363
- type: "function",
364
- function: {
365
- name: "getMicroserviceAgents",
366
- description: `Retrieves the list of available microservice agents.
367
- This function provides information about the microservices that can be communicated with.`,
233
+ name: "getCurrentDate",
234
+ description: `Returns the current date in ISO 8601 format (e.g., "2024-06-07T12:34:56.789Z").
235
+ Use this tool to obtain the current date when you need to specify a date for other tools, such as "getLogs".`,
368
236
  parameters: {}
369
237
  }
370
238
  }
@@ -372,107 +240,13 @@ const tools = [
372
240
  const availableTools = {
373
241
  getTraces,
374
242
  getLogs,
375
- getMetrics,
376
243
  startTelemetry,
377
244
  stopTelemetry,
378
245
  resetTelemetry,
379
246
  getTelemetryStatus,
380
- getCurrentTimestampInEpoch,
381
- talkToExternalMicroserviceAgent,
382
- getMicroserviceAgents
247
+ getCurrentDate
383
248
  };
384
249
  export { tools, availableTools, };
385
- function getSimplifiedMetrics(metrics) {
386
- return metrics.map(resourceMetric => {
387
- const serviceName = resourceMetric.resource?._memoizedAttributes?.service?.name || 'unknown-service';
388
- const cpuUtilization = {};
389
- let cpuCount = 0;
390
- const memoryUsageMB = { used: 0, free: 0 };
391
- const memoryUtilizationPercent = { used: 0, free: 0 };
392
- const networkIO = { transmit: 0, receive: 0 };
393
- const processCPU = {};
394
- let processMemoryUsage = 0;
395
- for (const scopeMetric of resourceMetric.scopeMetrics) {
396
- for (const metric of scopeMetric.metrics) {
397
- const name = metric.descriptor.name;
398
- if (name === 'system.cpu.utilization') {
399
- const stateSums = {};
400
- const stateCounts = {};
401
- for (const dp of metric.dataPoints) {
402
- const state = dp.attributes?.system?.cpu?.state;
403
- if (!state)
404
- continue;
405
- // @ts-expect-error index signature
406
- stateSums[state] = (stateSums[state] || 0) + dp.value;
407
- // @ts-expect-error index signature
408
- stateCounts[state] = (stateCounts[state] || 0) + 1;
409
- }
410
- for (const state in stateSums) {
411
- // @ts-expect-error index signature
412
- cpuUtilization[state] = stateSums[state] / stateCounts[state];
413
- }
414
- cpuCount = Math.max(...metric.dataPoints.map((dp) => parseInt(dp.attributes?.system?.cpu?.logical_number || 0, 10))) + 1;
415
- }
416
- if (name === 'system.memory.usage') {
417
- for (const dp of metric.dataPoints) {
418
- const state = dp.attributes?.system?.memory?.state;
419
- // @ts-expect-error index signature
420
- if (state)
421
- memoryUsageMB[state] = dp.value;
422
- }
423
- }
424
- if (name === 'system.memory.utilization') {
425
- for (const dp of metric.dataPoints) {
426
- const state = dp.attributes?.system?.memory?.state;
427
- // @ts-expect-error index signature
428
- if (state)
429
- memoryUtilizationPercent[state] = dp.value;
430
- }
431
- }
432
- if (name === 'system.network.io') {
433
- for (const dp of metric.dataPoints) {
434
- const direction = dp.attributes?.network?.io?.direction;
435
- // @ts-expect-error index signature
436
- if (direction)
437
- networkIO[direction] += dp.value;
438
- }
439
- }
440
- if (name === 'process.cpu.time') {
441
- for (const dp of metric.dataPoints) {
442
- const state = dp.attributes?.process?.cpu?.state;
443
- // @ts-expect-error index signature
444
- if (state)
445
- processCPU[state] = dp.value;
446
- }
447
- }
448
- if (name === 'process.memory.usage') {
449
- processMemoryUsage = metric.dataPoints[0]?.value || 0;
450
- }
451
- }
452
- }
453
- return {
454
- service: serviceName,
455
- cpu: {
456
- avgUtilization: cpuUtilization,
457
- cores: cpuCount,
458
- },
459
- memory: {
460
- usedGB: (memoryUsageMB.used || 0) / (1024 ** 3),
461
- freeGB: (memoryUsageMB.free || 0) / (1024 ** 3),
462
- usedPercent: (memoryUtilizationPercent.used || 0) * 100,
463
- freePercent: (1 - (memoryUtilizationPercent.used || 0)) * 100,
464
- },
465
- network: {
466
- transmittedMB: networkIO.transmit / (1024 ** 2),
467
- receivedMB: networkIO.receive / (1024 ** 2),
468
- },
469
- process: {
470
- cpuTimeSec: processCPU,
471
- memoryUsageMB: processMemoryUsage / (1024 ** 2),
472
- }
473
- };
474
- });
475
- }
476
250
  function getSimplifiedTraces(spans) {
477
251
  return spans.map((span) => {
478
252
  return {
@@ -490,10 +264,10 @@ function getSimplifiedTraces(spans) {
490
264
  function getSimplifiedLogs(logs) {
491
265
  return logs.map((log) => ({
492
266
  service: log.resource?.attributes?.service?.name || undefined,
493
- timestamp: log.timestamp,
267
+ timestamp: new Date(log.timestamp / 1000).toISOString(), // converting microseconds to milliseconds
268
+ severityText: log.severityText,
494
269
  message: log.body,
495
270
  traceId: log.traceId,
496
- spanId: log.spanId,
497
- source: log.attributes?.source?.source || undefined,
271
+ source: log.attributes?.source || undefined,
498
272
  }));
499
273
  }
@@ -16,19 +16,19 @@ export const getLogin = (oasTlmConfig) => (req, res) => {
16
16
  if (password === oasTlmConfig.auth.password) {
17
17
  const accessToken = generateAccessToken(oasTlmConfig.auth.jwtSecret, oasTlmConfig.auth.accessTokenMaxAge);
18
18
  const refreshToken = generateRefreshToken(oasTlmConfig.auth.jwtSecret, oasTlmConfig.auth.refreshTokenMaxAge);
19
- res.cookie("accessToken", accessToken, {
19
+ res.cookie("oas-tlm-access-token", accessToken, {
20
20
  maxAge: oasTlmConfig.auth.accessTokenMaxAge,
21
21
  httpOnly: true,
22
22
  secure: process.env.NODE_ENV === "production",
23
23
  sameSite: "lax",
24
24
  path: "/"
25
25
  });
26
- res.cookie("refreshToken", refreshToken, {
26
+ res.cookie("oas-tlm-refresh-token", refreshToken, {
27
27
  maxAge: oasTlmConfig.auth.refreshTokenMaxAge,
28
28
  httpOnly: true,
29
29
  secure: process.env.NODE_ENV === "production",
30
30
  sameSite: "lax",
31
- path: oasTlmConfig.general.baseUrl + "/auth/refresh" // <-- cambiado de "/auth/refresh" a oasTlmConfig.general.baseUrl + "/auth/refresh"
31
+ path: oasTlmConfig.general.baseUrl + "/auth/refresh"
32
32
  });
33
33
  res.status(200).json({ valid: true, message: "Login successful" });
34
34
  return;
@@ -45,8 +45,8 @@ export const getLogout = (oasTlmConfig) => (req, res) => {
45
45
  res.status(200).json({ valid: true, message: "Auth disabled" });
46
46
  return;
47
47
  }
48
- res.clearCookie('accessToken', { path: '/' });
49
- res.clearCookie('refreshToken', { path: oasTlmConfig.general.baseUrl + '/auth/refresh' }); // <-- cambiado de "/auth/refresh" a oasTlmConfig.general.baseUrl + "/auth/refresh"
48
+ res.clearCookie('oas-tlm-access-token', { path: '/' });
49
+ res.clearCookie('oas-tlm-refresh-token', { path: oasTlmConfig.general.baseUrl + '/auth/refresh' });
50
50
  res.status(200).json({ valid: true, message: "Logged out" });
51
51
  };
52
52
  export const getRefresh = (oasTlmConfig) => (req, res) => {
@@ -54,7 +54,7 @@ export const getRefresh = (oasTlmConfig) => (req, res) => {
54
54
  res.status(200).json({ valid: true, message: "Auth disabled" });
55
55
  return;
56
56
  }
57
- const refreshToken = req.cookies.refreshToken;
57
+ const refreshToken = req.cookies["oas-tlm-refresh-token"];
58
58
  if (!refreshToken) {
59
59
  res.status(401).json({ valid: false, message: "No refresh token" });
60
60
  return;
@@ -64,7 +64,7 @@ export const getRefresh = (oasTlmConfig) => (req, res) => {
64
64
  if (payload.type !== "refresh")
65
65
  throw new Error("Invalid token type");
66
66
  const accessToken = generateAccessToken(oasTlmConfig.auth.jwtSecret, oasTlmConfig.auth.accessTokenMaxAge);
67
- res.cookie("accessToken", accessToken, {
67
+ res.cookie("oas-tlm-access-token", accessToken, {
68
68
  maxAge: oasTlmConfig.auth.accessTokenMaxAge,
69
69
  httpOnly: true,
70
70
  secure: process.env.NODE_ENV === "production",
@@ -73,7 +73,7 @@ export const getRefresh = (oasTlmConfig) => (req, res) => {
73
73
  });
74
74
  res.status(200).json({ valid: true, message: "Refreshed" });
75
75
  }
76
- catch (err) {
76
+ catch {
77
77
  res.status(401).json({ valid: false, message: "Invalid refresh token" });
78
78
  }
79
79
  };
@@ -4,7 +4,7 @@ export function getAuthMiddleware(oasTlmConfig) {
4
4
  if (!oasTlmConfig.auth.enabled) {
5
5
  return next();
6
6
  }
7
- const token = req.cookies.accessToken;
7
+ const token = req.cookies["oas-tlm-access-token"];
8
8
  if (!token) {
9
9
  res.status(401).json({ valid: false, message: "No access token" });
10
10
  return;
@@ -1,21 +1,13 @@
1
1
  import { inMemoryDbLogExporter } from '../telemetry/telemetryRegistry.js';
2
2
  import logger from '../utils/logger.js';
3
3
  import { convertRegexRecursively } from '../utils/regexUtils.js';
4
- export const listLogs = async (req, res) => {
5
- try {
6
- const logs = inMemoryDbLogExporter.getFinishedLogs();
7
- res.send({ logsCount: logs.length, logs: logs });
8
- }
9
- catch (err) {
10
- logger.error(err);
11
- res.status(500).send({ error: 'Failed to list log data' });
12
- }
13
- };
14
4
  export const findLogs = async (req, res) => {
15
- const body = req.body;
16
- const messageSearch = body?.textSearch || null; // Search term for MiniSearch
17
- const findQuery = body?.query || {}; // Query for NeDB
18
- logger.debug(`findLogs called with query: ${JSON.stringify(findQuery)} and search ${messageSearch}`, { depth: 3 });
5
+ const body = req.body || {};
6
+ const messageSearch = body.textSearch || null;
7
+ const findQuery = body.query || {};
8
+ const limit = parseInt(body.limit) || 50;
9
+ const sortOrder = body.sort || null;
10
+ logger.debug(`findLogs called with query: ${JSON.stringify(findQuery)} and search: ${messageSearch}`, { depth: 3 });
19
11
  let processedQuery;
20
12
  try {
21
13
  processedQuery = convertRegexRecursively(findQuery);
@@ -26,15 +18,17 @@ export const findLogs = async (req, res) => {
26
18
  return; // Exit if invalid regex was encountered
27
19
  }
28
20
  try {
29
- const results = await new Promise((resolve, reject) => {
30
- inMemoryDbLogExporter.find(processedQuery, messageSearch, (err, docs) => {
31
- if (err)
32
- return reject(err);
33
- resolve(docs);
34
- });
21
+ // Use findConfig object
22
+ const findConfig = {
23
+ query: processedQuery,
24
+ messageSearch,
25
+ limit,
26
+ sortOrder
27
+ };
28
+ const docs = await inMemoryDbLogExporter.find(findConfig);
29
+ res.send({
30
+ items: docs,
35
31
  });
36
- const typedResults = results;
37
- res.send({ logsCount: typedResults.length, logs: typedResults });
38
32
  }
39
33
  catch (err) {
40
34
  logger.error(err);
@@ -49,7 +43,7 @@ export const insertLogsToDb = async (req, res) => {
49
43
  const jsonContent = req.body.logs;
50
44
  const resetData = req.query.reset === 'true';
51
45
  if (!Array.isArray(jsonContent)) {
52
- res.status(400).send({ error: 'Invalid data format. Expected an array of JSON objects.' });
46
+ res.status(400).send({ error: 'Invalid data format.' });
53
47
  return;
54
48
  }
55
49
  const cleanedLogs = jsonContent.map((log) => {
@@ -92,12 +86,16 @@ export const statusLogs = (req, res) => {
92
86
  const isRunning = inMemoryDbLogExporter.isEnabled() || false;
93
87
  res.send({ active: isRunning });
94
88
  };
95
- export const setRetentionTimeLogs = (req, res) => {
96
- const retentionTime = req.body.retentionTime;
97
- if (typeof retentionTime !== 'number' || retentionTime <= 0) {
89
+ export const setLogRetentionTime = (req, res) => {
90
+ const retentionTimeInSeconds = req.body.retentionTimeInSeconds;
91
+ if (typeof retentionTimeInSeconds !== 'number' || retentionTimeInSeconds <= 0) {
98
92
  res.status(400).send({ error: 'Invalid retention time. Must be a positive number.' });
99
93
  return;
100
94
  }
101
- inMemoryDbLogExporter.retentionTimeInSeconds = retentionTime;
102
- res.send({ message: `Retention time set to ${retentionTime} seconds.` });
95
+ inMemoryDbLogExporter.retentionTimeInSeconds = retentionTimeInSeconds;
96
+ res.send({ message: `Retention time set to ${retentionTimeInSeconds} seconds.` });
97
+ };
98
+ export const getLogRetentionTime = (req, res) => {
99
+ const retentionTimeInSeconds = inMemoryDbLogExporter.retentionTimeInSeconds || 0;
100
+ res.send({ retentionTimeInSeconds: retentionTimeInSeconds });
103
101
  };
@@ -1,5 +1,5 @@
1
1
  import { Router } from 'express';
2
- import { startLogs, stopLogs, statusLogs, resetLogs, listLogs, findLogs, insertLogsToDb, setRetentionTimeLogs } from './logController.js';
2
+ import { startLogs, stopLogs, statusLogs, resetLogs, findLogs, insertLogsToDb, setLogRetentionTime, getLogRetentionTime } from './logController.js';
3
3
  export const getLogRoutes = () => {
4
4
  const router = Router();
5
5
  // Logs Control
@@ -7,8 +7,9 @@ export const getLogRoutes = () => {
7
7
  router.post('/stop', stopLogs);
8
8
  router.get('/status', statusLogs);
9
9
  router.post('/reset', resetLogs);
10
- router.post('/retention-time', setRetentionTimeLogs);
11
- router.get('/', listLogs);
10
+ router.post('/retention-time', setLogRetentionTime);
11
+ router.get('/retention-time', getLogRetentionTime);
12
+ router.get('/', findLogs);
12
13
  router.post('/', insertLogsToDb);
13
14
  router.post('/find', findLogs);
14
15
  return router;
@@ -40,7 +40,7 @@ export const insertMetricsToDb = async (req, res) => {
40
40
  const jsonContent = req.body.metrics;
41
41
  const resetData = req.query.reset === 'true';
42
42
  if (!Array.isArray(jsonContent)) {
43
- res.status(400).send({ error: 'Invalid data format. Expected an array of JSON objects.' });
43
+ res.status(400).send({ error: 'Invalid data format.' });
44
44
  return;
45
45
  }
46
46
  const cleanedMetrics = jsonContent.map((metric) => {
@@ -83,12 +83,16 @@ export const statusMetrics = (req, res) => {
83
83
  const isRunning = inMemoryDbMetricExporter.isEnabled() || false;
84
84
  res.send({ active: isRunning });
85
85
  };
86
- export const setRetentionTimeMetrics = (req, res) => {
87
- const retentionTime = req.body.retentionTime;
88
- if (typeof retentionTime !== 'number' || retentionTime <= 0) {
86
+ export const setMetricRetentionTime = (req, res) => {
87
+ const retentionTimeInSeconds = req.body.retentionTimeInSeconds;
88
+ if (typeof retentionTimeInSeconds !== 'number' || retentionTimeInSeconds <= 0) {
89
89
  res.status(400).send({ error: 'Invalid retention time. Must be a positive number.' });
90
90
  return;
91
91
  }
92
- inMemoryDbMetricExporter.retentionTimeInSeconds = retentionTime;
93
- res.send({ message: `Retention time set to ${retentionTime} seconds.` });
92
+ inMemoryDbMetricExporter.retentionTimeInSeconds = retentionTimeInSeconds;
93
+ res.send({ message: `Retention time set to ${retentionTimeInSeconds} seconds.` });
94
+ };
95
+ export const getMetricRetentionTime = (req, res) => {
96
+ const retentionTimeInSeconds = inMemoryDbMetricExporter.retentionTimeInSeconds || 0;
97
+ res.send({ retentionTimeInSeconds: retentionTimeInSeconds });
94
98
  };
@@ -1,5 +1,5 @@
1
1
  import { Router } from 'express';
2
- import { listMetrics, findMetrics, resetMetrics, insertMetricsToDb, startMetrics, stopMetrics, statusMetrics, setRetentionTimeMetrics } from './metricsController.js';
2
+ import { listMetrics, findMetrics, resetMetrics, insertMetricsToDb, startMetrics, stopMetrics, statusMetrics, setMetricRetentionTime, getMetricRetentionTime } from './metricsController.js';
3
3
  export const getMetricsRoutes = () => {
4
4
  const router = Router();
5
5
  // Metrics Control
@@ -7,7 +7,8 @@ export const getMetricsRoutes = () => {
7
7
  router.post('/stop', stopMetrics);
8
8
  router.get('/status', statusMetrics);
9
9
  router.post('/reset', resetMetrics);
10
- router.post('/retention-time', setRetentionTimeMetrics);
10
+ router.post('/retention-time', setMetricRetentionTime);
11
+ router.get('/retention-time', getMetricRetentionTime);
11
12
  router.get('/', listMetrics);
12
13
  router.post('/', insertMetricsToDb);
13
14
  router.post('/find', findMetrics);