@oas-tools/oas-telemetry 0.7.0-alpha.4 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +6 -2
- package/README.md +35 -17
- package/dist/cjs/config/bootConfig.cjs +3 -1
- package/dist/cjs/config/config.cjs +7 -5
- package/dist/cjs/docs/openapi.yaml +1399 -0
- package/dist/cjs/routesManager.cjs +36 -48
- package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbLogExporter.cjs +43 -13
- package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.cjs +10 -2
- package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.cjs +21 -16
- package/dist/cjs/telemetry/initializeTelemetry.cjs +39 -15
- package/dist/cjs/telemetry/telemetryConfigurator.cjs +6 -9
- package/dist/cjs/telemetry/telemetryRegistry.cjs +11 -8
- package/dist/cjs/tlm-ai/agent.cjs +54 -84
- package/dist/cjs/tlm-ai/aiController.cjs +69 -47
- package/dist/cjs/tlm-ai/aiRoutes.cjs +10 -3
- package/dist/cjs/tlm-ai/aiService.cjs +109 -0
- package/dist/cjs/tlm-ai/tools.cjs +30 -268
- package/dist/cjs/tlm-auth/authController.cjs +91 -26
- package/dist/cjs/tlm-auth/authMiddleware.cjs +20 -7
- package/dist/cjs/tlm-auth/authRoutes.cjs +3 -2
- package/dist/cjs/tlm-log/logController.cjs +30 -36
- package/dist/cjs/tlm-log/logRoutes.cjs +3 -2
- package/dist/cjs/tlm-metric/metricsController.cjs +15 -8
- package/dist/cjs/tlm-metric/metricsRoutes.cjs +2 -1
- package/dist/cjs/tlm-plugin/pluginController.cjs +11 -1
- package/dist/cjs/tlm-plugin/pluginProcess.cjs +4 -2
- package/dist/cjs/tlm-plugin/pluginService.cjs +3 -0
- package/dist/cjs/tlm-trace/traceController.cjs +16 -9
- package/dist/cjs/tlm-trace/traceRoutes.cjs +2 -1
- package/dist/cjs/tlm-util/utilController.cjs +23 -2
- package/dist/cjs/tlm-util/utilRoutes.cjs +44 -5
- package/dist/cjs/utils/logger.cjs +35 -13
- package/dist/esm/config/bootConfig.js +2 -0
- package/dist/esm/config/config.js +4 -2
- package/dist/esm/docs/openapi.yaml +1399 -0
- package/dist/esm/routesManager.js +37 -49
- package/dist/esm/telemetry/custom-implementations/exporters/InMemoryDbLogExporter.js +32 -11
- package/dist/esm/telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.js +10 -2
- package/dist/esm/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.js +20 -13
- package/dist/esm/telemetry/initializeTelemetry.js +22 -14
- package/dist/esm/telemetry/telemetryConfigurator.js +7 -10
- package/dist/esm/telemetry/telemetryRegistry.js +10 -7
- package/dist/esm/tlm-ai/agent.js +37 -78
- package/dist/esm/tlm-ai/aiController.js +56 -39
- package/dist/esm/tlm-ai/aiRoutes.js +11 -4
- package/dist/esm/tlm-ai/aiService.js +94 -0
- package/dist/esm/tlm-ai/tools.js +29 -255
- package/dist/esm/tlm-auth/authController.js +62 -20
- package/dist/esm/tlm-auth/authMiddleware.js +18 -9
- package/dist/esm/tlm-auth/authRoutes.js +4 -3
- package/dist/esm/tlm-log/logController.js +26 -28
- package/dist/esm/tlm-log/logRoutes.js +4 -3
- package/dist/esm/tlm-metric/metricsController.js +10 -6
- package/dist/esm/tlm-metric/metricsRoutes.js +3 -2
- package/dist/esm/tlm-plugin/pluginController.js +2 -1
- package/dist/esm/tlm-plugin/pluginProcess.js +4 -2
- package/dist/esm/tlm-plugin/pluginService.js +4 -0
- package/dist/esm/tlm-trace/traceController.js +11 -7
- package/dist/esm/tlm-trace/traceRoutes.js +3 -2
- package/dist/esm/tlm-util/utilController.js +22 -0
- package/dist/esm/tlm-util/utilRoutes.js +40 -5
- package/dist/esm/utils/logger.js +35 -12
- package/dist/types/config/bootConfig.d.ts +1 -0
- package/dist/types/config/config.d.ts +6 -3
- package/dist/types/telemetry/custom-implementations/exporters/InMemoryDbLogExporter.d.ts +7 -1
- package/dist/types/telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.d.ts +1 -0
- package/dist/types/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.d.ts +1 -0
- package/dist/types/telemetry/telemetryRegistry.d.ts +22 -6
- package/dist/types/tlm-ai/agent.d.ts +2 -2
- package/dist/types/tlm-ai/aiController.d.ts +5 -4
- package/dist/types/tlm-ai/aiRoutes.d.ts +1 -1
- package/dist/types/tlm-ai/aiService.d.ts +38 -0
- package/dist/types/tlm-ai/tools.d.ts +5 -14
- package/dist/types/tlm-auth/authController.d.ts +2 -1
- package/dist/types/tlm-log/logController.d.ts +2 -2
- package/dist/types/tlm-metric/metricsController.d.ts +2 -1
- package/dist/types/tlm-plugin/pluginService.d.ts +2 -0
- package/dist/types/tlm-trace/traceController.d.ts +2 -1
- package/dist/types/tlm-util/utilController.d.ts +1 -0
- package/dist/types/utils/logger.d.ts +5 -5
- package/dist/ui/assets/ApiDocsPage-C_VVPPHa.js +16 -0
- package/dist/ui/assets/CollapsibleCard-B3KR_8mL.js +1 -0
- package/dist/ui/assets/DevToolsPage-OyZcDcmw.js +1 -0
- package/dist/ui/assets/LandingPage-CppFBA6K.js +6 -0
- package/dist/ui/assets/LogsPage-9Fq8GArS.js +26 -0
- package/dist/ui/assets/NotFoundPage-B3quk3P1.js +1 -0
- package/dist/ui/assets/PluginCreatePage-X_aCH4t4.js +50 -0
- package/dist/ui/assets/PluginPage-DMDSihrZ.js +27 -0
- package/dist/ui/assets/alert-jQ9HCPIf.js +1133 -0
- package/dist/ui/assets/badge-CNq0-mH5.js +1 -0
- package/dist/ui/assets/card-DFAwwhN3.js +1 -0
- package/dist/ui/assets/chevron-down-CPsvsmqj.js +6 -0
- package/dist/ui/assets/chevron-up-Df9jMo1X.js +6 -0
- package/dist/ui/assets/circle-alert-DOPQPvU8.js +6 -0
- package/dist/ui/assets/index-BkD6DijD.js +15 -0
- package/dist/ui/assets/index-CERGVYZK.js +292 -0
- package/dist/ui/assets/index-CSIPf9qw.css +1 -0
- package/dist/ui/assets/input-Dzvg_ZEZ.js +1 -0
- package/dist/ui/assets/label-DuVnkZ4q.js +1 -0
- package/dist/ui/assets/loader-circle-CrvlRy5o.js +6 -0
- package/dist/ui/assets/loginPage-qa4V-B70.js +6 -0
- package/dist/ui/assets/select-DhS8YUtJ.js +1 -0
- package/dist/ui/assets/separator-isK4chBP.js +6 -0
- package/dist/ui/assets/severityOptions-O38dSOfk.js +11 -0
- package/dist/ui/assets/switch-Z3mImG9n.js +1 -0
- package/dist/ui/assets/tabs-_77MUUQe.js +16 -0
- package/dist/ui/assets/upload-C1LT4Gkb.js +16 -0
- package/dist/ui/assets/utilService-DNyqzwj0.js +1 -0
- package/dist/ui/index.html +2 -2
- package/package.json +18 -7
- package/dist/ui/assets/index-BzIdRox6.js +0 -1733
- package/dist/ui/assets/index-CkoHzrrt.css +0 -1
|
@@ -1,40 +1,82 @@
|
|
|
1
1
|
import jwt from 'jsonwebtoken';
|
|
2
2
|
import logger from '../utils/logger.js';
|
|
3
|
+
function generateAccessToken(secret, expiresIn) {
|
|
4
|
+
return jwt.sign({ type: "access" }, secret, { expiresIn: Math.floor(expiresIn / 1000) });
|
|
5
|
+
}
|
|
6
|
+
function generateRefreshToken(secret, expiresIn) {
|
|
7
|
+
return jwt.sign({ type: "refresh" }, secret, { expiresIn: Math.floor(expiresIn / 1000) });
|
|
8
|
+
}
|
|
3
9
|
export const getLogin = (oasTlmConfig) => (req, res) => {
|
|
10
|
+
if (!oasTlmConfig.auth.enabled) {
|
|
11
|
+
res.status(200).json({ valid: true, message: "Auth disabled" });
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
4
14
|
try {
|
|
5
15
|
const { password } = req.body;
|
|
6
16
|
if (password === oasTlmConfig.auth.password) {
|
|
7
|
-
const
|
|
8
|
-
|
|
17
|
+
const accessToken = generateAccessToken(oasTlmConfig.auth.jwtSecret, oasTlmConfig.auth.accessTokenMaxAge);
|
|
18
|
+
const refreshToken = generateRefreshToken(oasTlmConfig.auth.jwtSecret, oasTlmConfig.auth.refreshTokenMaxAge);
|
|
19
|
+
res.cookie("oas-tlm-access-token", accessToken, {
|
|
20
|
+
maxAge: oasTlmConfig.auth.accessTokenMaxAge,
|
|
21
|
+
httpOnly: true,
|
|
22
|
+
secure: process.env.NODE_ENV === "production",
|
|
23
|
+
sameSite: "lax",
|
|
24
|
+
path: "/"
|
|
25
|
+
});
|
|
26
|
+
res.cookie("oas-tlm-refresh-token", refreshToken, {
|
|
27
|
+
maxAge: oasTlmConfig.auth.refreshTokenMaxAge,
|
|
9
28
|
httpOnly: true,
|
|
10
|
-
secure:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
res.
|
|
15
|
-
res.status(200).json({ valid: true, message: 'API Key is valid' });
|
|
29
|
+
secure: process.env.NODE_ENV === "production",
|
|
30
|
+
sameSite: "lax",
|
|
31
|
+
path: oasTlmConfig.general.baseUrl + "/auth/refresh"
|
|
32
|
+
});
|
|
33
|
+
res.status(200).json({ valid: true, message: "Login successful" });
|
|
16
34
|
return;
|
|
17
35
|
}
|
|
18
|
-
res.status(400).json({ valid: false, message:
|
|
36
|
+
res.status(400).json({ valid: false, message: "Invalid password" });
|
|
19
37
|
}
|
|
20
38
|
catch (error) {
|
|
21
|
-
logger.
|
|
22
|
-
res.status(500).json({ valid: false, message:
|
|
39
|
+
logger.error("Login error: ", error);
|
|
40
|
+
res.status(500).json({ valid: false, message: "Internal server error" });
|
|
23
41
|
}
|
|
24
42
|
};
|
|
25
43
|
export const getLogout = (oasTlmConfig) => (req, res) => {
|
|
26
|
-
|
|
27
|
-
|
|
44
|
+
if (!oasTlmConfig.auth.enabled) {
|
|
45
|
+
res.status(200).json({ valid: true, message: "Auth disabled" });
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
res.clearCookie('oas-tlm-access-token', { path: '/' });
|
|
49
|
+
res.clearCookie('oas-tlm-refresh-token', { path: oasTlmConfig.general.baseUrl + '/auth/refresh' });
|
|
50
|
+
res.status(200).json({ valid: true, message: "Logged out" });
|
|
28
51
|
};
|
|
29
|
-
export const
|
|
30
|
-
if (!
|
|
31
|
-
res.status(200).json({ valid:
|
|
52
|
+
export const getRefresh = (oasTlmConfig) => (req, res) => {
|
|
53
|
+
if (!oasTlmConfig.auth.enabled) {
|
|
54
|
+
res.status(200).json({ valid: true, message: "Auth disabled" });
|
|
32
55
|
return;
|
|
33
56
|
}
|
|
34
|
-
const
|
|
35
|
-
if (
|
|
36
|
-
res.status(
|
|
57
|
+
const refreshToken = req.cookies["oas-tlm-refresh-token"];
|
|
58
|
+
if (!refreshToken) {
|
|
59
|
+
res.status(401).json({ valid: false, message: "No refresh token" });
|
|
37
60
|
return;
|
|
38
61
|
}
|
|
39
|
-
|
|
62
|
+
try {
|
|
63
|
+
const payload = jwt.verify(refreshToken, oasTlmConfig.auth.jwtSecret);
|
|
64
|
+
if (payload.type !== "refresh")
|
|
65
|
+
throw new Error("Invalid token type");
|
|
66
|
+
const accessToken = generateAccessToken(oasTlmConfig.auth.jwtSecret, oasTlmConfig.auth.accessTokenMaxAge);
|
|
67
|
+
res.cookie("oas-tlm-access-token", accessToken, {
|
|
68
|
+
maxAge: oasTlmConfig.auth.accessTokenMaxAge,
|
|
69
|
+
httpOnly: true,
|
|
70
|
+
secure: process.env.NODE_ENV === "production",
|
|
71
|
+
sameSite: "lax",
|
|
72
|
+
path: "/"
|
|
73
|
+
});
|
|
74
|
+
res.status(200).json({ valid: true, message: "Refreshed" });
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
res.status(401).json({ valid: false, message: "Invalid refresh token" });
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
export const getAuthEnabled = (oasTlmConfig) => (req, res) => {
|
|
81
|
+
res.status(200).json({ enabled: !!oasTlmConfig.auth.enabled });
|
|
40
82
|
};
|
|
@@ -1,13 +1,22 @@
|
|
|
1
|
-
import jwt from
|
|
1
|
+
import jwt from "jsonwebtoken";
|
|
2
2
|
export function getAuthMiddleware(oasTlmConfig) {
|
|
3
3
|
return function authMiddleware(req, res, next) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
if (!oasTlmConfig.auth.enabled) {
|
|
5
|
+
return next();
|
|
6
|
+
}
|
|
7
|
+
const token = req.cookies["oas-tlm-access-token"];
|
|
8
|
+
if (!token) {
|
|
9
|
+
res.status(401).json({ valid: false, message: "No access token" });
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
const payload = jwt.verify(token, oasTlmConfig.auth.jwtSecret);
|
|
14
|
+
if (payload.type !== "access")
|
|
15
|
+
throw new Error("Invalid token type");
|
|
16
|
+
return next();
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
res.status(401).json({ valid: false, message: "Invalid access token" });
|
|
20
|
+
}
|
|
12
21
|
};
|
|
13
22
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Router } from 'express';
|
|
2
|
-
import { getLogin, getLogout,
|
|
2
|
+
import { getLogin, getLogout, getRefresh, getAuthEnabled } from './authController.js';
|
|
3
3
|
export const getAuthRoutes = (oasTlmConfig) => {
|
|
4
4
|
const router = Router();
|
|
5
5
|
router.post('/login', getLogin(oasTlmConfig));
|
|
6
|
-
router.
|
|
7
|
-
router.
|
|
6
|
+
router.post('/refresh', getRefresh(oasTlmConfig));
|
|
7
|
+
router.post('/logout', getLogout(oasTlmConfig));
|
|
8
|
+
router.get('/enabled', getAuthEnabled(oasTlmConfig));
|
|
8
9
|
return router;
|
|
9
10
|
};
|
|
@@ -1,21 +1,13 @@
|
|
|
1
1
|
import { inMemoryDbLogExporter } from '../telemetry/telemetryRegistry.js';
|
|
2
2
|
import logger from '../utils/logger.js';
|
|
3
3
|
import { convertRegexRecursively } from '../utils/regexUtils.js';
|
|
4
|
-
export const listLogs = async (req, res) => {
|
|
5
|
-
try {
|
|
6
|
-
const logs = inMemoryDbLogExporter.getFinishedLogs();
|
|
7
|
-
res.send({ logsCount: logs.length, logs: logs });
|
|
8
|
-
}
|
|
9
|
-
catch (err) {
|
|
10
|
-
logger.error(err);
|
|
11
|
-
res.status(500).send({ error: 'Failed to list log data' });
|
|
12
|
-
}
|
|
13
|
-
};
|
|
14
4
|
export const findLogs = async (req, res) => {
|
|
15
|
-
const body = req.body;
|
|
16
|
-
const messageSearch = body
|
|
17
|
-
const findQuery = body
|
|
18
|
-
|
|
5
|
+
const body = req.body || {};
|
|
6
|
+
const messageSearch = body.textSearch || null;
|
|
7
|
+
const findQuery = body.query || {};
|
|
8
|
+
const limit = parseInt(body.limit) || 50;
|
|
9
|
+
const sortOrder = body.sort || null;
|
|
10
|
+
logger.debug(`findLogs called with query: ${JSON.stringify(findQuery)} and search: ${messageSearch}`, { depth: 3 });
|
|
19
11
|
let processedQuery;
|
|
20
12
|
try {
|
|
21
13
|
processedQuery = convertRegexRecursively(findQuery);
|
|
@@ -26,15 +18,17 @@ export const findLogs = async (req, res) => {
|
|
|
26
18
|
return; // Exit if invalid regex was encountered
|
|
27
19
|
}
|
|
28
20
|
try {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
21
|
+
// Use findConfig object
|
|
22
|
+
const findConfig = {
|
|
23
|
+
query: processedQuery,
|
|
24
|
+
messageSearch,
|
|
25
|
+
limit,
|
|
26
|
+
sortOrder
|
|
27
|
+
};
|
|
28
|
+
const docs = await inMemoryDbLogExporter.find(findConfig);
|
|
29
|
+
res.send({
|
|
30
|
+
items: docs,
|
|
35
31
|
});
|
|
36
|
-
const typedResults = results;
|
|
37
|
-
res.send({ logsCount: typedResults.length, logs: typedResults });
|
|
38
32
|
}
|
|
39
33
|
catch (err) {
|
|
40
34
|
logger.error(err);
|
|
@@ -49,7 +43,7 @@ export const insertLogsToDb = async (req, res) => {
|
|
|
49
43
|
const jsonContent = req.body.logs;
|
|
50
44
|
const resetData = req.query.reset === 'true';
|
|
51
45
|
if (!Array.isArray(jsonContent)) {
|
|
52
|
-
res.status(400).send({ error: 'Invalid data format.
|
|
46
|
+
res.status(400).send({ error: 'Invalid data format.' });
|
|
53
47
|
return;
|
|
54
48
|
}
|
|
55
49
|
const cleanedLogs = jsonContent.map((log) => {
|
|
@@ -92,12 +86,16 @@ export const statusLogs = (req, res) => {
|
|
|
92
86
|
const isRunning = inMemoryDbLogExporter.isEnabled() || false;
|
|
93
87
|
res.send({ active: isRunning });
|
|
94
88
|
};
|
|
95
|
-
export const
|
|
96
|
-
const
|
|
97
|
-
if (typeof
|
|
89
|
+
export const setLogRetentionTime = (req, res) => {
|
|
90
|
+
const retentionTimeInSeconds = req.body.retentionTimeInSeconds;
|
|
91
|
+
if (typeof retentionTimeInSeconds !== 'number' || retentionTimeInSeconds <= 0) {
|
|
98
92
|
res.status(400).send({ error: 'Invalid retention time. Must be a positive number.' });
|
|
99
93
|
return;
|
|
100
94
|
}
|
|
101
|
-
inMemoryDbLogExporter.retentionTimeInSeconds =
|
|
102
|
-
res.send({ message: `Retention time set to ${
|
|
95
|
+
inMemoryDbLogExporter.retentionTimeInSeconds = retentionTimeInSeconds;
|
|
96
|
+
res.send({ message: `Retention time set to ${retentionTimeInSeconds} seconds.` });
|
|
97
|
+
};
|
|
98
|
+
export const getLogRetentionTime = (req, res) => {
|
|
99
|
+
const retentionTimeInSeconds = inMemoryDbLogExporter.retentionTimeInSeconds || 0;
|
|
100
|
+
res.send({ retentionTimeInSeconds: retentionTimeInSeconds });
|
|
103
101
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Router } from 'express';
|
|
2
|
-
import { startLogs, stopLogs, statusLogs, resetLogs,
|
|
2
|
+
import { startLogs, stopLogs, statusLogs, resetLogs, findLogs, insertLogsToDb, setLogRetentionTime, getLogRetentionTime } from './logController.js';
|
|
3
3
|
export const getLogRoutes = () => {
|
|
4
4
|
const router = Router();
|
|
5
5
|
// Logs Control
|
|
@@ -7,8 +7,9 @@ export const getLogRoutes = () => {
|
|
|
7
7
|
router.post('/stop', stopLogs);
|
|
8
8
|
router.get('/status', statusLogs);
|
|
9
9
|
router.post('/reset', resetLogs);
|
|
10
|
-
router.post('/retention-time',
|
|
11
|
-
router.get('/',
|
|
10
|
+
router.post('/retention-time', setLogRetentionTime);
|
|
11
|
+
router.get('/retention-time', getLogRetentionTime);
|
|
12
|
+
router.get('/', findLogs);
|
|
12
13
|
router.post('/', insertLogsToDb);
|
|
13
14
|
router.post('/find', findLogs);
|
|
14
15
|
return router;
|
|
@@ -40,7 +40,7 @@ export const insertMetricsToDb = async (req, res) => {
|
|
|
40
40
|
const jsonContent = req.body.metrics;
|
|
41
41
|
const resetData = req.query.reset === 'true';
|
|
42
42
|
if (!Array.isArray(jsonContent)) {
|
|
43
|
-
res.status(400).send({ error: 'Invalid data format.
|
|
43
|
+
res.status(400).send({ error: 'Invalid data format.' });
|
|
44
44
|
return;
|
|
45
45
|
}
|
|
46
46
|
const cleanedMetrics = jsonContent.map((metric) => {
|
|
@@ -83,12 +83,16 @@ export const statusMetrics = (req, res) => {
|
|
|
83
83
|
const isRunning = inMemoryDbMetricExporter.isEnabled() || false;
|
|
84
84
|
res.send({ active: isRunning });
|
|
85
85
|
};
|
|
86
|
-
export const
|
|
87
|
-
const
|
|
88
|
-
if (typeof
|
|
86
|
+
export const setMetricRetentionTime = (req, res) => {
|
|
87
|
+
const retentionTimeInSeconds = req.body.retentionTimeInSeconds;
|
|
88
|
+
if (typeof retentionTimeInSeconds !== 'number' || retentionTimeInSeconds <= 0) {
|
|
89
89
|
res.status(400).send({ error: 'Invalid retention time. Must be a positive number.' });
|
|
90
90
|
return;
|
|
91
91
|
}
|
|
92
|
-
inMemoryDbMetricExporter.retentionTimeInSeconds =
|
|
93
|
-
res.send({ message: `Retention time set to ${
|
|
92
|
+
inMemoryDbMetricExporter.retentionTimeInSeconds = retentionTimeInSeconds;
|
|
93
|
+
res.send({ message: `Retention time set to ${retentionTimeInSeconds} seconds.` });
|
|
94
|
+
};
|
|
95
|
+
export const getMetricRetentionTime = (req, res) => {
|
|
96
|
+
const retentionTimeInSeconds = inMemoryDbMetricExporter.retentionTimeInSeconds || 0;
|
|
97
|
+
res.send({ retentionTimeInSeconds: retentionTimeInSeconds });
|
|
94
98
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Router } from 'express';
|
|
2
|
-
import { listMetrics, findMetrics, resetMetrics, insertMetricsToDb, startMetrics, stopMetrics, statusMetrics,
|
|
2
|
+
import { listMetrics, findMetrics, resetMetrics, insertMetricsToDb, startMetrics, stopMetrics, statusMetrics, setMetricRetentionTime, getMetricRetentionTime } from './metricsController.js';
|
|
3
3
|
export const getMetricsRoutes = () => {
|
|
4
4
|
const router = Router();
|
|
5
5
|
// Metrics Control
|
|
@@ -7,7 +7,8 @@ export const getMetricsRoutes = () => {
|
|
|
7
7
|
router.post('/stop', stopMetrics);
|
|
8
8
|
router.get('/status', statusMetrics);
|
|
9
9
|
router.post('/reset', resetMetrics);
|
|
10
|
-
router.post('/retention-time',
|
|
10
|
+
router.post('/retention-time', setMetricRetentionTime);
|
|
11
|
+
router.get('/retention-time', getMetricRetentionTime);
|
|
11
12
|
router.get('/', listMetrics);
|
|
12
13
|
router.post('/', insertMetricsToDb);
|
|
13
14
|
router.post('/find', findMetrics);
|
|
@@ -5,7 +5,8 @@ import logger from "../utils/logger.js";
|
|
|
5
5
|
import { pluginService } from "./pluginService.js";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
7
|
export const listPlugins = (req, res) => {
|
|
8
|
-
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
9
|
+
const plugins = pluginService.getPlugins().map(({ process, ...rest }) => rest);
|
|
9
10
|
res.send({
|
|
10
11
|
pluginsCount: plugins.length,
|
|
11
12
|
plugins,
|
|
@@ -14,12 +14,14 @@ process.on("message", async (msg) => {
|
|
|
14
14
|
if (pluginResource.install && Array.isArray(pluginResource.install.dependencies) && pluginResource.install.dependencies.length > 0) {
|
|
15
15
|
log("Installing dependencies for plugin: " + pluginResource.name);
|
|
16
16
|
const dependenciesStatus = await installDependencies(pluginResource.install);
|
|
17
|
+
console.dir(dependenciesStatus);
|
|
17
18
|
if (!dependenciesStatus.success) {
|
|
19
|
+
const detailsFailed = dependenciesStatus.details.filter(detail => detail.success === false);
|
|
18
20
|
if (pluginResource.install.ignoreErrors === true) {
|
|
19
|
-
log(`Warning: Error installing dependencies: ${JSON.stringify(
|
|
21
|
+
log(`Warning: Error installing dependencies: ${JSON.stringify(detailsFailed)}. Continuing as ignoreErrors is true.`);
|
|
20
22
|
}
|
|
21
23
|
else {
|
|
22
|
-
process.send?.({ event: "error", error: `Error installing dependencies: ${JSON.stringify(
|
|
24
|
+
process.send?.({ event: "error", error: `Error installing dependencies: ${JSON.stringify(detailsFailed)}` });
|
|
23
25
|
return;
|
|
24
26
|
}
|
|
25
27
|
}
|
|
@@ -2,6 +2,7 @@ import logger from "../utils/logger.js";
|
|
|
2
2
|
class PluginService {
|
|
3
3
|
constructor() {
|
|
4
4
|
this.plugins = [];
|
|
5
|
+
this.enabled = false;
|
|
5
6
|
}
|
|
6
7
|
getPlugins() {
|
|
7
8
|
return this.plugins;
|
|
@@ -29,6 +30,8 @@ class PluginService {
|
|
|
29
30
|
this.plugins = this.plugins.filter((p) => p.id !== pluginId);
|
|
30
31
|
}
|
|
31
32
|
broadcastToPlugins(type, payload) {
|
|
33
|
+
if (!this.enabled)
|
|
34
|
+
return;
|
|
32
35
|
this.plugins.forEach((plugin, i) => {
|
|
33
36
|
if (!plugin.active)
|
|
34
37
|
return;
|
|
@@ -65,6 +68,7 @@ class PluginService {
|
|
|
65
68
|
}
|
|
66
69
|
/**
|
|
67
70
|
* Broadcast a new trace to all active plugins
|
|
71
|
+
* TODO: rename to span (trace is the whole trace, span is a single unit of work within a trace)
|
|
68
72
|
*/
|
|
69
73
|
broadcastTrace(trace) {
|
|
70
74
|
this.broadcastToPlugins("newTrace", trace);
|
|
@@ -41,7 +41,7 @@ export const findTraces = (req, res) => {
|
|
|
41
41
|
inMemoryDbSpanExporter.find(processedQuery, (err, docs) => {
|
|
42
42
|
if (err) {
|
|
43
43
|
console.error(err);
|
|
44
|
-
res.status(
|
|
44
|
+
res.status(400).send({ spansCount: 0, spans: [], error: err.message });
|
|
45
45
|
return; // Exit the function to prevent further execution
|
|
46
46
|
}
|
|
47
47
|
const spans = docs;
|
|
@@ -52,7 +52,7 @@ export const insertTracesToDb = async (req, res) => {
|
|
|
52
52
|
const jsonContent = req.body.spans;
|
|
53
53
|
const resetData = req.query.reset === 'true';
|
|
54
54
|
if (!Array.isArray(jsonContent)) {
|
|
55
|
-
res.status(400).send({ error: 'Invalid data format.
|
|
55
|
+
res.status(400).send({ error: 'Invalid data format.' });
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
58
58
|
const cleanedTraces = jsonContent.map((trace) => {
|
|
@@ -83,12 +83,16 @@ export const insertTracesToDb = async (req, res) => {
|
|
|
83
83
|
res.status(500).send({ error: 'Failed to reset and insert data', details: err.message });
|
|
84
84
|
}
|
|
85
85
|
};
|
|
86
|
-
export const
|
|
87
|
-
const
|
|
88
|
-
if (typeof
|
|
86
|
+
export const setTraceRetentionTime = (req, res) => {
|
|
87
|
+
const retentionTimeInSeconds = req.body.retentionTimeInSeconds;
|
|
88
|
+
if (typeof retentionTimeInSeconds !== 'number' || retentionTimeInSeconds <= 0) {
|
|
89
89
|
res.status(400).send({ error: 'Invalid retention time. Must be a positive number.' });
|
|
90
90
|
return;
|
|
91
91
|
}
|
|
92
|
-
inMemoryDbSpanExporter.retentionTimeInSeconds =
|
|
93
|
-
res.send({ message: `Retention time set to ${
|
|
92
|
+
inMemoryDbSpanExporter.retentionTimeInSeconds = retentionTimeInSeconds;
|
|
93
|
+
res.send({ message: `Retention time set to ${retentionTimeInSeconds} seconds.` });
|
|
94
|
+
};
|
|
95
|
+
export const getTraceRetentionTime = (req, res) => {
|
|
96
|
+
const retentionTimeInSeconds = inMemoryDbSpanExporter.retentionTimeInSeconds || 0;
|
|
97
|
+
res.send({ retentionTimeInSeconds: retentionTimeInSeconds });
|
|
94
98
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Router } from 'express';
|
|
2
|
-
import { startTraces, stopTraces, statusTraces, resetTraces, listTraces, findTraces, insertTracesToDb,
|
|
2
|
+
import { startTraces, stopTraces, statusTraces, resetTraces, listTraces, findTraces, insertTracesToDb, setTraceRetentionTime, getTraceRetentionTime } from './traceController.js';
|
|
3
3
|
export const getTraceRoutes = () => {
|
|
4
4
|
const router = Router();
|
|
5
5
|
// Telemetry Control
|
|
@@ -10,7 +10,8 @@ export const getTraceRoutes = () => {
|
|
|
10
10
|
router.get('/', listTraces);
|
|
11
11
|
router.post('/', insertTracesToDb);
|
|
12
12
|
router.post('/find', findTraces);
|
|
13
|
-
router.post('/retention-time',
|
|
13
|
+
router.post('/retention-time', setTraceRetentionTime);
|
|
14
|
+
router.get('/retention-time', getTraceRetentionTime);
|
|
14
15
|
return router;
|
|
15
16
|
};
|
|
16
17
|
export default getTraceRoutes;
|
|
@@ -2,6 +2,7 @@ import { readFileSync } from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import yaml from 'js-yaml';
|
|
4
4
|
import v8 from 'node:v8';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
5
6
|
export const specLoader = (_req, res, oasTlmConfig) => {
|
|
6
7
|
if (oasTlmConfig.general.specFileName) {
|
|
7
8
|
try {
|
|
@@ -54,3 +55,24 @@ export const heapStats = (req, res) => {
|
|
|
54
55
|
roundedHeapStats['units'] = 'MB';
|
|
55
56
|
res.send(roundedHeapStats);
|
|
56
57
|
};
|
|
58
|
+
const isCjs = typeof __filename !== "undefined" && typeof __dirname !== "undefined";
|
|
59
|
+
const __filenameUniversal = isCjs
|
|
60
|
+
? __filename
|
|
61
|
+
: fileURLToPath(import.meta.url);
|
|
62
|
+
const __dirnameUniversal = isCjs
|
|
63
|
+
? __dirname
|
|
64
|
+
: path.dirname(__filenameUniversal);
|
|
65
|
+
export const getOasTelemetrySpec = (_req, res) => {
|
|
66
|
+
try {
|
|
67
|
+
const specPath = path.join(__dirnameUniversal, '../docs/openapi.yaml');
|
|
68
|
+
const data = readFileSync(specPath, { encoding: 'utf8', flag: 'r' });
|
|
69
|
+
let json = data;
|
|
70
|
+
json = JSON.stringify(yaml.load(data), null, 2);
|
|
71
|
+
res.setHeader('Content-Type', 'application/json');
|
|
72
|
+
res.send(json);
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
75
|
+
console.error(`ERROR loading OAS Telemetry OpenAPI spec file: ${e}`);
|
|
76
|
+
res.status(500).send(`ERROR loading OAS Telemetry OpenAPI spec file: ${e}`);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
@@ -1,15 +1,33 @@
|
|
|
1
1
|
import { Router } from 'express';
|
|
2
|
-
import { specLoader, heapStats } from './utilController.js';
|
|
2
|
+
import { specLoader, heapStats, getOasTelemetrySpec } from './utilController.js';
|
|
3
3
|
export const getUtilsRoutes = (oasTlmConfig) => {
|
|
4
4
|
const router = Router();
|
|
5
5
|
router.get('/spec', (req, res) => specLoader(req, res, oasTlmConfig));
|
|
6
|
+
router.get('/oas-telemetry-spec', (req, res) => getOasTelemetrySpec(req, res));
|
|
6
7
|
router.get('/heapStats', heapStats);
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
//This route is NOT ignored by the spanExporter (includes "generate")
|
|
9
|
+
router.post('/generate-log', async (req, res) => {
|
|
10
|
+
const log = req.body.log || 'Default log message';
|
|
11
|
+
const repeat = parseInt(req.body.repeat) || 1;
|
|
12
|
+
const method = req.body.method?.toLowerCase() || 'log';
|
|
13
|
+
if (!['log', 'warn', 'error', 'info', 'debug'].includes(method)) {
|
|
14
|
+
res.status(400).send({ error: 'Invalid method. Use log, warn, error, info, or debug.' });
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
10
17
|
res.send({ message: 'Log generated', log: log });
|
|
18
|
+
for (let i = 0; i < repeat; i++) {
|
|
19
|
+
console[method](log);
|
|
20
|
+
await new Promise(resolve => setTimeout(resolve, 50)); // Slight delay between logs
|
|
21
|
+
}
|
|
11
22
|
});
|
|
12
|
-
|
|
23
|
+
// This route is NOT ignored by the spanExporter (includes "generate")
|
|
24
|
+
router.post('/generate-mock-logs', async (req, res) => {
|
|
25
|
+
const count = parseInt(req.body.count) || 50;
|
|
26
|
+
generateMockLogs(count);
|
|
27
|
+
res.send({ message: 'Started generating mock logs' });
|
|
28
|
+
});
|
|
29
|
+
// This route is NOT ignored by the spanExporter
|
|
30
|
+
router.get('/generate-wait/:seconds?', async (req, res) => {
|
|
13
31
|
const seconds = parseInt(req.params.seconds ?? "1", 10);
|
|
14
32
|
const waitTime = isNaN(seconds) ? 1 : seconds;
|
|
15
33
|
await new Promise(resolve => setTimeout(resolve, waitTime * 1000));
|
|
@@ -17,3 +35,20 @@ export const getUtilsRoutes = (oasTlmConfig) => {
|
|
|
17
35
|
});
|
|
18
36
|
return router;
|
|
19
37
|
};
|
|
38
|
+
const generateMockLogs = async (count) => {
|
|
39
|
+
const methodMessages = {
|
|
40
|
+
log: ['User logged in', 'Data fetched successfully'],
|
|
41
|
+
warn: ['Warning: Disk space low', 'Warning: High memory usage'],
|
|
42
|
+
error: ['Error connecting to database', 'Error: Invalid credentials'],
|
|
43
|
+
info: ['Info: Scheduled job started', 'Info: Configuration loaded'],
|
|
44
|
+
debug: ['Debugging mode enabled', 'Debug: Variable x = 42'],
|
|
45
|
+
};
|
|
46
|
+
const methods = Object.keys(methodMessages);
|
|
47
|
+
for (let i = 0; i < count; i++) {
|
|
48
|
+
await new Promise(resolve => setTimeout(resolve, 50)); // Slight delay between logs
|
|
49
|
+
const method = methods[Math.floor(Math.random() * methods.length)];
|
|
50
|
+
const messages = methodMessages[method];
|
|
51
|
+
const message = messages[Math.floor(Math.random() * messages.length)];
|
|
52
|
+
console[method](`[${new Date().toISOString()}][MOCK LOG][${method.toUpperCase()}] -${i + 1}- ${message}`);
|
|
53
|
+
}
|
|
54
|
+
};
|
package/dist/esm/utils/logger.js
CHANGED
|
@@ -1,18 +1,41 @@
|
|
|
1
1
|
import { bootEnvVariables } from "../config/bootConfig.js";
|
|
2
|
+
import { originalConsoleMethods } from "../telemetry/telemetryRegistry.js";
|
|
2
3
|
const LOG_LEVELS = ['DEBUG', 'INFO', 'WARN', 'ERROR', 'NONE'];
|
|
3
|
-
const currentLogLevel = (bootEnvVariables.OASTLM_BOOT_LOG_LEVEL
|
|
4
|
-
const serviceName = 'OAS-
|
|
5
|
-
function
|
|
6
|
-
|
|
7
|
-
const timestamp = new Date().toISOString();
|
|
8
|
-
console.log(`${timestamp} [${serviceName}] [${level}]:`, ...messages);
|
|
9
|
-
}
|
|
4
|
+
const currentLogLevel = (bootEnvVariables.OASTLM_BOOT_LOG_LEVEL).toUpperCase();
|
|
5
|
+
const serviceName = 'OAS-TLM-@-' + bootEnvVariables.OASTLM_BOOT_SERVICE_NAME;
|
|
6
|
+
function shouldLog(level) {
|
|
7
|
+
return LOG_LEVELS.indexOf(level) >= LOG_LEVELS.indexOf(currentLogLevel);
|
|
10
8
|
}
|
|
11
9
|
export default {
|
|
12
|
-
debug: (...messages) =>
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
debug: (...messages) => {
|
|
11
|
+
if (shouldLog('DEBUG')) {
|
|
12
|
+
const timestamp = new Date().toISOString();
|
|
13
|
+
originalConsoleMethods.debug(`${timestamp} [${serviceName}] [DEBUG]:`, ...messages);
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
info: (...messages) => {
|
|
17
|
+
if (shouldLog('INFO')) {
|
|
18
|
+
const timestamp = new Date().toISOString();
|
|
19
|
+
originalConsoleMethods.info(`${timestamp} [${serviceName}] [INFO]:`, ...messages);
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
log: (...messages) => {
|
|
23
|
+
if (shouldLog('INFO')) {
|
|
24
|
+
const timestamp = new Date().toISOString();
|
|
25
|
+
originalConsoleMethods.log(`${timestamp} [${serviceName}] [INFO]:`, ...messages);
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
warn: (...messages) => {
|
|
29
|
+
if (shouldLog('WARN')) {
|
|
30
|
+
const timestamp = new Date().toISOString();
|
|
31
|
+
originalConsoleMethods.warn(`${timestamp} [${serviceName}] [WARN]:`, ...messages);
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
error: (...messages) => {
|
|
35
|
+
if (shouldLog('ERROR')) {
|
|
36
|
+
const timestamp = new Date().toISOString();
|
|
37
|
+
originalConsoleMethods.error(`${timestamp} [${serviceName}] [ERROR]:`, ...messages);
|
|
38
|
+
}
|
|
39
|
+
},
|
|
17
40
|
currentLogLevel
|
|
18
41
|
};
|
|
@@ -13,9 +13,10 @@ export declare const defaultConfig: {
|
|
|
13
13
|
};
|
|
14
14
|
auth: {
|
|
15
15
|
enabled: boolean;
|
|
16
|
-
apiKeyMaxAge: number;
|
|
17
16
|
password: string;
|
|
18
17
|
jwtSecret: string;
|
|
18
|
+
accessTokenMaxAge: number;
|
|
19
|
+
refreshTokenMaxAge: number;
|
|
19
20
|
};
|
|
20
21
|
ai: {
|
|
21
22
|
openAIKey: string | null;
|
|
@@ -70,9 +71,10 @@ export declare const getConfig: (userConfig?: UserConfig, fallbackConfig?: OasTl
|
|
|
70
71
|
};
|
|
71
72
|
auth: {
|
|
72
73
|
enabled: boolean;
|
|
73
|
-
apiKeyMaxAge: number;
|
|
74
74
|
password: string;
|
|
75
75
|
jwtSecret: string;
|
|
76
|
+
accessTokenMaxAge: number;
|
|
77
|
+
refreshTokenMaxAge: number;
|
|
76
78
|
};
|
|
77
79
|
ai: {
|
|
78
80
|
openAIKey: string | null;
|
|
@@ -126,9 +128,10 @@ export declare const getConfig: (userConfig?: UserConfig, fallbackConfig?: OasTl
|
|
|
126
128
|
} | undefined;
|
|
127
129
|
auth?: {
|
|
128
130
|
enabled?: boolean | undefined;
|
|
129
|
-
apiKeyMaxAge?: number | undefined;
|
|
130
131
|
password?: string | undefined;
|
|
131
132
|
jwtSecret?: string | undefined;
|
|
133
|
+
accessTokenMaxAge?: number | undefined;
|
|
134
|
+
refreshTokenMaxAge?: number | undefined;
|
|
132
135
|
} | undefined;
|
|
133
136
|
ai?: {
|
|
134
137
|
openAIKey?: string | null | undefined;
|
|
@@ -17,7 +17,12 @@ export declare class InMemoryDbLogExporter extends Enabler implements LogRecordE
|
|
|
17
17
|
* Shutdown the exporter.
|
|
18
18
|
*/
|
|
19
19
|
shutdown(): Promise<void>;
|
|
20
|
-
find(
|
|
20
|
+
find(findConfig: {
|
|
21
|
+
query: any;
|
|
22
|
+
messageSearch: string | null;
|
|
23
|
+
limit: number;
|
|
24
|
+
sortOrder?: any;
|
|
25
|
+
}): Promise<any[]>;
|
|
21
26
|
insert(data: any[], callback: (err: any, newDocs: any[]) => void): void;
|
|
22
27
|
getFinishedLogs(): any[];
|
|
23
28
|
/**
|
|
@@ -28,6 +33,7 @@ export declare class InMemoryDbLogExporter extends Enabler implements LogRecordE
|
|
|
28
33
|
*/
|
|
29
34
|
private _formatLogRecord;
|
|
30
35
|
set retentionTimeInSeconds(retentionTimeInSeconds: number);
|
|
36
|
+
get retentionTimeInSeconds(): number;
|
|
31
37
|
private _insertLogs;
|
|
32
38
|
private _startCleanupJob;
|
|
33
39
|
}
|
|
@@ -17,5 +17,6 @@ export declare class InMemoryDbMetricExporter extends Enabler implements PushMet
|
|
|
17
17
|
*/
|
|
18
18
|
insert(metrics: any[], callback: (err: any, newDocs: any[]) => void): void;
|
|
19
19
|
set retentionTimeInSeconds(retentionTimeInSeconds: number);
|
|
20
|
+
get retentionTimeInSeconds(): number;
|
|
20
21
|
private _startCleanupJob;
|
|
21
22
|
}
|