@oas-tools/oas-telemetry 0.7.0-alpha.2 → 0.7.0-alpha.3
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 +242 -240
- 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 +52 -0
- package/dist/cjs/telemetry/custom-implementations/exporters/PluginMetricExporter.cjs +53 -0
- package/dist/cjs/telemetry/custom-implementations/exporters/PluginSpanExporter.cjs +69 -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 +40 -19
- package/dist/cjs/tlm-plugin/pluginRoutes.cjs +8 -6
- package/dist/cjs/tlm-plugin/pluginService.cjs +25 -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 +44 -0
- package/dist/esm/telemetry/custom-implementations/exporters/PluginMetricExporter.js +43 -0
- package/dist/esm/telemetry/custom-implementations/exporters/PluginSpanExporter.js +61 -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 +40 -19
- package/dist/esm/tlm-plugin/pluginRoutes.js +6 -5
- package/dist/esm/tlm-plugin/pluginService.js +19 -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 +253 -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/pluginRoutes.d.ts +1 -2
- package/dist/types/tlm-plugin/pluginService.d.ts +9 -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 +7 -46
- package/dist/types/utils/regexUtils.d.ts +1 -0
- package/dist/ui/assets/index-D9HsRlaQ.js +437 -0
- package/dist/ui/assets/index-DEyIcKBi.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
|
@@ -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,29 +1,51 @@
|
|
|
1
|
-
import { globalOasTlmConfig } from '../config.js';
|
|
2
1
|
import axios from 'axios';
|
|
3
2
|
// @ts-expect-error: import-from-string does not have proper type declarations
|
|
4
3
|
import { importFromString, requireFromString } from 'import-from-string';
|
|
5
4
|
// @ts-expect-error: dynamic-installer does not have proper type declarations
|
|
6
5
|
import { installDependencies } from 'dynamic-installer';
|
|
7
6
|
import logger from '../utils/logger.js';
|
|
7
|
+
import { pluginService } from './pluginService.js';
|
|
8
8
|
export const listPlugins = (req, res) => {
|
|
9
|
-
|
|
9
|
+
const plugins = pluginService.getPlugins().map((plugin) => {
|
|
10
10
|
return {
|
|
11
11
|
id: plugin.id,
|
|
12
12
|
name: plugin.name,
|
|
13
13
|
url: plugin.url,
|
|
14
14
|
active: plugin.active
|
|
15
15
|
};
|
|
16
|
-
})
|
|
16
|
+
});
|
|
17
|
+
res.send({
|
|
18
|
+
pluginsCount: plugins.length,
|
|
19
|
+
plugins: plugins
|
|
20
|
+
});
|
|
17
21
|
};
|
|
18
22
|
export const registerPlugin = async (req, res) => {
|
|
19
|
-
const pluginResource = req.body;
|
|
20
|
-
logger.info(`Plugin Registration Request: = ${JSON.stringify(req.body, null, 2)}...`);
|
|
21
|
-
logger.info(`Getting plugin at ${pluginResource.url}...`);
|
|
22
23
|
let pluginCode;
|
|
24
|
+
const pluginResource = req.body;
|
|
25
|
+
logger.debug(`Plugin Registration Request: = ${JSON.stringify(req.body, null, 2)}...`);
|
|
26
|
+
// Validate plugin id
|
|
27
|
+
if (!pluginResource.id || typeof pluginResource.id !== "string") {
|
|
28
|
+
res.status(400).send(`Plugin id must be provided and must be a string`);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
// Check for duplicate plugin id
|
|
32
|
+
const existingPlugin = pluginService.getPlugins().find((plugin) => plugin.id === pluginResource.id);
|
|
33
|
+
if (existingPlugin) {
|
|
34
|
+
res.status(400).send(`A plugin with id "${pluginResource.id}" already exists.`);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
23
37
|
if (!pluginResource.url && !pluginResource.code) {
|
|
24
38
|
res.status(400).send(`Plugin code or URL must be provided`);
|
|
25
39
|
return;
|
|
26
40
|
}
|
|
41
|
+
if (!pluginResource.moduleFormat) {
|
|
42
|
+
res.status(400).send(`Plugin moduleFormat must be provided (e.g., "cjs" or "esm")`);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (!["cjs", "esm"].includes(pluginResource.moduleFormat.toLowerCase())) {
|
|
46
|
+
res.status(400).send(`Invalid moduleFormat "${pluginResource.moduleFormat}". Supported formats are "cjs" and "esm".`);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
27
49
|
let module;
|
|
28
50
|
try {
|
|
29
51
|
if (pluginResource.code) {
|
|
@@ -38,6 +60,7 @@ export const registerPlugin = async (req, res) => {
|
|
|
38
60
|
return;
|
|
39
61
|
}
|
|
40
62
|
if (pluginResource.install) {
|
|
63
|
+
logger.info("Installing dependencies for plugin: " + pluginResource.name);
|
|
41
64
|
const dependenciesStatus = await installDependencies(pluginResource.install);
|
|
42
65
|
if (!dependenciesStatus.success) {
|
|
43
66
|
if (pluginResource.install.ignoreErrors === true) {
|
|
@@ -49,16 +72,14 @@ export const registerPlugin = async (req, res) => {
|
|
|
49
72
|
}
|
|
50
73
|
}
|
|
51
74
|
}
|
|
52
|
-
logger.
|
|
53
|
-
|
|
54
|
-
if (pluginResource?.moduleFormat && pluginResource.moduleFormat.toUpperCase() == "ESM") {
|
|
75
|
+
logger.debug("Plugin format (provided): " + pluginResource?.moduleFormat);
|
|
76
|
+
if (pluginResource.moduleFormat.toLowerCase() === "esm") {
|
|
55
77
|
logger.info("ESM detected");
|
|
56
78
|
module = await importFromString(pluginCode);
|
|
57
79
|
}
|
|
58
80
|
else {
|
|
59
81
|
logger.info("CJS detected (default)");
|
|
60
82
|
module = await requireFromString(pluginCode);
|
|
61
|
-
logger.info(module);
|
|
62
83
|
}
|
|
63
84
|
}
|
|
64
85
|
catch (error) {
|
|
@@ -67,14 +88,14 @@ export const registerPlugin = async (req, res) => {
|
|
|
67
88
|
return;
|
|
68
89
|
}
|
|
69
90
|
const plugin = module.default?.plugin ?? module.plugin;
|
|
70
|
-
if (plugin
|
|
71
|
-
res.status(400).send(`Plugin code should export a "plugin" object`);
|
|
72
|
-
logger.info("Error in plugin code: no plugin object exported");
|
|
91
|
+
if (!plugin) {
|
|
92
|
+
res.status(400).send(`Plugin code should export a valid "plugin" object or static class`);
|
|
93
|
+
logger.info("Error in plugin code: no valid plugin object exported");
|
|
73
94
|
return;
|
|
74
95
|
}
|
|
75
96
|
for (const requiredFunction of ["load", "getName", "isConfigured"]) {
|
|
76
|
-
if (plugin[requiredFunction]
|
|
77
|
-
res.status(400).send(`The plugin code exports a "plugin" object,
|
|
97
|
+
if (typeof plugin[requiredFunction] !== "function") {
|
|
98
|
+
res.status(400).send(`The plugin code exports a "plugin" object, but it must have a "${requiredFunction}" method`);
|
|
78
99
|
logger.info("Error in plugin code: some required functions are missing");
|
|
79
100
|
return;
|
|
80
101
|
}
|
|
@@ -89,15 +110,15 @@ export const registerPlugin = async (req, res) => {
|
|
|
89
110
|
}
|
|
90
111
|
if (plugin.isConfigured()) {
|
|
91
112
|
logger.info(`Loaded plugin <${plugin.getName()}>`);
|
|
92
|
-
pluginResource.
|
|
113
|
+
pluginResource.pluginImplementation = plugin;
|
|
93
114
|
pluginResource.name = plugin.getName();
|
|
94
115
|
pluginResource.active = true;
|
|
95
|
-
|
|
96
|
-
|
|
116
|
+
pluginService.pushPlugin(pluginResource);
|
|
117
|
+
pluginService.activatePlugin(pluginResource);
|
|
97
118
|
res.status(201).send(`Plugin registered`);
|
|
98
119
|
}
|
|
99
120
|
else {
|
|
100
|
-
logger.error(`Plugin <${plugin.getName()}>
|
|
121
|
+
logger.error(`Plugin <${plugin.getName()}> cannot be configured`);
|
|
101
122
|
res.status(400).send(`Plugin configuration problem`);
|
|
102
123
|
}
|
|
103
124
|
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Router } from 'express';
|
|
2
2
|
import { listPlugins, registerPlugin } from './pluginController.js';
|
|
3
|
-
export const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
export const getPluginRoutes = () => {
|
|
4
|
+
const router = Router();
|
|
5
|
+
router.get('/', listPlugins);
|
|
6
|
+
router.post('/', registerPlugin);
|
|
7
|
+
return router;
|
|
8
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
class PluginService {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.plugins = [];
|
|
4
|
+
}
|
|
5
|
+
getPlugins() {
|
|
6
|
+
return this.plugins;
|
|
7
|
+
}
|
|
8
|
+
pushPlugin(plugin) {
|
|
9
|
+
this.plugins.push(plugin);
|
|
10
|
+
}
|
|
11
|
+
activatePlugin(plugin) {
|
|
12
|
+
this.plugins.forEach(p => {
|
|
13
|
+
if (p.id === plugin.id) {
|
|
14
|
+
p.active = true;
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export const pluginService = new PluginService();
|
|
@@ -1,52 +1,48 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { inMemoryDbSpanExporter } from '../telemetry/telemetryRegistry.js';
|
|
2
|
+
import { convertRegexRecursively } from '../utils/regexUtils.js';
|
|
3
|
+
export const startTraces = (req, res) => {
|
|
4
|
+
inMemoryDbSpanExporter.enable();
|
|
5
|
+
res.send('Traces started');
|
|
5
6
|
};
|
|
6
|
-
export const
|
|
7
|
-
|
|
8
|
-
res.send('
|
|
7
|
+
export const stopTraces = (req, res) => {
|
|
8
|
+
inMemoryDbSpanExporter.disable();
|
|
9
|
+
res.send('Traces stopped');
|
|
9
10
|
};
|
|
10
|
-
export const
|
|
11
|
-
const isRunning =
|
|
11
|
+
export const statusTraces = (req, res) => {
|
|
12
|
+
const isRunning = inMemoryDbSpanExporter.isEnabled() || false;
|
|
12
13
|
res.send({ active: isRunning });
|
|
13
14
|
};
|
|
14
|
-
export const
|
|
15
|
-
|
|
16
|
-
res.send('
|
|
15
|
+
export const resetTraces = (req, res) => {
|
|
16
|
+
inMemoryDbSpanExporter.reset();
|
|
17
|
+
res.send('Traces reset');
|
|
17
18
|
};
|
|
18
|
-
export const
|
|
19
|
+
export const listTraces = async (req, res) => {
|
|
19
20
|
try {
|
|
20
|
-
const spans =
|
|
21
|
+
const spans = inMemoryDbSpanExporter.getFinishedSpans();
|
|
21
22
|
res.send({ spansCount: spans.length, spans: spans });
|
|
22
23
|
}
|
|
23
24
|
catch (err) {
|
|
24
25
|
console.error(err);
|
|
25
|
-
res.status(500).send({ error: 'Failed to list
|
|
26
|
+
res.status(500).send({ error: 'Failed to list traces data' });
|
|
26
27
|
}
|
|
27
28
|
};
|
|
28
|
-
export const
|
|
29
|
+
export const findTraces = (req, res) => {
|
|
29
30
|
const body = req.body;
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
body.config?.regexIds?.forEach(regexId => {
|
|
35
|
-
if (search[regexId])
|
|
36
|
-
search[regexId] = new RegExp(search[regexId]);
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
catch (e) {
|
|
40
|
-
console.error(e);
|
|
41
|
-
res.status(404).send({ spansCount: 0, spans: [], error: e });
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
31
|
+
const query = body?.query ? body.query : {};
|
|
32
|
+
let processedQuery;
|
|
33
|
+
try {
|
|
34
|
+
processedQuery = convertRegexRecursively(query);
|
|
44
35
|
}
|
|
45
|
-
|
|
36
|
+
catch (error) {
|
|
37
|
+
console.error(error.message);
|
|
38
|
+
res.status(400).send({ error: error.message });
|
|
39
|
+
return; // Exit if invalid regex was encountered
|
|
40
|
+
}
|
|
41
|
+
inMemoryDbSpanExporter.find(processedQuery, (err, docs) => {
|
|
46
42
|
if (err) {
|
|
47
43
|
console.error(err);
|
|
48
|
-
res.status(404).send({ spansCount: 0, spans: [], error: err });
|
|
49
|
-
return;
|
|
44
|
+
res.status(404).send({ spansCount: 0, spans: [], error: err.message });
|
|
45
|
+
return; // Exit the function to prevent further execution
|
|
50
46
|
}
|
|
51
47
|
const spans = docs;
|
|
52
48
|
res.send({ spansCount: spans.length, spans: spans });
|
|
@@ -67,11 +63,11 @@ export const insertTracesToDb = async (req, res) => {
|
|
|
67
63
|
try {
|
|
68
64
|
let message = '';
|
|
69
65
|
if (resetData) {
|
|
70
|
-
|
|
66
|
+
inMemoryDbSpanExporter.reset();
|
|
71
67
|
message += 'Traces Database reset. ';
|
|
72
68
|
}
|
|
73
69
|
await new Promise((resolve, reject) => {
|
|
74
|
-
|
|
70
|
+
inMemoryDbSpanExporter.insert(cleanedTraces, (err, newDocs) => {
|
|
75
71
|
if (err) {
|
|
76
72
|
console.error('Error inserting traces:', err);
|
|
77
73
|
return reject(err);
|
|
@@ -87,3 +83,12 @@ export const insertTracesToDb = async (req, res) => {
|
|
|
87
83
|
res.status(500).send({ error: 'Failed to reset and insert data', details: err.message });
|
|
88
84
|
}
|
|
89
85
|
};
|
|
86
|
+
export const setRetentionTimeTraces = (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
|
+
inMemoryDbSpanExporter.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 {
|
|
3
|
-
export const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
2
|
+
import { startTraces, stopTraces, statusTraces, resetTraces, listTraces, findTraces, insertTracesToDb, setRetentionTimeTraces } from './traceController.js';
|
|
3
|
+
export const getTraceRoutes = () => {
|
|
4
|
+
const router = Router();
|
|
5
|
+
// Telemetry Control
|
|
6
|
+
router.post('/start', startTraces);
|
|
7
|
+
router.post('/stop', stopTraces);
|
|
8
|
+
router.get('/status', statusTraces);
|
|
9
|
+
router.post('/reset', resetTraces);
|
|
10
|
+
router.get('/', listTraces);
|
|
11
|
+
router.post('/', insertTracesToDb);
|
|
12
|
+
router.post('/find', findTraces);
|
|
13
|
+
router.post('/retention-time', setRetentionTimeTraces);
|
|
14
|
+
return router;
|
|
15
|
+
};
|
|
16
|
+
export default getTraceRoutes;
|
|
@@ -2,22 +2,27 @@ import express, { Router } from 'express';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import logger from '../utils/logger.js';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
//
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
5
|
+
import { bootEnvVariables } from '../config/bootConfig.js';
|
|
6
|
+
export const getUIRoutes = () => {
|
|
7
|
+
// This is when this file is in /dist
|
|
8
|
+
let relativePath = '../../ui';
|
|
9
|
+
// This is when this file in in /src
|
|
10
|
+
if (bootEnvVariables.OASTLM_BOOT_ENV === 'development') {
|
|
11
|
+
relativePath = '../../dist/ui';
|
|
12
|
+
logger.warn('🚧 This process is serving the OASTLM UI from the build directory, but you are in development mode. For live updates, run the React app separately and access it at http://localhost:5173/.');
|
|
13
|
+
}
|
|
14
|
+
const customFilename = fileURLToPath(import.meta.url);
|
|
15
|
+
const customDirname = path.dirname(customFilename);
|
|
16
|
+
const staticFilesPath = path.join(customDirname, relativePath);
|
|
17
|
+
const router = Router();
|
|
18
|
+
// This only works once the app is built: src/ --> dist/esm/
|
|
19
|
+
// This file: dist/esm/routes/
|
|
20
|
+
// UI bundle: dist/ui/
|
|
21
|
+
// For development, the UI is served separately.
|
|
22
|
+
router.use(express.static(staticFilesPath));
|
|
23
|
+
router.get('*', (_req, res) => {
|
|
24
|
+
// Serve the index.html file for all routes
|
|
25
|
+
res.sendFile(path.join(staticFilesPath, 'index.html'));
|
|
26
|
+
});
|
|
27
|
+
return router;
|
|
28
|
+
};
|