@oas-tools/oas-telemetry 0.6.2 → 0.7.0-alpha.1

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.
Files changed (125) hide show
  1. package/README.md +442 -442
  2. package/dist/{config.cjs → cjs/config.cjs} +6 -7
  3. package/dist/{exporters → cjs/exporters}/InMemoryDBMetricsExporter.cjs +5 -40
  4. package/dist/cjs/exporters/InMemoryDbExporter.cjs +87 -0
  5. package/dist/cjs/exporters/InMemoryLogRecordExporter.cjs +110 -0
  6. package/dist/{exporters → cjs/exporters}/consoleExporter.cjs +2 -7
  7. package/dist/{exporters → cjs/exporters}/dynamicExporter.cjs +12 -19
  8. package/dist/cjs/index.cjs +43 -0
  9. package/dist/cjs/instrumentation/index.cjs +28 -0
  10. package/dist/cjs/instrumentation/logs.cjs +46 -0
  11. package/dist/cjs/instrumentation/metrics.cjs +27 -0
  12. package/dist/cjs/instrumentation/traces.cjs +19 -0
  13. package/dist/cjs/tlm-ai/agent.cjs +79 -0
  14. package/dist/cjs/tlm-ai/aiController.cjs +69 -0
  15. package/dist/cjs/tlm-ai/aiRoutes.cjs +13 -0
  16. package/dist/cjs/tlm-ai/knownMicroservices.cjs +13 -0
  17. package/dist/cjs/tlm-ai/tools.cjs +504 -0
  18. package/dist/{routes/authRoutes.cjs → cjs/tlm-auth/authController.cjs} +21 -28
  19. package/dist/{middleware → cjs/tlm-auth}/authMiddleware.cjs +1 -1
  20. package/dist/cjs/tlm-auth/authRoutes.cjs +14 -0
  21. package/dist/cjs/tlm-log/logController.cjs +55 -0
  22. package/dist/cjs/tlm-log/logRoutes.cjs +13 -0
  23. package/dist/{routes → cjs/tlm-metric}/metricsRoutes.cjs +1 -2
  24. package/dist/{controllers → cjs/tlm-plugin}/pluginController.cjs +31 -41
  25. package/dist/cjs/tlm-plugin/pluginRoutes.cjs +13 -0
  26. package/dist/{controllers/telemetryController.cjs → cjs/tlm-trace/traceController.cjs} +8 -19
  27. package/dist/cjs/tlm-trace/traceRoutes.cjs +17 -0
  28. package/dist/cjs/tlm-ui/uiRoutes.cjs +31 -0
  29. package/dist/cjs/tlm-util/utilController.cjs +63 -0
  30. package/dist/cjs/tlm-util/utilRoutes.cjs +12 -0
  31. package/dist/cjs/tlmRoutes.cjs +79 -0
  32. package/dist/cjs/types/index.cjs +8 -0
  33. package/dist/cjs/utils/circular.cjs +90 -0
  34. package/dist/cjs/utils/logger.cjs +28 -0
  35. package/{src → dist/esm}/config.js +20 -23
  36. package/{src → dist/esm}/exporters/InMemoryDBMetricsExporter.js +57 -111
  37. package/dist/esm/exporters/InMemoryDbExporter.js +87 -0
  38. package/dist/esm/exporters/InMemoryLogRecordExporter.js +95 -0
  39. package/{src → dist/esm}/exporters/consoleExporter.js +38 -47
  40. package/{src → dist/esm}/exporters/dynamicExporter.js +50 -62
  41. package/dist/esm/index.js +39 -0
  42. package/dist/esm/instrumentation/index.js +26 -0
  43. package/dist/esm/instrumentation/logs.js +34 -0
  44. package/dist/esm/instrumentation/metrics.js +18 -0
  45. package/dist/esm/instrumentation/traces.js +12 -0
  46. package/dist/esm/tlm-ai/agent.js +68 -0
  47. package/dist/esm/tlm-ai/aiController.js +45 -0
  48. package/dist/esm/tlm-ai/aiRoutes.js +7 -0
  49. package/dist/esm/tlm-ai/knownMicroservices.js +5 -0
  50. package/dist/esm/tlm-ai/tools.js +490 -0
  51. package/dist/esm/tlm-auth/authController.js +41 -0
  52. package/{src/middleware → dist/esm/tlm-auth}/authMiddleware.js +12 -14
  53. package/dist/esm/tlm-auth/authRoutes.js +7 -0
  54. package/dist/esm/tlm-log/logController.js +36 -0
  55. package/dist/esm/tlm-log/logRoutes.js +7 -0
  56. package/{src/controllers → dist/esm/tlm-metric}/metricsController.js +28 -30
  57. package/{src/routes → dist/esm/tlm-metric}/metricsRoutes.js +8 -15
  58. package/{src/controllers → dist/esm/tlm-plugin}/pluginController.js +103 -115
  59. package/dist/esm/tlm-plugin/pluginRoutes.js +7 -0
  60. package/dist/esm/tlm-trace/traceController.js +54 -0
  61. package/dist/esm/tlm-trace/traceRoutes.js +11 -0
  62. package/dist/esm/tlm-ui/uiRoutes.js +23 -0
  63. package/dist/esm/tlm-util/utilController.js +57 -0
  64. package/dist/esm/tlm-util/utilRoutes.js +6 -0
  65. package/dist/esm/tlmRoutes.js +72 -0
  66. package/dist/esm/types/index.js +4 -0
  67. package/dist/esm/utils/circular.js +84 -0
  68. package/dist/esm/utils/logger.js +19 -0
  69. package/dist/types/config.d.ts +6 -0
  70. package/dist/types/exporters/InMemoryDBMetricsExporter.d.ts +15 -0
  71. package/dist/types/exporters/InMemoryDbExporter.d.ts +24 -0
  72. package/dist/types/exporters/InMemoryLogRecordExporter.d.ts +27 -0
  73. package/dist/types/exporters/consoleExporter.d.ts +13 -0
  74. package/dist/types/exporters/dynamicExporter.d.ts +25 -0
  75. package/dist/types/index.d.ts +8 -0
  76. package/dist/types/instrumentation/index.d.ts +1 -0
  77. package/dist/types/instrumentation/logs.d.ts +1 -0
  78. package/dist/types/instrumentation/metrics.d.ts +1 -0
  79. package/dist/types/instrumentation/traces.d.ts +1 -0
  80. package/dist/types/tlm-ai/agent.d.ts +1 -0
  81. package/dist/types/tlm-ai/aiController.d.ts +4 -0
  82. package/dist/types/tlm-ai/aiRoutes.d.ts +2 -0
  83. package/dist/types/tlm-ai/knownMicroservices.d.ts +6 -0
  84. package/dist/types/tlm-ai/tools.d.ts +45 -0
  85. package/dist/types/tlm-auth/authController.d.ts +4 -0
  86. package/dist/types/tlm-auth/authMiddleware.d.ts +2 -0
  87. package/dist/types/tlm-auth/authRoutes.d.ts +2 -0
  88. package/dist/types/tlm-log/logController.d.ts +4 -0
  89. package/dist/types/tlm-log/logRoutes.d.ts +2 -0
  90. package/dist/types/tlm-metric/metricsController.d.ts +4 -0
  91. package/dist/types/tlm-metric/metricsRoutes.d.ts +2 -0
  92. package/dist/types/tlm-plugin/pluginController.d.ts +3 -0
  93. package/dist/types/tlm-plugin/pluginRoutes.d.ts +2 -0
  94. package/dist/types/tlm-trace/traceController.d.ts +7 -0
  95. package/dist/types/tlm-trace/traceRoutes.d.ts +2 -0
  96. package/dist/types/tlm-ui/uiRoutes.d.ts +2 -0
  97. package/dist/types/tlm-util/utilController.d.ts +3 -0
  98. package/dist/types/tlm-util/utilRoutes.d.ts +2 -0
  99. package/dist/types/tlmRoutes.d.ts +2 -0
  100. package/dist/types/types/index.d.ts +56 -0
  101. package/dist/types/utils/circular.d.ts +31 -0
  102. package/dist/types/utils/logger.d.ts +9 -0
  103. package/dist/ui/assets/index-BNhZBPi2.css +1 -0
  104. package/dist/ui/assets/index-DxGAMrAl.js +401 -0
  105. package/dist/ui/index.html +14 -0
  106. package/dist/ui/vite.svg +1 -0
  107. package/package.json +80 -77
  108. package/dist/controllers/uiController.cjs +0 -78
  109. package/dist/exporters/InMemoryDbExporter.cjs +0 -178
  110. package/dist/index.cjs +0 -110
  111. package/dist/openTelemetry.cjs +0 -58
  112. package/dist/routes/telemetryRoutes.cjs +0 -31
  113. package/dist/services/uiService.cjs +0 -1520
  114. package/dist/systemMetrics.cjs +0 -97
  115. package/src/controllers/telemetryController.js +0 -69
  116. package/src/controllers/uiController.js +0 -69
  117. package/src/dev/ui/login.html +0 -32
  118. package/src/exporters/InMemoryDbExporter.js +0 -181
  119. package/src/index.js +0 -121
  120. package/src/openTelemetry.js +0 -58
  121. package/src/routes/authRoutes.js +0 -53
  122. package/src/routes/telemetryRoutes.js +0 -38
  123. package/src/services/uiService.js +0 -1520
  124. package/src/systemMetrics.js +0 -102
  125. /package/dist/{controllers → cjs/tlm-metric}/metricsController.cjs +0 -0
@@ -1,15 +1,8 @@
1
- import { Router } from 'express';
2
- import {
3
- listMetrics,
4
- findMetrics,
5
- resetMetrics
6
- } from '../controllers/metricsController.js';
7
-
8
- export const metricsRoutes = Router();
9
-
10
- // Metrics Control
11
- metricsRoutes.get('/', listMetrics);
12
- metricsRoutes.post('/find', findMetrics);
13
- metricsRoutes.get('/reset', resetMetrics);
14
-
15
- export default metricsRoutes;
1
+ import { Router } from 'express';
2
+ import { listMetrics, findMetrics, resetMetrics } from './metricsController.js';
3
+ export const metricsRoutes = Router();
4
+ // Metrics Control
5
+ metricsRoutes.get('/', listMetrics);
6
+ metricsRoutes.post('/find', findMetrics);
7
+ metricsRoutes.get('/reset', resetMetrics);
8
+ export default metricsRoutes;
@@ -1,115 +1,103 @@
1
-
2
- import { globalOasTlmConfig } from '../config.js';
3
- import axios from 'axios';
4
- import { importFromString, requireFromString } from 'import-from-string';
5
- import { installDependencies } from 'dynamic-installer';
6
-
7
- let dbglog = () => { };
8
-
9
- if (process.env.OTDEBUG == "true")
10
- dbglog = console.log;
11
- export const listPlugins = (req, res) => {
12
- res.send(globalOasTlmConfig.dynamicExporter.getPlugins().map((p) => {
13
- return {
14
- id: p.id,
15
- name: p.name,
16
- url: p.url,
17
- active: p.active
18
- };
19
- }));
20
- }
21
-
22
- export const registerPlugin = async (req, res) => {
23
- let pluginResource = req.body;
24
- dbglog(`Plugin Registration Request: = ${JSON.stringify(req.body, null, 2)}...`);
25
- dbglog(`Getting plugin at ${pluginResource.url}...`);
26
- let pluginCode;
27
- if (!pluginResource.url && !pluginResource.code) {
28
- res.status(400).send(`Plugin code or URL must be provided`);
29
- return;
30
- }
31
-
32
- let module;
33
- try {
34
- if (pluginResource.code) {
35
- pluginCode = pluginResource.code
36
- } else {
37
- const response = await axios.get(pluginResource.url);
38
- pluginCode = response.data;
39
- }
40
- if (!pluginCode) {
41
- res.status(400).send(`Plugin code could not be loaded`);
42
- return;
43
- }
44
- if (pluginResource.install) {
45
- const dependenciesStatus = await installDependencies(pluginResource.install);
46
- if (!dependenciesStatus.success) {
47
- if (pluginResource.install.ignoreErrors === true) {
48
- console.warn(`Warning: Error installing dependencies: ${JSON.stringify(dependenciesStatus.details)}`);
49
- } else {
50
- res.status(400).send(`Error installing dependencies: ${JSON.stringify(dependenciesStatus.details)}`);
51
- return;
52
- }
53
- }
54
- }
55
-
56
- dbglog("Plugin size: " + pluginCode?.length);
57
- dbglog("Plugin format: " + pluginResource?.moduleFormat);
58
- if (pluginResource?.moduleFormat && pluginResource.moduleFormat.toUpperCase() == "ESM") {
59
- console.log("ESM detected")
60
- module = await importFromString(pluginCode)
61
- } else {
62
- console.log("CJS detected (default)")
63
- module = await requireFromString(pluginCode)
64
- console.log(module)
65
- }
66
- } catch (error) {
67
- console.error(`Error loading plugin: ${error}`);
68
- res.status(400).send(`Error loading plugin: ${error}`);
69
- return;
70
- }
71
-
72
- const plugin = module.default?.plugin ?? module.plugin;
73
-
74
- if (plugin == undefined) {
75
- res.status(400).send(`Plugin code should export a "plugin" object`);
76
- console.log("Error in plugin code: no plugin object exported");
77
- return;
78
- }
79
- for (let requiredFunction of ["load", "getName", "isConfigured"]) {
80
- if (plugin[requiredFunction] == undefined) {
81
- res.status(400).send(`The plugin code exports a "plugin" object, however it should have a "${requiredFunction}" method`);
82
- console.log("Error in plugin code: some required functions are missing");
83
- return;
84
- }
85
- }
86
-
87
- try {
88
- await plugin.load(pluginResource.config);
89
- } catch (error) {
90
- console.error(`Error loading plugin configuration: ${error}`);
91
- res.status(400).send(`Error loading plugin configuration: ${error}`);
92
- return;
93
- }
94
- if (plugin.isConfigured()) {
95
- dbglog(`Loaded plugin <${plugin.getName()}>`);
96
- pluginResource.plugin = plugin;
97
- pluginResource.name = plugin.getName();
98
- pluginResource.active = true;
99
- globalOasTlmConfig.dynamicExporter.pushPlugin(pluginResource);
100
- globalOasTlmConfig.dynamicExporter.activatePlugin(pluginResource.plugin);
101
- res.status(201).send(`Plugin registered`);
102
- } else {
103
- console.error(`Plugin <${plugin.getName()}> can not be configured`);
104
- res.status(400).send(`Plugin configuration problem`);
105
- }
106
- }
107
-
108
- export const checkApiKey = (req, res) => {
109
- const apiKey = req.query.apiKey || req.body.apiKey;
110
- if (apiKey === process.env.APIKEY) {
111
- res.status(200).send({ valid: true });
112
- } else {
113
- res.status(401).send({ valid: false });
114
- }
115
- }
1
+ import { globalOasTlmConfig } from '../config.js';
2
+ import axios from 'axios';
3
+ // @ts-expect-error: import-from-string does not have proper type declarations
4
+ import { importFromString, requireFromString } from 'import-from-string';
5
+ // @ts-expect-error: dynamic-installer does not have proper type declarations
6
+ import { installDependencies } from 'dynamic-installer';
7
+ import logger from '../utils/logger.js';
8
+ export const listPlugins = (req, res) => {
9
+ res.send(globalOasTlmConfig.dynamicSpanExporter.getPlugins().map((plugin) => {
10
+ return {
11
+ id: plugin.id,
12
+ name: plugin.name,
13
+ url: plugin.url,
14
+ active: plugin.active
15
+ };
16
+ }));
17
+ };
18
+ 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
+ let pluginCode;
23
+ if (!pluginResource.url && !pluginResource.code) {
24
+ res.status(400).send(`Plugin code or URL must be provided`);
25
+ return;
26
+ }
27
+ let module;
28
+ try {
29
+ if (pluginResource.code) {
30
+ pluginCode = pluginResource.code;
31
+ }
32
+ else {
33
+ const response = await axios.get(pluginResource.url);
34
+ pluginCode = response.data;
35
+ }
36
+ if (!pluginCode) {
37
+ res.status(400).send(`Plugin code could not be loaded`);
38
+ return;
39
+ }
40
+ if (pluginResource.install) {
41
+ const dependenciesStatus = await installDependencies(pluginResource.install);
42
+ if (!dependenciesStatus.success) {
43
+ if (pluginResource.install.ignoreErrors === true) {
44
+ logger.warn(`Warning: Error installing dependencies: ${JSON.stringify(dependenciesStatus.details)}`);
45
+ }
46
+ else {
47
+ res.status(400).send(`Error installing dependencies: ${JSON.stringify(dependenciesStatus.details)}`);
48
+ return;
49
+ }
50
+ }
51
+ }
52
+ logger.info("Plugin size: " + pluginCode?.length);
53
+ logger.info("Plugin format: " + pluginResource?.moduleFormat);
54
+ if (pluginResource?.moduleFormat && pluginResource.moduleFormat.toUpperCase() == "ESM") {
55
+ logger.info("ESM detected");
56
+ module = await importFromString(pluginCode);
57
+ }
58
+ else {
59
+ logger.info("CJS detected (default)");
60
+ module = await requireFromString(pluginCode);
61
+ logger.info(module);
62
+ }
63
+ }
64
+ catch (error) {
65
+ logger.error(`Error loading plugin: ${error}`);
66
+ res.status(400).send(`Error loading plugin: ${error}`);
67
+ return;
68
+ }
69
+ const plugin = module.default?.plugin ?? module.plugin;
70
+ if (plugin == undefined) {
71
+ res.status(400).send(`Plugin code should export a "plugin" object`);
72
+ logger.info("Error in plugin code: no plugin object exported");
73
+ return;
74
+ }
75
+ for (const requiredFunction of ["load", "getName", "isConfigured"]) {
76
+ if (plugin[requiredFunction] == undefined) {
77
+ res.status(400).send(`The plugin code exports a "plugin" object, however it should have a "${requiredFunction}" method`);
78
+ logger.info("Error in plugin code: some required functions are missing");
79
+ return;
80
+ }
81
+ }
82
+ try {
83
+ await plugin.load(pluginResource.config);
84
+ }
85
+ catch (error) {
86
+ logger.error(`Error loading plugin configuration: ${error}`);
87
+ res.status(400).send(`Error loading plugin configuration: ${error}`);
88
+ return;
89
+ }
90
+ if (plugin.isConfigured()) {
91
+ logger.info(`Loaded plugin <${plugin.getName()}>`);
92
+ pluginResource.plugin = plugin;
93
+ pluginResource.name = plugin.getName();
94
+ pluginResource.active = true;
95
+ globalOasTlmConfig.dynamicSpanExporter.pushPlugin(pluginResource);
96
+ globalOasTlmConfig.dynamicSpanExporter.activatePlugin(pluginResource.plugin);
97
+ res.status(201).send(`Plugin registered`);
98
+ }
99
+ else {
100
+ logger.error(`Plugin <${plugin.getName()}> can not be configured`);
101
+ res.status(400).send(`Plugin configuration problem`);
102
+ }
103
+ };
@@ -0,0 +1,7 @@
1
+ import { Router } from 'express';
2
+ import { listPlugins, registerPlugin } from './pluginController.js';
3
+ export const pluginRoutes = Router();
4
+ // Plugins
5
+ pluginRoutes.get('/plugins', listPlugins);
6
+ pluginRoutes.post('/plugins', registerPlugin);
7
+ export default pluginRoutes;
@@ -0,0 +1,54 @@
1
+ import { globalOasTlmConfig } from '../config.js';
2
+ export const startTelemetry = (req, res) => {
3
+ globalOasTlmConfig.dynamicSpanExporter.exporter.start();
4
+ res.send('Telemetry started');
5
+ };
6
+ export const stopTelemetry = (req, res) => {
7
+ globalOasTlmConfig.dynamicSpanExporter.exporter.stop();
8
+ res.send('Telemetry stopped');
9
+ };
10
+ export const statusTelemetry = (req, res) => {
11
+ const isRunning = globalOasTlmConfig.dynamicSpanExporter.exporter.isRunning() || false;
12
+ res.send({ active: isRunning });
13
+ };
14
+ export const resetTelemetry = (req, res) => {
15
+ globalOasTlmConfig.dynamicSpanExporter.exporter.reset();
16
+ res.send('Telemetry reset');
17
+ };
18
+ export const listTelemetry = async (req, res) => {
19
+ try {
20
+ const spans = await globalOasTlmConfig.dynamicSpanExporter.exporter.getFinishedSpans();
21
+ res.send({ spansCount: spans.length, spans: spans });
22
+ }
23
+ catch (err) {
24
+ console.error(err);
25
+ res.status(500).send({ error: 'Failed to list telemetry data' });
26
+ }
27
+ };
28
+ export const findTelemetry = (req, res) => {
29
+ const body = req.body;
30
+ const search = body?.search ? body.search : {};
31
+ if (body?.flags?.containsRegex) {
32
+ try {
33
+ //@ts-expect-error yes
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
+ }
44
+ }
45
+ globalOasTlmConfig.dynamicSpanExporter.exporter.find(search, (err, docs) => {
46
+ if (err) {
47
+ console.error(err);
48
+ res.status(404).send({ spansCount: 0, spans: [], error: err });
49
+ return;
50
+ }
51
+ const spans = docs;
52
+ res.send({ spansCount: spans.length, spans: spans });
53
+ });
54
+ };
@@ -0,0 +1,11 @@
1
+ import { Router } from 'express';
2
+ import { startTelemetry, stopTelemetry, statusTelemetry, resetTelemetry, listTelemetry, findTelemetry } from './traceController.js';
3
+ export const traceRoutes = Router();
4
+ traceRoutes.get('/', listTelemetry);
5
+ traceRoutes.post('/find', findTelemetry);
6
+ // Telemetry Control
7
+ traceRoutes.get('/start', startTelemetry);
8
+ traceRoutes.get('/stop', stopTelemetry);
9
+ traceRoutes.get('/status', statusTelemetry);
10
+ traceRoutes.get('/reset', resetTelemetry);
11
+ export default traceRoutes;
@@ -0,0 +1,23 @@
1
+ import express, { Router } from 'express';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import logger from '../utils/logger.js';
5
+ let relativePath = '../../ui';
6
+ if (process.env.OASTLM_ENV === 'development') {
7
+ relativePath = '../../dist/ui';
8
+ 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/.');
9
+ }
10
+ const customFilename = fileURLToPath(import.meta.url);
11
+ const customDirname = path.dirname(customFilename);
12
+ const staticFilesPath = path.join(customDirname, relativePath);
13
+ export const uiRoutes = Router();
14
+ // This only works once the app is built: src/ --> dist/esm/
15
+ // This file: dist/esm/routes/
16
+ // UI bundle: dist/ui/
17
+ // For development, the UI is served separately.
18
+ uiRoutes.use(express.static(staticFilesPath));
19
+ uiRoutes.get('*', (_req, res) => {
20
+ // Serve the index.html file for all routes
21
+ res.sendFile(path.join(staticFilesPath, 'index.html'));
22
+ });
23
+ export default uiRoutes;
@@ -0,0 +1,57 @@
1
+ import { globalOasTlmConfig } from '../config.js';
2
+ import { readFileSync } from 'fs';
3
+ import path from 'path';
4
+ import yaml from 'js-yaml';
5
+ import v8 from 'node:v8';
6
+ export const specLoader = (_req, res) => {
7
+ if (globalOasTlmConfig.specFileName) {
8
+ try {
9
+ const data = readFileSync(globalOasTlmConfig.specFileName, { encoding: 'utf8', flag: 'r' });
10
+ const extension = path.extname(globalOasTlmConfig.specFileName);
11
+ let json = data;
12
+ if (extension == "yaml")
13
+ //@ts-expect-error yes
14
+ json = JSON.stringify(yaml.SafeLoad(data), null, 2);
15
+ res.setHeader('Content-Type', 'application/json');
16
+ res.send(json);
17
+ }
18
+ catch (e) {
19
+ console.error(`ERROR loading spec file ${globalOasTlmConfig.specFileName}: ${e}`);
20
+ }
21
+ }
22
+ else if (globalOasTlmConfig.spec) {
23
+ let spec = null;
24
+ try {
25
+ spec = JSON.parse(globalOasTlmConfig.spec);
26
+ }
27
+ catch (ej) {
28
+ try {
29
+ spec = JSON.stringify(yaml.load(globalOasTlmConfig.spec), null, 2);
30
+ }
31
+ catch (ey) {
32
+ console.error(`Error parsing spec: ${ej} - ${ey}`);
33
+ }
34
+ }
35
+ if (!spec) {
36
+ res.status(404);
37
+ }
38
+ else {
39
+ res.setHeader('Content-Type', 'application/json');
40
+ res.send(spec);
41
+ }
42
+ }
43
+ else {
44
+ res.status(404);
45
+ }
46
+ };
47
+ export const heapStats = (req, res) => {
48
+ const heapStats = v8.getHeapStatistics();
49
+ const roundedHeapStats = Object.getOwnPropertyNames(heapStats).reduce(function (map, stat) {
50
+ //@ts-expect-error yes
51
+ map[stat] = Math.round((heapStats[stat] / 1024 / 1024) * 1000) / 1000;
52
+ return map;
53
+ }, {});
54
+ // @ts-expect-error yes
55
+ roundedHeapStats['units'] = 'MB';
56
+ res.send(roundedHeapStats);
57
+ };
@@ -0,0 +1,6 @@
1
+ import { Router } from 'express';
2
+ import { specLoader, heapStats } from './utilController.js';
3
+ export const utilsRoutes = Router();
4
+ utilsRoutes.get('/spec', specLoader);
5
+ utilsRoutes.get('/heapStats', heapStats);
6
+ export default utilsRoutes;
@@ -0,0 +1,72 @@
1
+ import { json } from "express";
2
+ import logger from "./utils/logger.js";
3
+ import cors from 'cors';
4
+ import { globalOasTlmConfig } from "./config.js";
5
+ import metricsRoutes from "./tlm-metric/metricsRoutes.js";
6
+ import cookieParser from 'cookie-parser';
7
+ import authRoutes from './tlm-auth/authRoutes.js';
8
+ import uiRoutes from './tlm-ui/uiRoutes.js';
9
+ import traceRoutes from "./tlm-trace/traceRoutes.js";
10
+ import { authMiddleware } from "./tlm-auth/authMiddleware.js";
11
+ import utilsRoutes from "./tlm-util/utilRoutes.js";
12
+ import logRoutes from './tlm-log/logRoutes.js';
13
+ import aiRoutes from "./tlm-ai/aiRoutes.js";
14
+ export const configureRoutes = (router) => {
15
+ if (process.env.OASTLM_ENV === 'development') {
16
+ logger.info("Running in development mode, enabling CORS for all origins");
17
+ router.use(cors({
18
+ origin: '*', // Permitir todas las solicitudes en desarrollo
19
+ methods: ['GET', 'POST', 'PUT', 'DELETE'],
20
+ allowedHeaders: ['Content-Type', 'Authorization'],
21
+ }));
22
+ }
23
+ router.use((req, res, next) => {
24
+ if (req.body !== undefined) {
25
+ return next(); // Already parsed, no need to parse again.
26
+ }
27
+ return json()(req, res, next);
28
+ });
29
+ const allAuthMiddlewares = getWrappedMiddlewares(() => globalOasTlmConfig.authEnabled, [cookieParser(), authRoutes, authMiddleware]);
30
+ const baseURL = globalOasTlmConfig.baseURL;
31
+ router.use(baseURL, allAuthMiddlewares);
32
+ // WARNING: This path must be the same as the one used in the UI package App.tsx "oas-telemetry-ui"
33
+ router.use(baseURL + "/traces", traceRoutes);
34
+ router.use(baseURL + "/metrics", metricsRoutes);
35
+ router.use(baseURL + "/logs", logRoutes);
36
+ router.use(baseURL + "/ai", getWrappedMiddlewares(() => process.env.OASTLM_AI_OPENAI_API_KEY !== null && process.env.OASTLM_AI_OPENAI_API_KEY !== "", [aiRoutes]));
37
+ router.use(baseURL + "/oas-telemetry-ui", uiRoutes);
38
+ router.use(baseURL + "/utils", utilsRoutes);
39
+ //redirect to the UI when accessing the base URL
40
+ router.get(baseURL, (req, res) => {
41
+ res.redirect(baseURL + "/oas-telemetry-ui");
42
+ });
43
+ };
44
+ /**
45
+ * This function wraps the provided middleware functions with a condition callback.
46
+ * If the condition callback returns true, the middleware/router will be executed.
47
+ * If the condition callback returns false, the middleware/router will be skipped.
48
+ *
49
+ * @callback {function} conditionCallback A callback function that returns a boolean to determine if the middleware should be used.
50
+ * @param {Array} middlewares An array of middleware or routers to be wrapped.
51
+ * @returns {Array} An array of wrapped middleware functions.
52
+ */
53
+ function getWrappedMiddlewares(conditionCallback, middlewares) {
54
+ return middlewares.map(middleware => {
55
+ return function (req, res, next) {
56
+ if (conditionCallback()) {
57
+ if (typeof middleware === 'function') {
58
+ // look for handle property, if it exists, it's a router. If not call middleware
59
+ if (middleware.handle) {
60
+ middleware.handle(req, res, next);
61
+ }
62
+ else {
63
+ middleware(req, res, next);
64
+ }
65
+ }
66
+ }
67
+ else {
68
+ next();
69
+ }
70
+ };
71
+ });
72
+ }
@@ -0,0 +1,4 @@
1
+ ;
2
+ ;
3
+ ;
4
+ export {};
@@ -0,0 +1,84 @@
1
+ export function removeCircularRefs(obj) {
2
+ // const seen = new WeakMap(); // Used to keep track of visited objects
3
+ // Replacer function to handle circular references
4
+ function replacer(key, value) {
5
+ if (key === "_spanProcessor") {
6
+ return "oas-telemetry skips this field to avoid circular reference";
7
+ }
8
+ // GENERIC CIRCULAR REFERENCE HANDLING
9
+ // if (typeof value === "object" && value !== null) {
10
+ // // If the object has been visited before, return the name prefixed with "CIRCULAR+"
11
+ // if (seen.has(value)) {
12
+ // return `CIRCULAR${key}`;
13
+ // }
14
+ // seen.set(value, key); // Mark the object as visited with its name
15
+ // }
16
+ return value;
17
+ }
18
+ // Convert the object to a string and then parse it back
19
+ // This will trigger the replacer function to handle circular references
20
+ const jsonString = JSON.stringify(obj, replacer);
21
+ return JSON.parse(jsonString);
22
+ }
23
+ /**
24
+ * Recursively converts dot-separated keys in an object to nested objects.
25
+ *
26
+ * @param {any} obj - The object to process.
27
+ * @returns {any} - The object with all dot-separated keys converted to nested objects.
28
+ * @example
29
+ * // Input:
30
+ * // {
31
+ * // "http.method": "GET",
32
+ * // "http.url": "http://example.com",
33
+ * // "nested.obj.key": "value"
34
+ * // }
35
+ * // Output:
36
+ * // {
37
+ * // "http": {
38
+ * // "method": "GET",
39
+ * // "url": "http://example.com"
40
+ * // },
41
+ * // "nested": {
42
+ * // "obj": {
43
+ * // "key": "value"
44
+ * // }
45
+ * // }
46
+ * // }
47
+ */
48
+ export function convertToNestedObject(obj) {
49
+ const result = {};
50
+ for (const key in obj) {
51
+ const keys = key.split('.');
52
+ let temp = result;
53
+ for (let i = 0; i < keys.length; i++) {
54
+ const currentKey = keys[i];
55
+ if (i === keys.length - 1) {
56
+ // Last key, set the value
57
+ temp[currentKey] = obj[key];
58
+ }
59
+ else {
60
+ // Intermediate key, ensure the object exists
61
+ if (!temp[currentKey]) {
62
+ temp[currentKey] = {};
63
+ }
64
+ temp = temp[currentKey];
65
+ }
66
+ }
67
+ }
68
+ return result;
69
+ }
70
+ /**
71
+ * Applies nesting to all dot-separated keys within an object.
72
+ */
73
+ export function applyNesting(obj) {
74
+ for (const key in obj) {
75
+ const value = obj[key];
76
+ if (Array.isArray(value)) {
77
+ obj[key] = value.map(item => typeof item === 'object' && item !== null ? applyNesting(item) : item);
78
+ }
79
+ else if (typeof value === 'object' && value !== null) {
80
+ obj[key] = applyNesting(value);
81
+ }
82
+ }
83
+ return convertToNestedObject(obj);
84
+ }
@@ -0,0 +1,19 @@
1
+ import dotenv from 'dotenv';
2
+ dotenv.config();
3
+ const LOG_LEVELS = ['DEBUG', 'INFO', 'WARN', 'ERROR', 'NONE'];
4
+ const currentLogLevel = (process.env.OASTLM_LOG_LEVEL || 'INFO').toUpperCase();
5
+ const serviceName = process.env.OASTLM_SERVICE_NAME || 'OAS-TLM';
6
+ function log(level, ...messages) {
7
+ if (LOG_LEVELS.indexOf(level) >= LOG_LEVELS.indexOf(currentLogLevel)) {
8
+ const timestamp = new Date().toISOString();
9
+ console.log(`${timestamp} [${serviceName}] [${level}]:`, ...messages);
10
+ }
11
+ }
12
+ export default {
13
+ debug: (...messages) => log('DEBUG', ...messages),
14
+ info: (...messages) => log('INFO', ...messages),
15
+ log: (...messages) => log('INFO', ...messages), // Alias for info
16
+ warn: (...messages) => log('WARN', ...messages),
17
+ error: (...messages) => log('ERROR', ...messages),
18
+ currentLogLevel
19
+ };
@@ -0,0 +1,6 @@
1
+ import { type GlobalOasTlmConfig } from "./types/index.js";
2
+ export declare const globalOasTlmConfig: GlobalOasTlmConfig;
3
+ declare const _default: {
4
+ globalOasTlmConfig: GlobalOasTlmConfig;
5
+ };
6
+ export default _default;
@@ -0,0 +1,15 @@
1
+ import { ResourceMetrics } from '@opentelemetry/sdk-metrics';
2
+ export declare class InMemoryDBMetricsExporter {
3
+ private _metrics;
4
+ private _stopped;
5
+ constructor();
6
+ export(metrics: ResourceMetrics, resultCallback: any): any;
7
+ start(): void;
8
+ stop(): void;
9
+ isRunning(): boolean;
10
+ shutdown(): Promise<void>;
11
+ forceFlush(): Promise<void>;
12
+ find(search: any, callback: any): void;
13
+ reset(): void;
14
+ getFinishedMetrics(): import("@seald-io/nedb").Document<Record<string, any>>[];
15
+ }
@@ -0,0 +1,24 @@
1
+ import { ExportResultCode } from '@opentelemetry/core';
2
+ import { ReadableSpan } from '@opentelemetry/sdk-trace-base';
3
+ import { OasTlmExporter, PluginResource } from '../types/index.js';
4
+ export declare class InMemoryExporter implements OasTlmExporter {
5
+ private _spans;
6
+ private _stopped;
7
+ constructor();
8
+ plugins: PluginResource[];
9
+ export(readableSpans: ReadableSpan[], resultCallback: (arg0: {
10
+ code: ExportResultCode;
11
+ error?: Error;
12
+ }) => void): void;
13
+ start(): void;
14
+ stop(): void;
15
+ isRunning(): boolean;
16
+ shutdown(): Promise<void>;
17
+ /**
18
+ * Exports any pending spans in the exporter
19
+ */
20
+ forceFlush(): Promise<void>;
21
+ find(search: any, callback: any): void;
22
+ reset(): void;
23
+ getFinishedSpans(): import("@seald-io/nedb").Document<Record<string, any>>[];
24
+ }