@oas-tools/oas-telemetry 0.7.0-alpha.2 → 0.7.0-alpha.4
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/.env.example +50 -17
- package/README.md +244 -239
- package/dist/cjs/config/bootConfig.cjs +18 -0
- package/dist/cjs/config/config.cjs +145 -0
- package/dist/cjs/config/config.types.cjs +5 -0
- package/dist/cjs/index.cjs +19 -25
- package/dist/cjs/{tlmRoutes.cjs → routesManager.cjs} +28 -21
- package/dist/cjs/{exporters/InMemoryLogRecordExporter.cjs → telemetry/custom-implementations/exporters/InMemoryDbLogExporter.cjs} +42 -19
- package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.cjs +97 -0
- package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.cjs +118 -0
- package/dist/cjs/telemetry/custom-implementations/exporters/PluginLogExporter.cjs +45 -0
- package/dist/cjs/telemetry/custom-implementations/exporters/PluginMetricExporter.cjs +46 -0
- package/dist/cjs/telemetry/custom-implementations/exporters/PluginSpanExporter.cjs +61 -0
- package/dist/cjs/telemetry/custom-implementations/processors/dynamicMultiLogProcessor.cjs +70 -0
- package/dist/cjs/telemetry/custom-implementations/processors/dynamicMultiSpanProcessor.cjs +70 -0
- package/dist/cjs/{utils → telemetry/custom-implementations/utils}/circular.cjs +39 -49
- package/dist/cjs/telemetry/custom-implementations/wrappers.cjs +175 -0
- package/dist/cjs/telemetry/initializeTelemetry.cjs +74 -0
- package/dist/cjs/telemetry/telemetryConfigurator.cjs +84 -0
- package/dist/cjs/telemetry/telemetryRegistry.cjs +40 -0
- package/dist/cjs/tlm-ai/agent.cjs +82 -63
- package/dist/cjs/tlm-ai/aiController.cjs +5 -4
- package/dist/cjs/tlm-ai/aiRoutes.cjs +9 -6
- package/dist/cjs/tlm-ai/tools.cjs +16 -9
- package/dist/cjs/tlm-auth/authController.cjs +14 -15
- package/dist/cjs/tlm-auth/authMiddleware.cjs +11 -10
- package/dist/cjs/tlm-auth/authRoutes.cjs +9 -7
- package/dist/cjs/tlm-log/logController.cjs +45 -18
- package/dist/cjs/tlm-log/logRoutes.cjs +16 -11
- package/dist/cjs/tlm-metric/metricsController.cjs +37 -12
- package/dist/cjs/tlm-metric/metricsRoutes.cjs +16 -11
- package/dist/cjs/tlm-plugin/pluginController.cjs +114 -75
- package/dist/cjs/tlm-plugin/pluginProcess.cjs +108 -0
- package/dist/cjs/tlm-plugin/pluginRoutes.cjs +11 -6
- package/dist/cjs/tlm-plugin/pluginService.cjs +79 -0
- package/dist/cjs/tlm-trace/traceController.cjs +54 -45
- package/dist/cjs/tlm-trace/traceRoutes.cjs +16 -11
- package/dist/cjs/tlm-ui/uiRoutes.cjs +26 -20
- package/dist/cjs/tlm-util/utilController.cjs +8 -9
- package/dist/cjs/tlm-util/utilRoutes.cjs +22 -19
- package/dist/cjs/types/index.cjs +0 -1
- package/dist/cjs/utils/logger.cjs +3 -5
- package/dist/cjs/utils/regexUtils.cjs +27 -0
- package/dist/esm/config/bootConfig.js +11 -0
- package/dist/esm/config/config.js +126 -0
- package/dist/esm/index.js +18 -29
- package/dist/esm/{tlmRoutes.js → routesManager.js} +27 -22
- package/dist/esm/{exporters/InMemoryLogRecordExporter.js → telemetry/custom-implementations/exporters/InMemoryDbLogExporter.js} +31 -17
- package/dist/esm/{exporters/InMemoryDBMetricsExporter.js → telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.js} +31 -17
- package/dist/esm/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.js +105 -0
- package/dist/esm/telemetry/custom-implementations/exporters/PluginLogExporter.js +36 -0
- package/dist/esm/telemetry/custom-implementations/exporters/PluginMetricExporter.js +35 -0
- package/dist/esm/telemetry/custom-implementations/exporters/PluginSpanExporter.js +52 -0
- package/dist/esm/telemetry/custom-implementations/processors/dynamicMultiLogProcessor.js +64 -0
- package/dist/esm/telemetry/custom-implementations/processors/dynamicMultiSpanProcessor.js +64 -0
- package/dist/esm/telemetry/custom-implementations/utils/circular.js +76 -0
- package/dist/esm/telemetry/custom-implementations/wrappers.js +163 -0
- package/dist/esm/telemetry/initializeTelemetry.js +71 -0
- package/dist/esm/telemetry/telemetryConfigurator.js +74 -0
- package/dist/esm/telemetry/telemetryRegistry.js +34 -0
- package/dist/esm/tlm-ai/agent.js +77 -59
- package/dist/esm/tlm-ai/aiController.js +5 -4
- package/dist/esm/tlm-ai/aiRoutes.js +7 -5
- package/dist/esm/tlm-ai/tools.js +18 -9
- package/dist/esm/tlm-auth/authController.js +9 -10
- package/dist/esm/tlm-auth/authMiddleware.js +10 -9
- package/dist/esm/tlm-auth/authRoutes.js +8 -6
- package/dist/esm/tlm-log/logController.js +36 -16
- package/dist/esm/tlm-log/logRoutes.js +15 -11
- package/dist/esm/tlm-metric/metricsController.js +29 -10
- package/dist/esm/tlm-metric/metricsRoutes.js +15 -11
- package/dist/esm/tlm-plugin/pluginController.js +112 -77
- package/dist/esm/tlm-plugin/pluginProcess.js +101 -0
- package/dist/esm/tlm-plugin/pluginRoutes.js +10 -6
- package/dist/esm/tlm-plugin/pluginService.js +73 -0
- package/dist/esm/tlm-trace/traceController.js +40 -35
- package/dist/esm/tlm-trace/traceRoutes.js +15 -11
- package/dist/esm/tlm-ui/uiRoutes.js +24 -19
- package/dist/esm/tlm-util/utilController.js +8 -9
- package/dist/esm/tlm-util/utilRoutes.js +17 -15
- package/dist/esm/types/index.js +0 -1
- package/dist/esm/utils/logger.js +3 -4
- package/dist/esm/utils/regexUtils.js +23 -0
- package/dist/types/config/bootConfig.d.ts +5 -0
- package/dist/types/config/config.d.ts +858 -0
- package/dist/types/config/config.types.d.ts +34 -0
- package/dist/types/index.d.ts +5 -4
- package/dist/types/routesManager.d.ts +3 -0
- package/dist/types/{exporters/InMemoryLogRecordExporter.d.ts → telemetry/custom-implementations/exporters/InMemoryDbLogExporter.d.ts} +6 -6
- package/dist/types/{exporters/InMemoryDBMetricsExporter.d.ts → telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.d.ts} +7 -7
- package/dist/types/{exporters/InMemoryDbExporter.d.ts → telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.d.ts} +9 -9
- package/dist/types/telemetry/custom-implementations/exporters/PluginLogExporter.d.ts +8 -0
- package/dist/types/telemetry/custom-implementations/exporters/PluginMetricExporter.d.ts +12 -0
- package/dist/types/telemetry/custom-implementations/exporters/PluginSpanExporter.d.ts +14 -0
- package/dist/types/telemetry/custom-implementations/processors/dynamicMultiLogProcessor.d.ts +32 -0
- package/dist/types/telemetry/custom-implementations/processors/dynamicMultiSpanProcessor.d.ts +34 -0
- package/dist/types/telemetry/custom-implementations/utils/circular.d.ts +27 -0
- package/dist/types/telemetry/custom-implementations/wrappers.d.ts +52 -0
- package/dist/types/telemetry/initializeTelemetry.d.ts +1 -0
- package/dist/types/telemetry/telemetryConfigurator.d.ts +2 -0
- package/dist/types/telemetry/telemetryRegistry.d.ts +20 -0
- package/dist/types/tlm-ai/agent.d.ts +2 -1
- package/dist/types/tlm-ai/aiController.d.ts +4 -3
- package/dist/types/tlm-ai/aiRoutes.d.ts +2 -2
- package/dist/types/tlm-ai/tools.d.ts +3 -1
- package/dist/types/tlm-auth/authController.d.ts +4 -3
- package/dist/types/tlm-auth/authMiddleware.d.ts +2 -1
- package/dist/types/tlm-auth/authRoutes.d.ts +2 -2
- package/dist/types/tlm-log/logController.d.ts +1 -0
- package/dist/types/tlm-log/logRoutes.d.ts +2 -2
- package/dist/types/tlm-metric/metricsController.d.ts +1 -0
- package/dist/types/tlm-metric/metricsRoutes.d.ts +2 -2
- package/dist/types/tlm-plugin/pluginController.d.ts +4 -1
- package/dist/types/tlm-plugin/pluginProcess.d.ts +1 -0
- package/dist/types/tlm-plugin/pluginRoutes.d.ts +1 -2
- package/dist/types/tlm-plugin/pluginService.d.ts +24 -0
- package/dist/types/tlm-trace/traceController.d.ts +7 -6
- package/dist/types/tlm-trace/traceRoutes.d.ts +2 -2
- package/dist/types/tlm-ui/uiRoutes.d.ts +1 -2
- package/dist/types/tlm-util/utilController.d.ts +2 -1
- package/dist/types/tlm-util/utilRoutes.d.ts +2 -2
- package/dist/types/types/index.d.ts +17 -47
- package/dist/types/utils/regexUtils.d.ts +1 -0
- package/dist/ui/assets/index-BzIdRox6.js +1733 -0
- package/dist/ui/assets/index-CkoHzrrt.css +1 -0
- package/dist/ui/index.html +3 -3
- package/dist/ui/oas-tlm.svg +185 -0
- package/package.json +12 -7
- package/dist/cjs/config.cjs +0 -31
- package/dist/cjs/exporters/InMemoryDBMetricsExporter.cjs +0 -74
- package/dist/cjs/exporters/InMemoryDbExporter.cjs +0 -102
- package/dist/cjs/exporters/consoleExporter.cjs +0 -47
- package/dist/cjs/exporters/dynamicExporter.cjs +0 -57
- package/dist/cjs/instrumentation/index.cjs +0 -28
- package/dist/cjs/instrumentation/logs.cjs +0 -46
- package/dist/cjs/instrumentation/metrics.cjs +0 -27
- package/dist/cjs/instrumentation/traces.cjs +0 -19
- package/dist/esm/config.js +0 -20
- package/dist/esm/exporters/InMemoryDbExporter.js +0 -102
- package/dist/esm/exporters/consoleExporter.js +0 -38
- package/dist/esm/exporters/dynamicExporter.js +0 -50
- package/dist/esm/instrumentation/index.js +0 -26
- package/dist/esm/instrumentation/logs.js +0 -34
- package/dist/esm/instrumentation/metrics.js +0 -18
- package/dist/esm/instrumentation/traces.js +0 -12
- package/dist/esm/utils/circular.js +0 -84
- package/dist/types/config.d.ts +0 -6
- package/dist/types/exporters/consoleExporter.d.ts +0 -13
- package/dist/types/exporters/dynamicExporter.d.ts +0 -25
- package/dist/types/instrumentation/logs.d.ts +0 -1
- package/dist/types/instrumentation/metrics.d.ts +0 -1
- package/dist/types/instrumentation/traces.d.ts +0 -1
- package/dist/types/tlmRoutes.d.ts +0 -2
- package/dist/types/utils/circular.d.ts +0 -31
- package/dist/ui/assets/index-BNhZBPi2.css +0 -1
- package/dist/ui/assets/index-DxGAMrAl.js +0 -401
- package/dist/ui/vite.svg +0 -1
- /package/dist/{types/instrumentation/index.d.ts → esm/config/config.types.js} +0 -0
package/dist/esm/tlm-ai/tools.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
|
-
import { globalOasTlmConfig } from '../config.js';
|
|
3
2
|
import logger from '../utils/logger.js';
|
|
4
3
|
import { getKnownMicroservices } from './knownMicroservices.js';
|
|
4
|
+
import { inMemoryDbLogExporter, inMemoryDbMetricExporter, inMemoryDbSpanExporter } from '../telemetry/telemetryRegistry.js';
|
|
5
5
|
const getTraces = async (searchInput) => {
|
|
6
6
|
logger.debug("getTraces called with searchInput:", searchInput);
|
|
7
7
|
try {
|
|
8
8
|
const search = searchInput || {};
|
|
9
9
|
const traces = await new Promise((resolve, reject) => {
|
|
10
|
-
|
|
10
|
+
inMemoryDbSpanExporter.find(search, (err, docs) => {
|
|
11
11
|
if (err)
|
|
12
12
|
reject(err);
|
|
13
13
|
else
|
|
@@ -42,7 +42,7 @@ const getLogs = async (startDate, endDate) => {
|
|
|
42
42
|
}
|
|
43
43
|
const logs = [];
|
|
44
44
|
await new Promise((resolve, reject) => {
|
|
45
|
-
|
|
45
|
+
inMemoryDbLogExporter.find(nedbQuery, null, (err, docs) => {
|
|
46
46
|
if (err) {
|
|
47
47
|
reject(err);
|
|
48
48
|
}
|
|
@@ -66,7 +66,7 @@ const getMetrics = async (searchInput) => {
|
|
|
66
66
|
try {
|
|
67
67
|
const search = searchInput || {};
|
|
68
68
|
const metrics = await new Promise((resolve, reject) => {
|
|
69
|
-
|
|
69
|
+
inMemoryDbMetricExporter.find(search, (err, docs) => {
|
|
70
70
|
if (err)
|
|
71
71
|
reject(err);
|
|
72
72
|
else
|
|
@@ -90,20 +90,29 @@ const getCurrentTimestampInEpoch = () => {
|
|
|
90
90
|
};
|
|
91
91
|
const startTelemetry = () => {
|
|
92
92
|
logger.debug("Starting telemetry...");
|
|
93
|
-
|
|
93
|
+
inMemoryDbSpanExporter.enable();
|
|
94
|
+
inMemoryDbLogExporter.enable();
|
|
95
|
+
inMemoryDbMetricExporter.enable();
|
|
94
96
|
};
|
|
95
97
|
const stopTelemetry = () => {
|
|
96
98
|
logger.debug("Stopping telemetry...");
|
|
97
|
-
|
|
99
|
+
inMemoryDbSpanExporter.disable();
|
|
100
|
+
inMemoryDbLogExporter.disable();
|
|
101
|
+
inMemoryDbMetricExporter.disable();
|
|
98
102
|
};
|
|
99
103
|
const resetTelemetry = () => {
|
|
100
104
|
logger.debug("Resetting telemetry...");
|
|
101
|
-
|
|
105
|
+
inMemoryDbSpanExporter.reset();
|
|
106
|
+
inMemoryDbLogExporter.reset();
|
|
107
|
+
inMemoryDbMetricExporter.reset();
|
|
102
108
|
};
|
|
103
109
|
const getTelemetryStatus = () => {
|
|
104
110
|
logger.debug("Getting telemetry status...");
|
|
105
|
-
|
|
106
|
-
|
|
111
|
+
return {
|
|
112
|
+
spansEnabled: inMemoryDbSpanExporter.isEnabled(),
|
|
113
|
+
logsEnabled: inMemoryDbLogExporter.isEnabled(),
|
|
114
|
+
metricsEnabled: inMemoryDbMetricExporter.isEnabled()
|
|
115
|
+
};
|
|
107
116
|
};
|
|
108
117
|
const talkToExternalMicroserviceAgent = async (message, microserviceId) => {
|
|
109
118
|
logger.debug("talkToExternalMicroserviceAgent called with question:", message, "microservice:", microserviceId);
|
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
import { globalOasTlmConfig } from '../config.js';
|
|
2
1
|
import jwt from 'jsonwebtoken';
|
|
3
2
|
import logger from '../utils/logger.js';
|
|
4
|
-
export const
|
|
3
|
+
export const getLogin = (oasTlmConfig) => (req, res) => {
|
|
5
4
|
try {
|
|
6
5
|
const { password } = req.body;
|
|
7
|
-
if (password ===
|
|
6
|
+
if (password === oasTlmConfig.auth.password) {
|
|
8
7
|
const options = {
|
|
9
|
-
maxAge:
|
|
8
|
+
maxAge: oasTlmConfig.auth.apiKeyMaxAge,
|
|
10
9
|
httpOnly: true,
|
|
11
10
|
secure: true,
|
|
12
11
|
signed: false
|
|
13
12
|
};
|
|
14
|
-
const apiKey = jwt.sign({ password:
|
|
13
|
+
const apiKey = jwt.sign({ password: oasTlmConfig.auth.password }, oasTlmConfig.auth.jwtSecret);
|
|
15
14
|
res.cookie('apiKey', apiKey, options);
|
|
16
15
|
res.status(200).json({ valid: true, message: 'API Key is valid' });
|
|
17
16
|
return;
|
|
@@ -23,17 +22,17 @@ export const login = (req, res) => {
|
|
|
23
22
|
res.status(500).json({ valid: false, message: 'Internal server error' });
|
|
24
23
|
}
|
|
25
24
|
};
|
|
26
|
-
export const
|
|
25
|
+
export const getLogout = (oasTlmConfig) => (req, res) => {
|
|
27
26
|
res.clearCookie('apiKey');
|
|
28
|
-
res.redirect(
|
|
27
|
+
res.redirect(oasTlmConfig.general.baseUrl + oasTlmConfig.general.uiPath + '/login');
|
|
29
28
|
};
|
|
30
|
-
export const
|
|
29
|
+
export const getCheck = (oasTlmConfig) => (req, res) => {
|
|
31
30
|
if (!req.cookies.apiKey) {
|
|
32
31
|
res.status(200).json({ valid: false, message: 'API Key is invalid' });
|
|
33
32
|
return;
|
|
34
33
|
}
|
|
35
|
-
const decoded = jwt.verify(req.cookies.apiKey,
|
|
36
|
-
if (decoded.password ===
|
|
34
|
+
const decoded = jwt.verify(req.cookies.apiKey, oasTlmConfig.auth.jwtSecret);
|
|
35
|
+
if (decoded.password === oasTlmConfig.auth.password) {
|
|
37
36
|
res.status(200).json({ valid: true, message: 'API Key is valid' });
|
|
38
37
|
return;
|
|
39
38
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { globalOasTlmConfig } from "../config.js";
|
|
2
1
|
import jwt from 'jsonwebtoken';
|
|
3
|
-
export function
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
export function getAuthMiddleware(oasTlmConfig) {
|
|
3
|
+
return function authMiddleware(req, res, next) {
|
|
4
|
+
const apiKey = req.cookies.apiKey;
|
|
5
|
+
if (apiKey) {
|
|
6
|
+
const decoded = jwt.verify(apiKey, oasTlmConfig.auth.jwtSecret);
|
|
7
|
+
if (decoded.password === oasTlmConfig.auth.password) {
|
|
8
|
+
return next();
|
|
9
|
+
}
|
|
9
10
|
}
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
res.status(401).redirect(oasTlmConfig.general.baseUrl + oasTlmConfig.general.uiPath + '/login');
|
|
12
|
+
};
|
|
12
13
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { Router } from 'express';
|
|
2
|
-
import {
|
|
3
|
-
const
|
|
4
|
-
router
|
|
5
|
-
router.
|
|
6
|
-
router.get('/
|
|
7
|
-
|
|
2
|
+
import { getLogin, getLogout, getCheck } from './authController.js';
|
|
3
|
+
export const getAuthRoutes = (oasTlmConfig) => {
|
|
4
|
+
const router = Router();
|
|
5
|
+
router.post('/login', getLogin(oasTlmConfig));
|
|
6
|
+
router.get('/logout', getLogout(oasTlmConfig));
|
|
7
|
+
router.get('/check', getCheck(oasTlmConfig));
|
|
8
|
+
return router;
|
|
9
|
+
};
|
|
@@ -1,22 +1,33 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { inMemoryDbLogExporter } from '../telemetry/telemetryRegistry.js';
|
|
2
|
+
import logger from '../utils/logger.js';
|
|
3
|
+
import { convertRegexRecursively } from '../utils/regexUtils.js';
|
|
2
4
|
export const listLogs = async (req, res) => {
|
|
3
5
|
try {
|
|
4
|
-
const logs =
|
|
6
|
+
const logs = inMemoryDbLogExporter.getFinishedLogs();
|
|
5
7
|
res.send({ logsCount: logs.length, logs: logs });
|
|
6
8
|
}
|
|
7
9
|
catch (err) {
|
|
8
|
-
|
|
10
|
+
logger.error(err);
|
|
9
11
|
res.status(500).send({ error: 'Failed to list log data' });
|
|
10
12
|
}
|
|
11
13
|
};
|
|
12
14
|
export const findLogs = async (req, res) => {
|
|
13
15
|
const body = req.body;
|
|
14
|
-
const messageSearch = body?.
|
|
15
|
-
const findQuery = body?.
|
|
16
|
-
|
|
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 });
|
|
19
|
+
let processedQuery;
|
|
20
|
+
try {
|
|
21
|
+
processedQuery = convertRegexRecursively(findQuery);
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
logger.error(error.message);
|
|
25
|
+
res.status(400).send({ error: error.message });
|
|
26
|
+
return; // Exit if invalid regex was encountered
|
|
27
|
+
}
|
|
17
28
|
try {
|
|
18
29
|
const results = await new Promise((resolve, reject) => {
|
|
19
|
-
|
|
30
|
+
inMemoryDbLogExporter.find(processedQuery, messageSearch, (err, docs) => {
|
|
20
31
|
if (err)
|
|
21
32
|
return reject(err);
|
|
22
33
|
resolve(docs);
|
|
@@ -26,12 +37,12 @@ export const findLogs = async (req, res) => {
|
|
|
26
37
|
res.send({ logsCount: typedResults.length, logs: typedResults });
|
|
27
38
|
}
|
|
28
39
|
catch (err) {
|
|
29
|
-
|
|
40
|
+
logger.error(err);
|
|
30
41
|
res.status(500).send({ error: 'Failed to find logs', details: err.message });
|
|
31
42
|
}
|
|
32
43
|
};
|
|
33
44
|
export const resetLogs = (req, res) => {
|
|
34
|
-
|
|
45
|
+
inMemoryDbLogExporter.reset();
|
|
35
46
|
res.send('Logs reset');
|
|
36
47
|
};
|
|
37
48
|
export const insertLogsToDb = async (req, res) => {
|
|
@@ -49,13 +60,13 @@ export const insertLogsToDb = async (req, res) => {
|
|
|
49
60
|
try {
|
|
50
61
|
let message = '';
|
|
51
62
|
if (resetData) {
|
|
52
|
-
|
|
63
|
+
inMemoryDbLogExporter.reset();
|
|
53
64
|
message += 'Logs Database reset. ';
|
|
54
65
|
}
|
|
55
66
|
await new Promise((resolve, reject) => {
|
|
56
|
-
|
|
67
|
+
inMemoryDbLogExporter.insert(cleanedLogs, (err, newDocs) => {
|
|
57
68
|
if (err) {
|
|
58
|
-
|
|
69
|
+
logger.error('Error inserting logs:', err);
|
|
59
70
|
return reject(err);
|
|
60
71
|
}
|
|
61
72
|
resolve(newDocs);
|
|
@@ -65,19 +76,28 @@ export const insertLogsToDb = async (req, res) => {
|
|
|
65
76
|
res.send({ message, InsertedLogsCount: cleanedLogs.length });
|
|
66
77
|
}
|
|
67
78
|
catch (err) {
|
|
68
|
-
|
|
79
|
+
logger.error(err);
|
|
69
80
|
res.status(500).send({ error: 'Failed to reset and insert data', details: err.message });
|
|
70
81
|
}
|
|
71
82
|
};
|
|
72
83
|
export const startLogs = (req, res) => {
|
|
73
|
-
|
|
84
|
+
inMemoryDbLogExporter.enable();
|
|
74
85
|
res.send('Log collection started');
|
|
75
86
|
};
|
|
76
87
|
export const stopLogs = (req, res) => {
|
|
77
|
-
|
|
88
|
+
inMemoryDbLogExporter.disable();
|
|
78
89
|
res.send('Log collection stopped');
|
|
79
90
|
};
|
|
80
91
|
export const statusLogs = (req, res) => {
|
|
81
|
-
const isRunning =
|
|
92
|
+
const isRunning = inMemoryDbLogExporter.isEnabled() || false;
|
|
82
93
|
res.send({ active: isRunning });
|
|
83
94
|
};
|
|
95
|
+
export const setRetentionTimeLogs = (req, res) => {
|
|
96
|
+
const retentionTime = req.body.retentionTime;
|
|
97
|
+
if (typeof retentionTime !== 'number' || retentionTime <= 0) {
|
|
98
|
+
res.status(400).send({ error: 'Invalid retention time. Must be a positive number.' });
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
inMemoryDbLogExporter.retentionTimeInSeconds = retentionTime;
|
|
102
|
+
res.send({ message: `Retention time set to ${retentionTime} seconds.` });
|
|
103
|
+
};
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { Router } from 'express';
|
|
2
|
-
import { startLogs, stopLogs, statusLogs, resetLogs, listLogs, findLogs, insertLogsToDb } from './logController.js';
|
|
3
|
-
export const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
2
|
+
import { startLogs, stopLogs, statusLogs, resetLogs, listLogs, findLogs, insertLogsToDb, setRetentionTimeLogs } from './logController.js';
|
|
3
|
+
export const getLogRoutes = () => {
|
|
4
|
+
const router = Router();
|
|
5
|
+
// Logs Control
|
|
6
|
+
router.post('/start', startLogs);
|
|
7
|
+
router.post('/stop', stopLogs);
|
|
8
|
+
router.get('/status', statusLogs);
|
|
9
|
+
router.post('/reset', resetLogs);
|
|
10
|
+
router.post('/retention-time', setRetentionTimeLogs);
|
|
11
|
+
router.get('/', listLogs);
|
|
12
|
+
router.post('/', insertLogsToDb);
|
|
13
|
+
router.post('/find', findLogs);
|
|
14
|
+
return router;
|
|
15
|
+
};
|
|
16
|
+
export default getLogRoutes;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { inMemoryDbMetricExporter } from '../telemetry/telemetryRegistry.js';
|
|
2
|
+
import { convertRegexRecursively } from '../utils/regexUtils.js';
|
|
2
3
|
export const listMetrics = async (req, res) => {
|
|
3
4
|
try {
|
|
4
|
-
const metrics =
|
|
5
|
+
const metrics = inMemoryDbMetricExporter.getFinishedMetrics();
|
|
5
6
|
res.send({ metricsCount: metrics.length, metrics: metrics });
|
|
6
7
|
}
|
|
7
8
|
catch (err) {
|
|
@@ -11,8 +12,17 @@ export const listMetrics = async (req, res) => {
|
|
|
11
12
|
};
|
|
12
13
|
export const findMetrics = (req, res) => {
|
|
13
14
|
const body = req.body;
|
|
14
|
-
const
|
|
15
|
-
|
|
15
|
+
const query = body?.query ? body.query : {};
|
|
16
|
+
let processedQuery;
|
|
17
|
+
try {
|
|
18
|
+
processedQuery = convertRegexRecursively(query);
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
console.error(error.message);
|
|
22
|
+
res.status(400).send({ error: error.message });
|
|
23
|
+
return; // Exit if invalid regex was encountered
|
|
24
|
+
}
|
|
25
|
+
inMemoryDbMetricExporter.find(processedQuery, (err, docs) => {
|
|
16
26
|
if (err) {
|
|
17
27
|
console.error(err);
|
|
18
28
|
res.status(404).send({ metricsCount: 0, metrics: [], error: err });
|
|
@@ -23,7 +33,7 @@ export const findMetrics = (req, res) => {
|
|
|
23
33
|
});
|
|
24
34
|
};
|
|
25
35
|
export const resetMetrics = (req, res) => {
|
|
26
|
-
|
|
36
|
+
inMemoryDbMetricExporter.reset();
|
|
27
37
|
res.send('Metrics reset');
|
|
28
38
|
};
|
|
29
39
|
export const insertMetricsToDb = async (req, res) => {
|
|
@@ -41,11 +51,11 @@ export const insertMetricsToDb = async (req, res) => {
|
|
|
41
51
|
try {
|
|
42
52
|
let message = '';
|
|
43
53
|
if (resetData) {
|
|
44
|
-
|
|
54
|
+
inMemoryDbMetricExporter.reset();
|
|
45
55
|
message += 'Metrics Database reset. ';
|
|
46
56
|
}
|
|
47
57
|
await new Promise((resolve, reject) => {
|
|
48
|
-
|
|
58
|
+
inMemoryDbMetricExporter.insert(cleanedMetrics, (err, newDocs) => {
|
|
49
59
|
if (err) {
|
|
50
60
|
console.error('Error inserting metrics:', err);
|
|
51
61
|
return reject(err);
|
|
@@ -62,14 +72,23 @@ export const insertMetricsToDb = async (req, res) => {
|
|
|
62
72
|
}
|
|
63
73
|
};
|
|
64
74
|
export const startMetrics = (req, res) => {
|
|
65
|
-
|
|
75
|
+
inMemoryDbMetricExporter.enable();
|
|
66
76
|
res.send('Metrics collection started');
|
|
67
77
|
};
|
|
68
78
|
export const stopMetrics = (req, res) => {
|
|
69
|
-
|
|
79
|
+
inMemoryDbMetricExporter.disable();
|
|
70
80
|
res.send('Metrics collection stopped');
|
|
71
81
|
};
|
|
72
82
|
export const statusMetrics = (req, res) => {
|
|
73
|
-
const isRunning =
|
|
83
|
+
const isRunning = inMemoryDbMetricExporter.isEnabled() || false;
|
|
74
84
|
res.send({ active: isRunning });
|
|
75
85
|
};
|
|
86
|
+
export const setRetentionTimeMetrics = (req, res) => {
|
|
87
|
+
const retentionTime = req.body.retentionTime;
|
|
88
|
+
if (typeof retentionTime !== 'number' || retentionTime <= 0) {
|
|
89
|
+
res.status(400).send({ error: 'Invalid retention time. Must be a positive number.' });
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
inMemoryDbMetricExporter.retentionTimeInSeconds = retentionTime;
|
|
93
|
+
res.send({ message: `Retention time set to ${retentionTime} seconds.` });
|
|
94
|
+
};
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { Router } from 'express';
|
|
2
|
-
import { listMetrics, findMetrics, resetMetrics, insertMetricsToDb, startMetrics, stopMetrics, statusMetrics } from './metricsController.js';
|
|
3
|
-
export const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
2
|
+
import { listMetrics, findMetrics, resetMetrics, insertMetricsToDb, startMetrics, stopMetrics, statusMetrics, setRetentionTimeMetrics } from './metricsController.js';
|
|
3
|
+
export const getMetricsRoutes = () => {
|
|
4
|
+
const router = Router();
|
|
5
|
+
// Metrics Control
|
|
6
|
+
router.post('/start', startMetrics);
|
|
7
|
+
router.post('/stop', stopMetrics);
|
|
8
|
+
router.get('/status', statusMetrics);
|
|
9
|
+
router.post('/reset', resetMetrics);
|
|
10
|
+
router.post('/retention-time', setRetentionTimeMetrics);
|
|
11
|
+
router.get('/', listMetrics);
|
|
12
|
+
router.post('/', insertMetricsToDb);
|
|
13
|
+
router.post('/find', findMetrics);
|
|
14
|
+
return router;
|
|
15
|
+
};
|
|
16
|
+
export default getMetricsRoutes;
|
|
@@ -1,103 +1,138 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
import logger from '../utils/logger.js';
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { fork } from "child_process";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import logger from "../utils/logger.js";
|
|
5
|
+
import { pluginService } from "./pluginService.js";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
8
7
|
export const listPlugins = (req, res) => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
active: plugin.active
|
|
15
|
-
};
|
|
16
|
-
}));
|
|
8
|
+
const plugins = pluginService.getPlugins();
|
|
9
|
+
res.send({
|
|
10
|
+
pluginsCount: plugins.length,
|
|
11
|
+
plugins,
|
|
12
|
+
});
|
|
17
13
|
};
|
|
18
14
|
export const registerPlugin = async (req, res) => {
|
|
19
15
|
const pluginResource = req.body;
|
|
20
|
-
logger.
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
logger.debug(`Plugin Registration Request: ${JSON.stringify(req.body, null, 2)}...`);
|
|
17
|
+
// Validate id
|
|
18
|
+
if (!pluginResource.id || typeof pluginResource.id !== "string") {
|
|
19
|
+
res.status(400).send("Plugin id must be provided and must be a string");
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
// Check duplicate
|
|
23
|
+
if (pluginService.getPlugins().find((p) => p.id === pluginResource.id)) {
|
|
24
|
+
res.status(400).send(`Plugin with id "${pluginResource.id}" already exists.`);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
// Validate inputs
|
|
23
28
|
if (!pluginResource.url && !pluginResource.code) {
|
|
24
|
-
res.status(400).send(
|
|
29
|
+
res.status(400).send("Plugin code or URL must be provided");
|
|
25
30
|
return;
|
|
26
31
|
}
|
|
27
|
-
|
|
32
|
+
if (!pluginResource.moduleFormat) {
|
|
33
|
+
res.status(400).send("Plugin moduleFormat must be provided (cjs|esm)");
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
// Fetch code
|
|
37
|
+
let pluginCode;
|
|
28
38
|
try {
|
|
29
39
|
if (pluginResource.code) {
|
|
30
40
|
pluginCode = pluginResource.code;
|
|
31
41
|
}
|
|
32
42
|
else {
|
|
43
|
+
console.log(pluginResource.url);
|
|
33
44
|
const response = await axios.get(pluginResource.url);
|
|
34
45
|
pluginCode = response.data;
|
|
35
46
|
}
|
|
36
|
-
|
|
37
|
-
res.status(400).send(`Plugin code could not be loaded`);
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
if (pluginResource.install) {
|
|
41
|
-
const dependenciesStatus = await installDependencies(pluginResource.install);
|
|
42
|
-
if (!dependenciesStatus.success) {
|
|
43
|
-
if (pluginResource.install.ignoreErrors === true) {
|
|
44
|
-
logger.warn(`Warning: Error installing dependencies: ${JSON.stringify(dependenciesStatus.details)}`);
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
res.status(400).send(`Error installing dependencies: ${JSON.stringify(dependenciesStatus.details)}`);
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
logger.info("Plugin size: " + pluginCode?.length);
|
|
53
|
-
logger.info("Plugin format: " + pluginResource?.moduleFormat);
|
|
54
|
-
if (pluginResource?.moduleFormat && pluginResource.moduleFormat.toUpperCase() == "ESM") {
|
|
55
|
-
logger.info("ESM detected");
|
|
56
|
-
module = await importFromString(pluginCode);
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
logger.info("CJS detected (default)");
|
|
60
|
-
module = await requireFromString(pluginCode);
|
|
61
|
-
logger.info(module);
|
|
62
|
-
}
|
|
47
|
+
pluginResource.sourceCode = pluginCode;
|
|
63
48
|
}
|
|
64
|
-
catch (
|
|
65
|
-
|
|
66
|
-
res.status(400).send(`Error loading plugin: ${error}`);
|
|
49
|
+
catch (err) {
|
|
50
|
+
res.status(400).send(`Error fetching plugin code: ${err}`);
|
|
67
51
|
return;
|
|
68
52
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
res.status(400).send(`Plugin code should export a "plugin" object`);
|
|
72
|
-
logger.info("Error in plugin code: no plugin object exported");
|
|
53
|
+
if (!pluginCode) {
|
|
54
|
+
res.status(400).send("Plugin code could not be loaded");
|
|
73
55
|
return;
|
|
74
56
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
57
|
+
const isCjs = typeof __filename !== "undefined" && typeof __dirname !== "undefined";
|
|
58
|
+
const __filenameUniversal = isCjs
|
|
59
|
+
? __filename
|
|
60
|
+
: fileURLToPath(import.meta.url);
|
|
61
|
+
const __dirnameUniversal = isCjs
|
|
62
|
+
? __dirname
|
|
63
|
+
: path.dirname(__filenameUniversal);
|
|
64
|
+
const pluginProcessFile = isCjs
|
|
65
|
+
? "pluginProcess.cjs"
|
|
66
|
+
: "pluginProcess.js";
|
|
67
|
+
const child = fork(path.resolve(__dirnameUniversal, pluginProcessFile), [], {
|
|
68
|
+
stdio: ["pipe", "pipe", "pipe", "ipc"],
|
|
69
|
+
});
|
|
70
|
+
child.stdout?.on("data", (data) => {
|
|
71
|
+
logger.info(`[Plugin ${pluginResource.id}] STDOUT: ${data.toString().trim()}`);
|
|
72
|
+
});
|
|
73
|
+
child.stderr?.on("data", (data) => {
|
|
74
|
+
logger.error(`[Plugin ${pluginResource.id}] STDERR: ${data.toString().trim()}`);
|
|
75
|
+
});
|
|
76
|
+
child.on("message", (msg) => {
|
|
77
|
+
if (msg.event === "loaded") {
|
|
78
|
+
pluginResource.name = msg.name;
|
|
79
|
+
pluginResource.active = true;
|
|
80
|
+
pluginResource.process = child;
|
|
81
|
+
pluginService.pushPlugin(pluginResource);
|
|
82
|
+
res.status(201).send(`Plugin ${msg.name} registered`);
|
|
80
83
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
else if (msg.event === "error") {
|
|
85
|
+
res.status(400).send(`Error loading plugin: ${msg.error}`);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
child.on("exit", (code) => {
|
|
89
|
+
pluginResource.active = false;
|
|
90
|
+
pluginResource.process = undefined;
|
|
91
|
+
logger.warn(`Plugin ${pluginResource.id} exited (code: ${code})`);
|
|
92
|
+
});
|
|
93
|
+
child.on("disconnect", () => {
|
|
94
|
+
pluginResource.active = false;
|
|
95
|
+
pluginResource.process = undefined;
|
|
96
|
+
logger.warn(`Plugin ${pluginResource.id} disconnected`);
|
|
97
|
+
});
|
|
98
|
+
child.on("error", (err) => {
|
|
99
|
+
pluginResource.active = false;
|
|
100
|
+
pluginResource.process = undefined;
|
|
101
|
+
logger.error(`Plugin ${pluginResource.id} error: ${err.message}`);
|
|
102
|
+
});
|
|
103
|
+
// Send data to child
|
|
104
|
+
child.send({
|
|
105
|
+
type: "load",
|
|
106
|
+
pluginResource,
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
export const activatePlugin = (req, res) => {
|
|
110
|
+
const { id } = req.params;
|
|
111
|
+
const plugin = pluginService.getPlugins().find((p) => p.id === id);
|
|
112
|
+
if (!plugin) {
|
|
113
|
+
res.status(404).send(`Plugin with id "${id}" not found.`);
|
|
88
114
|
return;
|
|
89
115
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
res.status(
|
|
116
|
+
pluginService.activatePlugin(id);
|
|
117
|
+
res.status(200).send(`Plugin "${id}" activated.`);
|
|
118
|
+
};
|
|
119
|
+
export const deactivatePlugin = (req, res) => {
|
|
120
|
+
const { id } = req.params;
|
|
121
|
+
const plugin = pluginService.getPlugins().find((p) => p.id === id);
|
|
122
|
+
if (!plugin) {
|
|
123
|
+
res.status(404).send(`Plugin with id "${id}" not found.`);
|
|
124
|
+
return;
|
|
98
125
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
126
|
+
pluginService.deactivatePlugin(id); // This only sets active to false
|
|
127
|
+
res.status(200).send(`Plugin "${id}" deactivated.`);
|
|
128
|
+
};
|
|
129
|
+
export const deletePlugin = (req, res) => {
|
|
130
|
+
const { id } = req.params;
|
|
131
|
+
const plugin = pluginService.getPlugins().find((p) => p.id === id);
|
|
132
|
+
if (!plugin) {
|
|
133
|
+
res.status(404).send(`Plugin with id "${id}" not found.`);
|
|
134
|
+
return;
|
|
102
135
|
}
|
|
136
|
+
pluginService.deletePlugin(id); // kills child inside service
|
|
137
|
+
res.status(200).send(`Plugin "${id}" deleted.`);
|
|
103
138
|
};
|