@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
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// pluginProcess.js
|
|
2
|
+
// Runs inside a child process, isolated from the main app
|
|
3
|
+
// @ts-expect-error no types
|
|
4
|
+
import { importFromString, requireFromString } from "import-from-string";
|
|
5
|
+
import { installDependencies } from "dynamic-installer";
|
|
6
|
+
let plugin;
|
|
7
|
+
const log = (...args) => {
|
|
8
|
+
console.log(`[PluginProcess:${process.pid}]`, ...args);
|
|
9
|
+
};
|
|
10
|
+
process.on("message", async (msg) => {
|
|
11
|
+
if (msg.type === "load") {
|
|
12
|
+
try {
|
|
13
|
+
const pluginResource = normalizePluginResource(msg.pluginResource);
|
|
14
|
+
if (pluginResource.install && Array.isArray(pluginResource.install.dependencies) && pluginResource.install.dependencies.length > 0) {
|
|
15
|
+
log("Installing dependencies for plugin: " + pluginResource.name);
|
|
16
|
+
const dependenciesStatus = await installDependencies(pluginResource.install);
|
|
17
|
+
if (!dependenciesStatus.success) {
|
|
18
|
+
if (pluginResource.install.ignoreErrors === true) {
|
|
19
|
+
log(`Warning: Error installing dependencies: ${JSON.stringify(dependenciesStatus.details)}`);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
process.send?.({ event: "error", error: `Error installing dependencies: ${JSON.stringify(dependenciesStatus.details)}` });
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
let module;
|
|
28
|
+
if (pluginResource?.moduleFormat?.toLowerCase() === "esm") {
|
|
29
|
+
module = await importFromString(pluginResource.sourceCode);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
module = await requireFromString(pluginResource.sourceCode);
|
|
33
|
+
}
|
|
34
|
+
plugin = module.default?.plugin ?? module.plugin;
|
|
35
|
+
if (!plugin)
|
|
36
|
+
throw new Error("Plugin must export a valid 'plugin' object");
|
|
37
|
+
for (const fn of ["load", "isConfigured"]) {
|
|
38
|
+
if (typeof plugin[fn] !== "function") {
|
|
39
|
+
throw new Error(`Plugin is missing required function "${fn}"`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
await plugin.load(pluginResource.config);
|
|
43
|
+
if (!plugin.isConfigured()) {
|
|
44
|
+
throw new Error("Plugin could not be configured");
|
|
45
|
+
}
|
|
46
|
+
process.send?.({ event: "loaded", name: pluginResource.name || pluginResource.id || "unknown" });
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
process.send?.({ event: "error", error: err.message });
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Forward log/metric/trace calls
|
|
54
|
+
if (msg.type === "newLog" && plugin?.newLog) {
|
|
55
|
+
plugin.newLog(msg.payload);
|
|
56
|
+
}
|
|
57
|
+
if (msg.type === "newMetric" && plugin?.newMetric) {
|
|
58
|
+
plugin.newMetric(msg.payload);
|
|
59
|
+
}
|
|
60
|
+
if (msg.type === "newTrace" && plugin?.newTrace) {
|
|
61
|
+
plugin.newTrace(msg.payload);
|
|
62
|
+
}
|
|
63
|
+
if (msg.type === "unload") {
|
|
64
|
+
if (plugin && typeof plugin.unload === "function") {
|
|
65
|
+
await plugin.unload();
|
|
66
|
+
}
|
|
67
|
+
process.send?.({ event: "unloaded" });
|
|
68
|
+
process.exit(0);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
function normalizePluginResource(raw) {
|
|
72
|
+
let resource = raw;
|
|
73
|
+
// case: received as stringified JSON
|
|
74
|
+
if (typeof raw === "string") {
|
|
75
|
+
try {
|
|
76
|
+
resource = JSON.parse(raw);
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
throw new Error("Invalid pluginResource JSON: " + err.message);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// normalize install
|
|
83
|
+
if (typeof resource.install === "string") {
|
|
84
|
+
try {
|
|
85
|
+
resource.install = JSON.parse(resource.install);
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
throw new Error("Invalid install JSON: " + err.message);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// normalize config
|
|
92
|
+
if (typeof resource.config === "string") {
|
|
93
|
+
try {
|
|
94
|
+
resource.config = JSON.parse(resource.config);
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
throw new Error("Invalid config JSON: " + err.message);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return resource;
|
|
101
|
+
}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { Router } from 'express';
|
|
2
|
-
import { listPlugins, registerPlugin } from './pluginController.js';
|
|
3
|
-
export const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
import { listPlugins, registerPlugin, activatePlugin, deactivatePlugin, deletePlugin } from './pluginController.js';
|
|
3
|
+
export const getPluginRoutes = () => {
|
|
4
|
+
const router = Router();
|
|
5
|
+
router.get('/', listPlugins);
|
|
6
|
+
router.post('/', registerPlugin);
|
|
7
|
+
router.post('/:id/activate', activatePlugin);
|
|
8
|
+
router.post('/:id/deactivate', deactivatePlugin);
|
|
9
|
+
router.delete('/:id', deletePlugin);
|
|
10
|
+
return router;
|
|
11
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import logger from "../utils/logger.js";
|
|
2
|
+
class PluginService {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.plugins = [];
|
|
5
|
+
}
|
|
6
|
+
getPlugins() {
|
|
7
|
+
return this.plugins;
|
|
8
|
+
}
|
|
9
|
+
pushPlugin(plugin) {
|
|
10
|
+
this.plugins.push(plugin);
|
|
11
|
+
}
|
|
12
|
+
activatePlugin(pluginId) {
|
|
13
|
+
const plugin = this.plugins.find((p) => p.id === pluginId);
|
|
14
|
+
if (plugin) {
|
|
15
|
+
plugin.active = true;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
deactivatePlugin(pluginId) {
|
|
19
|
+
const plugin = this.plugins.find((p) => p.id === pluginId);
|
|
20
|
+
if (plugin) {
|
|
21
|
+
plugin.active = false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
deletePlugin(pluginId) {
|
|
25
|
+
const plugin = this.plugins.find((p) => p.id === pluginId);
|
|
26
|
+
if (plugin?.process && !plugin.process.killed) {
|
|
27
|
+
plugin.process.kill(1);
|
|
28
|
+
}
|
|
29
|
+
this.plugins = this.plugins.filter((p) => p.id !== pluginId);
|
|
30
|
+
}
|
|
31
|
+
broadcastToPlugins(type, payload) {
|
|
32
|
+
this.plugins.forEach((plugin, i) => {
|
|
33
|
+
if (!plugin.active)
|
|
34
|
+
return;
|
|
35
|
+
if (plugin.process) {
|
|
36
|
+
if (plugin.process.connected) {
|
|
37
|
+
try {
|
|
38
|
+
plugin.process.send({ type, payload });
|
|
39
|
+
logger.debug(`Sent ${type} to child-process plugin <${plugin.name}> (#${i})`);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
logger.error(`Failed to send ${type} to plugin <${plugin.name}> (#${i}):`, err);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
logger.warn(`Plugin <${plugin.name}> (#${i}) is not connected. Skipping ${type}.`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
logger.debug(`Plugin <${plugin.name}> does not implement ${type}. Skipping.`);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Broadcast a new metric to all active plugins
|
|
56
|
+
*/
|
|
57
|
+
broadcastMetric(metric) {
|
|
58
|
+
this.broadcastToPlugins("newMetric", metric);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Broadcast a new log to all active plugins
|
|
62
|
+
*/
|
|
63
|
+
broadcastLog(log) {
|
|
64
|
+
this.broadcastToPlugins("newLog", log);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Broadcast a new trace to all active plugins
|
|
68
|
+
*/
|
|
69
|
+
broadcastTrace(trace) {
|
|
70
|
+
this.broadcastToPlugins("newTrace", trace);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
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
|
+
};
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import { globalOasTlmConfig } from '../config.js';
|
|
2
1
|
import { readFileSync } from 'fs';
|
|
3
2
|
import path from 'path';
|
|
4
3
|
import yaml from 'js-yaml';
|
|
5
4
|
import v8 from 'node:v8';
|
|
6
|
-
export const specLoader = (_req, res) => {
|
|
7
|
-
if (
|
|
5
|
+
export const specLoader = (_req, res, oasTlmConfig) => {
|
|
6
|
+
if (oasTlmConfig.general.specFileName) {
|
|
8
7
|
try {
|
|
9
|
-
const data = readFileSync(
|
|
10
|
-
const extension = path.extname(
|
|
8
|
+
const data = readFileSync(oasTlmConfig.general.specFileName, { encoding: 'utf8', flag: 'r' });
|
|
9
|
+
const extension = path.extname(oasTlmConfig.general.specFileName);
|
|
11
10
|
let json = data;
|
|
12
11
|
if (extension == "yaml")
|
|
13
12
|
//@ts-expect-error yes
|
|
@@ -16,17 +15,17 @@ export const specLoader = (_req, res) => {
|
|
|
16
15
|
res.send(json);
|
|
17
16
|
}
|
|
18
17
|
catch (e) {
|
|
19
|
-
console.error(`ERROR loading spec file ${
|
|
18
|
+
console.error(`ERROR loading spec file ${oasTlmConfig.general.specFileName}: ${e}`);
|
|
20
19
|
}
|
|
21
20
|
}
|
|
22
|
-
else if (
|
|
21
|
+
else if (oasTlmConfig.general.spec) {
|
|
23
22
|
let spec = null;
|
|
24
23
|
try {
|
|
25
|
-
spec = JSON.parse(
|
|
24
|
+
spec = JSON.parse(oasTlmConfig.general.spec);
|
|
26
25
|
}
|
|
27
26
|
catch (ej) {
|
|
28
27
|
try {
|
|
29
|
-
spec = JSON.stringify(yaml.load(
|
|
28
|
+
spec = JSON.stringify(yaml.load(oasTlmConfig.general.spec), null, 2);
|
|
30
29
|
}
|
|
31
30
|
catch (ey) {
|
|
32
31
|
console.error(`Error parsing spec: ${ej} - ${ey}`);
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import { Router } from 'express';
|
|
2
2
|
import { specLoader, heapStats } from './utilController.js';
|
|
3
|
-
export const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
});
|
|
17
|
-
|
|
3
|
+
export const getUtilsRoutes = (oasTlmConfig) => {
|
|
4
|
+
const router = Router();
|
|
5
|
+
router.get('/spec', (req, res) => specLoader(req, res, oasTlmConfig));
|
|
6
|
+
router.get('/heapStats', heapStats);
|
|
7
|
+
router.get('/generateLog', (req, res) => {
|
|
8
|
+
const log = req.query.log || 'Default log message';
|
|
9
|
+
console.log(log);
|
|
10
|
+
res.send({ message: 'Log generated', log: log });
|
|
11
|
+
});
|
|
12
|
+
router.get('/wait/:seconds?', async (req, res) => {
|
|
13
|
+
const seconds = parseInt(req.params.seconds ?? "1", 10);
|
|
14
|
+
const waitTime = isNaN(seconds) ? 1 : seconds;
|
|
15
|
+
await new Promise(resolve => setTimeout(resolve, waitTime * 1000));
|
|
16
|
+
res.send({ waited: waitTime });
|
|
17
|
+
});
|
|
18
|
+
return router;
|
|
19
|
+
};
|
package/dist/esm/types/index.js
CHANGED
package/dist/esm/utils/logger.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
dotenv.config();
|
|
1
|
+
import { bootEnvVariables } from "../config/bootConfig.js";
|
|
3
2
|
const LOG_LEVELS = ['DEBUG', 'INFO', 'WARN', 'ERROR', 'NONE'];
|
|
4
|
-
const currentLogLevel = (
|
|
5
|
-
const serviceName =
|
|
3
|
+
const currentLogLevel = (bootEnvVariables.OASTLM_BOOT_LOG_LEVEL || 'INFO').toUpperCase();
|
|
4
|
+
const serviceName = 'OAS-Telemetry';
|
|
6
5
|
function log(level, ...messages) {
|
|
7
6
|
if (LOG_LEVELS.indexOf(level) >= LOG_LEVELS.indexOf(currentLogLevel)) {
|
|
8
7
|
const timestamp = new Date().toISOString();
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const convertRegexRecursively = (obj) => {
|
|
2
|
+
if (Array.isArray(obj)) {
|
|
3
|
+
return obj.map(convertRegexRecursively);
|
|
4
|
+
}
|
|
5
|
+
else if (obj && typeof obj === 'object') {
|
|
6
|
+
const newObj = {};
|
|
7
|
+
for (const key of Object.keys(obj)) {
|
|
8
|
+
if (key === '$regex' && typeof obj[key] === 'string') {
|
|
9
|
+
try {
|
|
10
|
+
return new RegExp(obj[key]);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
throw new Error(`Invalid regex value "${obj[key]}"`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
newObj[key] = convertRegexRecursively(obj[key]);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return newObj;
|
|
21
|
+
}
|
|
22
|
+
return obj;
|
|
23
|
+
};
|