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