@oas-tools/oas-telemetry 0.7.0-alpha.2 → 0.7.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/.env.example +50 -17
  2. package/README.md +242 -240
  3. package/dist/cjs/config/bootConfig.cjs +18 -0
  4. package/dist/cjs/config/config.cjs +145 -0
  5. package/dist/cjs/config/config.types.cjs +5 -0
  6. package/dist/cjs/index.cjs +19 -25
  7. package/dist/cjs/{tlmRoutes.cjs → routesManager.cjs} +28 -21
  8. package/dist/cjs/{exporters/InMemoryLogRecordExporter.cjs → telemetry/custom-implementations/exporters/InMemoryDbLogExporter.cjs} +42 -19
  9. package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.cjs +97 -0
  10. package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.cjs +118 -0
  11. package/dist/cjs/telemetry/custom-implementations/exporters/PluginLogExporter.cjs +52 -0
  12. package/dist/cjs/telemetry/custom-implementations/exporters/PluginMetricExporter.cjs +53 -0
  13. package/dist/cjs/telemetry/custom-implementations/exporters/PluginSpanExporter.cjs +69 -0
  14. package/dist/cjs/telemetry/custom-implementations/processors/dynamicMultiLogProcessor.cjs +70 -0
  15. package/dist/cjs/telemetry/custom-implementations/processors/dynamicMultiSpanProcessor.cjs +70 -0
  16. package/dist/cjs/{utils → telemetry/custom-implementations/utils}/circular.cjs +39 -49
  17. package/dist/cjs/telemetry/custom-implementations/wrappers.cjs +175 -0
  18. package/dist/cjs/telemetry/initializeTelemetry.cjs +74 -0
  19. package/dist/cjs/telemetry/telemetryConfigurator.cjs +84 -0
  20. package/dist/cjs/telemetry/telemetryRegistry.cjs +40 -0
  21. package/dist/cjs/tlm-ai/agent.cjs +82 -63
  22. package/dist/cjs/tlm-ai/aiController.cjs +5 -4
  23. package/dist/cjs/tlm-ai/aiRoutes.cjs +9 -6
  24. package/dist/cjs/tlm-ai/tools.cjs +16 -9
  25. package/dist/cjs/tlm-auth/authController.cjs +14 -15
  26. package/dist/cjs/tlm-auth/authMiddleware.cjs +11 -10
  27. package/dist/cjs/tlm-auth/authRoutes.cjs +9 -7
  28. package/dist/cjs/tlm-log/logController.cjs +45 -18
  29. package/dist/cjs/tlm-log/logRoutes.cjs +16 -11
  30. package/dist/cjs/tlm-metric/metricsController.cjs +37 -12
  31. package/dist/cjs/tlm-metric/metricsRoutes.cjs +16 -11
  32. package/dist/cjs/tlm-plugin/pluginController.cjs +40 -19
  33. package/dist/cjs/tlm-plugin/pluginRoutes.cjs +8 -6
  34. package/dist/cjs/tlm-plugin/pluginService.cjs +25 -0
  35. package/dist/cjs/tlm-trace/traceController.cjs +54 -45
  36. package/dist/cjs/tlm-trace/traceRoutes.cjs +16 -11
  37. package/dist/cjs/tlm-ui/uiRoutes.cjs +26 -20
  38. package/dist/cjs/tlm-util/utilController.cjs +8 -9
  39. package/dist/cjs/tlm-util/utilRoutes.cjs +22 -19
  40. package/dist/cjs/types/index.cjs +0 -1
  41. package/dist/cjs/utils/logger.cjs +3 -5
  42. package/dist/cjs/utils/regexUtils.cjs +27 -0
  43. package/dist/esm/config/bootConfig.js +11 -0
  44. package/dist/esm/config/config.js +126 -0
  45. package/dist/esm/index.js +18 -29
  46. package/dist/esm/{tlmRoutes.js → routesManager.js} +27 -22
  47. package/dist/esm/{exporters/InMemoryLogRecordExporter.js → telemetry/custom-implementations/exporters/InMemoryDbLogExporter.js} +31 -17
  48. package/dist/esm/{exporters/InMemoryDBMetricsExporter.js → telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.js} +31 -17
  49. package/dist/esm/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.js +105 -0
  50. package/dist/esm/telemetry/custom-implementations/exporters/PluginLogExporter.js +44 -0
  51. package/dist/esm/telemetry/custom-implementations/exporters/PluginMetricExporter.js +43 -0
  52. package/dist/esm/telemetry/custom-implementations/exporters/PluginSpanExporter.js +61 -0
  53. package/dist/esm/telemetry/custom-implementations/processors/dynamicMultiLogProcessor.js +64 -0
  54. package/dist/esm/telemetry/custom-implementations/processors/dynamicMultiSpanProcessor.js +64 -0
  55. package/dist/esm/telemetry/custom-implementations/utils/circular.js +76 -0
  56. package/dist/esm/telemetry/custom-implementations/wrappers.js +163 -0
  57. package/dist/esm/telemetry/initializeTelemetry.js +71 -0
  58. package/dist/esm/telemetry/telemetryConfigurator.js +74 -0
  59. package/dist/esm/telemetry/telemetryRegistry.js +34 -0
  60. package/dist/esm/tlm-ai/agent.js +77 -59
  61. package/dist/esm/tlm-ai/aiController.js +5 -4
  62. package/dist/esm/tlm-ai/aiRoutes.js +7 -5
  63. package/dist/esm/tlm-ai/tools.js +18 -9
  64. package/dist/esm/tlm-auth/authController.js +9 -10
  65. package/dist/esm/tlm-auth/authMiddleware.js +10 -9
  66. package/dist/esm/tlm-auth/authRoutes.js +8 -6
  67. package/dist/esm/tlm-log/logController.js +36 -16
  68. package/dist/esm/tlm-log/logRoutes.js +15 -11
  69. package/dist/esm/tlm-metric/metricsController.js +29 -10
  70. package/dist/esm/tlm-metric/metricsRoutes.js +15 -11
  71. package/dist/esm/tlm-plugin/pluginController.js +40 -19
  72. package/dist/esm/tlm-plugin/pluginRoutes.js +6 -5
  73. package/dist/esm/tlm-plugin/pluginService.js +19 -0
  74. package/dist/esm/tlm-trace/traceController.js +40 -35
  75. package/dist/esm/tlm-trace/traceRoutes.js +15 -11
  76. package/dist/esm/tlm-ui/uiRoutes.js +24 -19
  77. package/dist/esm/tlm-util/utilController.js +8 -9
  78. package/dist/esm/tlm-util/utilRoutes.js +17 -15
  79. package/dist/esm/types/index.js +0 -1
  80. package/dist/esm/utils/logger.js +3 -4
  81. package/dist/esm/utils/regexUtils.js +23 -0
  82. package/dist/types/config/bootConfig.d.ts +5 -0
  83. package/dist/types/config/config.d.ts +253 -0
  84. package/dist/types/config/config.types.d.ts +34 -0
  85. package/dist/types/index.d.ts +5 -4
  86. package/dist/types/routesManager.d.ts +3 -0
  87. package/dist/types/{exporters/InMemoryLogRecordExporter.d.ts → telemetry/custom-implementations/exporters/InMemoryDbLogExporter.d.ts} +6 -6
  88. package/dist/types/{exporters/InMemoryDBMetricsExporter.d.ts → telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.d.ts} +7 -7
  89. package/dist/types/{exporters/InMemoryDbExporter.d.ts → telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.d.ts} +9 -9
  90. package/dist/types/telemetry/custom-implementations/exporters/PluginLogExporter.d.ts +8 -0
  91. package/dist/types/telemetry/custom-implementations/exporters/PluginMetricExporter.d.ts +12 -0
  92. package/dist/types/telemetry/custom-implementations/exporters/PluginSpanExporter.d.ts +14 -0
  93. package/dist/types/telemetry/custom-implementations/processors/dynamicMultiLogProcessor.d.ts +32 -0
  94. package/dist/types/telemetry/custom-implementations/processors/dynamicMultiSpanProcessor.d.ts +34 -0
  95. package/dist/types/telemetry/custom-implementations/utils/circular.d.ts +27 -0
  96. package/dist/types/telemetry/custom-implementations/wrappers.d.ts +52 -0
  97. package/dist/types/telemetry/initializeTelemetry.d.ts +1 -0
  98. package/dist/types/telemetry/telemetryConfigurator.d.ts +2 -0
  99. package/dist/types/telemetry/telemetryRegistry.d.ts +20 -0
  100. package/dist/types/tlm-ai/agent.d.ts +2 -1
  101. package/dist/types/tlm-ai/aiController.d.ts +4 -3
  102. package/dist/types/tlm-ai/aiRoutes.d.ts +2 -2
  103. package/dist/types/tlm-ai/tools.d.ts +3 -1
  104. package/dist/types/tlm-auth/authController.d.ts +4 -3
  105. package/dist/types/tlm-auth/authMiddleware.d.ts +2 -1
  106. package/dist/types/tlm-auth/authRoutes.d.ts +2 -2
  107. package/dist/types/tlm-log/logController.d.ts +1 -0
  108. package/dist/types/tlm-log/logRoutes.d.ts +2 -2
  109. package/dist/types/tlm-metric/metricsController.d.ts +1 -0
  110. package/dist/types/tlm-metric/metricsRoutes.d.ts +2 -2
  111. package/dist/types/tlm-plugin/pluginRoutes.d.ts +1 -2
  112. package/dist/types/tlm-plugin/pluginService.d.ts +9 -0
  113. package/dist/types/tlm-trace/traceController.d.ts +7 -6
  114. package/dist/types/tlm-trace/traceRoutes.d.ts +2 -2
  115. package/dist/types/tlm-ui/uiRoutes.d.ts +1 -2
  116. package/dist/types/tlm-util/utilController.d.ts +2 -1
  117. package/dist/types/tlm-util/utilRoutes.d.ts +2 -2
  118. package/dist/types/types/index.d.ts +7 -46
  119. package/dist/types/utils/regexUtils.d.ts +1 -0
  120. package/dist/ui/assets/index-D9HsRlaQ.js +437 -0
  121. package/dist/ui/assets/index-DEyIcKBi.css +1 -0
  122. package/dist/ui/index.html +3 -3
  123. package/dist/ui/oas-tlm.svg +185 -0
  124. package/package.json +12 -7
  125. package/dist/cjs/config.cjs +0 -31
  126. package/dist/cjs/exporters/InMemoryDBMetricsExporter.cjs +0 -74
  127. package/dist/cjs/exporters/InMemoryDbExporter.cjs +0 -102
  128. package/dist/cjs/exporters/consoleExporter.cjs +0 -47
  129. package/dist/cjs/exporters/dynamicExporter.cjs +0 -57
  130. package/dist/cjs/instrumentation/index.cjs +0 -28
  131. package/dist/cjs/instrumentation/logs.cjs +0 -46
  132. package/dist/cjs/instrumentation/metrics.cjs +0 -27
  133. package/dist/cjs/instrumentation/traces.cjs +0 -19
  134. package/dist/esm/config.js +0 -20
  135. package/dist/esm/exporters/InMemoryDbExporter.js +0 -102
  136. package/dist/esm/exporters/consoleExporter.js +0 -38
  137. package/dist/esm/exporters/dynamicExporter.js +0 -50
  138. package/dist/esm/instrumentation/index.js +0 -26
  139. package/dist/esm/instrumentation/logs.js +0 -34
  140. package/dist/esm/instrumentation/metrics.js +0 -18
  141. package/dist/esm/instrumentation/traces.js +0 -12
  142. package/dist/esm/utils/circular.js +0 -84
  143. package/dist/types/config.d.ts +0 -6
  144. package/dist/types/exporters/consoleExporter.d.ts +0 -13
  145. package/dist/types/exporters/dynamicExporter.d.ts +0 -25
  146. package/dist/types/instrumentation/logs.d.ts +0 -1
  147. package/dist/types/instrumentation/metrics.d.ts +0 -1
  148. package/dist/types/instrumentation/traces.d.ts +0 -1
  149. package/dist/types/tlmRoutes.d.ts +0 -2
  150. package/dist/types/utils/circular.d.ts +0 -31
  151. package/dist/ui/assets/index-BNhZBPi2.css +0 -1
  152. package/dist/ui/assets/index-DxGAMrAl.js +0 -401
  153. package/dist/ui/vite.svg +0 -1
  154. /package/dist/{types/instrumentation/index.d.ts → esm/config/config.types.js} +0 -0
@@ -3,16 +3,21 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.traceRoutes = exports.default = void 0;
6
+ exports.getTraceRoutes = exports.default = void 0;
7
7
  var _express = require("express");
8
8
  var _traceController = require("./traceController.cjs");
9
- const traceRoutes = exports.traceRoutes = (0, _express.Router)();
10
- traceRoutes.get('/', _traceController.listTelemetry);
11
- traceRoutes.post('/', _traceController.insertTracesToDb);
12
- traceRoutes.post('/find', _traceController.findTelemetry);
13
- // Telemetry Control
14
- traceRoutes.get('/start', _traceController.startTelemetry);
15
- traceRoutes.get('/stop', _traceController.stopTelemetry);
16
- traceRoutes.get('/status', _traceController.statusTelemetry);
17
- traceRoutes.get('/reset', _traceController.resetTelemetry);
18
- var _default = exports.default = traceRoutes;
9
+ const getTraceRoutes = () => {
10
+ const router = (0, _express.Router)();
11
+ // Telemetry Control
12
+ router.post('/start', _traceController.startTraces);
13
+ router.post('/stop', _traceController.stopTraces);
14
+ router.get('/status', _traceController.statusTraces);
15
+ router.post('/reset', _traceController.resetTraces);
16
+ router.get('/', _traceController.listTraces);
17
+ router.post('/', _traceController.insertTracesToDb);
18
+ router.post('/find', _traceController.findTraces);
19
+ router.post('/retention-time', _traceController.setRetentionTimeTraces);
20
+ return router;
21
+ };
22
+ exports.getTraceRoutes = getTraceRoutes;
23
+ var _default = exports.default = getTraceRoutes;
@@ -3,29 +3,35 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.uiRoutes = exports.default = void 0;
6
+ exports.getUIRoutes = void 0;
7
7
  var _express = _interopRequireWildcard(require("express"));
8
8
  var _path = _interopRequireDefault(require("path"));
9
9
  var _url = require("url");
10
10
  var _logger = _interopRequireDefault(require("../utils/logger.cjs"));
11
+ var _bootConfig = require("../config/bootConfig.cjs");
11
12
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
13
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
13
- let relativePath = '../../ui';
14
- if (process.env.OASTLM_ENV === 'development') {
15
- relativePath = '../../dist/ui';
16
- _logger.default.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/.');
17
- }
18
- const customFilename = (0, _url.fileURLToPath)(require('url').pathToFileURL(__filename).toString());
19
- const customDirname = _path.default.dirname(customFilename);
20
- const staticFilesPath = _path.default.join(customDirname, relativePath);
21
- const uiRoutes = exports.uiRoutes = (0, _express.Router)();
22
- // This only works once the app is built: src/ --> dist/esm/
23
- // This file: dist/esm/routes/
24
- // UI bundle: dist/ui/
25
- // For development, the UI is served separately.
26
- uiRoutes.use(_express.default.static(staticFilesPath));
27
- uiRoutes.get('*', (_req, res) => {
28
- // Serve the index.html file for all routes
29
- res.sendFile(_path.default.join(staticFilesPath, 'index.html'));
30
- });
31
- var _default = exports.default = uiRoutes;
14
+ const getUIRoutes = () => {
15
+ // This is when this file is in /dist
16
+ let relativePath = '../../ui';
17
+ // This is when this file in in /src
18
+ if (_bootConfig.bootEnvVariables.OASTLM_BOOT_ENV === 'development') {
19
+ relativePath = '../../dist/ui';
20
+ _logger.default.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/.');
21
+ }
22
+ const customFilename = (0, _url.fileURLToPath)(require('url').pathToFileURL(__filename).toString());
23
+ const customDirname = _path.default.dirname(customFilename);
24
+ const staticFilesPath = _path.default.join(customDirname, relativePath);
25
+ const router = (0, _express.Router)();
26
+ // This only works once the app is built: src/ --> dist/esm/
27
+ // This file: dist/esm/routes/
28
+ // UI bundle: dist/ui/
29
+ // For development, the UI is served separately.
30
+ router.use(_express.default.static(staticFilesPath));
31
+ router.get('*', (_req, res) => {
32
+ // Serve the index.html file for all routes
33
+ res.sendFile(_path.default.join(staticFilesPath, 'index.html'));
34
+ });
35
+ return router;
36
+ };
37
+ exports.getUIRoutes = getUIRoutes;
@@ -4,20 +4,19 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.specLoader = exports.heapStats = void 0;
7
- var _config = require("../config.cjs");
8
7
  var _fs = require("fs");
9
8
  var _path = _interopRequireDefault(require("path"));
10
9
  var _jsYaml = _interopRequireDefault(require("js-yaml"));
11
10
  var _nodeV = _interopRequireDefault(require("node:v8"));
12
11
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
- const specLoader = (_req, res) => {
14
- if (_config.globalOasTlmConfig.specFileName) {
12
+ const specLoader = (_req, res, oasTlmConfig) => {
13
+ if (oasTlmConfig.general.specFileName) {
15
14
  try {
16
- const data = (0, _fs.readFileSync)(_config.globalOasTlmConfig.specFileName, {
15
+ const data = (0, _fs.readFileSync)(oasTlmConfig.general.specFileName, {
17
16
  encoding: 'utf8',
18
17
  flag: 'r'
19
18
  });
20
- const extension = _path.default.extname(_config.globalOasTlmConfig.specFileName);
19
+ const extension = _path.default.extname(oasTlmConfig.general.specFileName);
21
20
  let json = data;
22
21
  if (extension == "yaml")
23
22
  //@ts-expect-error yes
@@ -25,15 +24,15 @@ const specLoader = (_req, res) => {
25
24
  res.setHeader('Content-Type', 'application/json');
26
25
  res.send(json);
27
26
  } catch (e) {
28
- console.error(`ERROR loading spec file ${_config.globalOasTlmConfig.specFileName}: ${e}`);
27
+ console.error(`ERROR loading spec file ${oasTlmConfig.general.specFileName}: ${e}`);
29
28
  }
30
- } else if (_config.globalOasTlmConfig.spec) {
29
+ } else if (oasTlmConfig.general.spec) {
31
30
  let spec = null;
32
31
  try {
33
- spec = JSON.parse(_config.globalOasTlmConfig.spec);
32
+ spec = JSON.parse(oasTlmConfig.general.spec);
34
33
  } catch (ej) {
35
34
  try {
36
- spec = JSON.stringify(_jsYaml.default.load(_config.globalOasTlmConfig.spec), null, 2);
35
+ spec = JSON.stringify(_jsYaml.default.load(oasTlmConfig.general.spec), null, 2);
37
36
  } catch (ey) {
38
37
  console.error(`Error parsing spec: ${ej} - ${ey}`);
39
38
  }
@@ -3,26 +3,29 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.utilsRoutes = exports.default = void 0;
6
+ exports.getUtilsRoutes = void 0;
7
7
  var _express = require("express");
8
8
  var _utilController = require("./utilController.cjs");
9
- const utilsRoutes = exports.utilsRoutes = (0, _express.Router)();
10
- utilsRoutes.get('/spec', _utilController.specLoader);
11
- utilsRoutes.get('/heapStats', _utilController.heapStats);
12
- utilsRoutes.get('/generateLog', (req, res) => {
13
- const log = req.query.log || 'Default log message';
14
- console.log('Generated log:', log);
15
- res.send({
16
- message: 'Log generated',
17
- log: log
9
+ const getUtilsRoutes = oasTlmConfig => {
10
+ const router = (0, _express.Router)();
11
+ router.get('/spec', (req, res) => (0, _utilController.specLoader)(req, res, oasTlmConfig));
12
+ router.get('/heapStats', _utilController.heapStats);
13
+ router.get('/generateLog', (req, res) => {
14
+ const log = req.query.log || 'Default log message';
15
+ console.log(log);
16
+ res.send({
17
+ message: 'Log generated',
18
+ log: log
19
+ });
18
20
  });
19
- });
20
- utilsRoutes.get('/wait/:seconds?', async (req, res) => {
21
- const seconds = parseInt(req.params.seconds ?? "1", 10);
22
- const waitTime = isNaN(seconds) ? 1 : seconds;
23
- await new Promise(resolve => setTimeout(resolve, waitTime * 1000));
24
- res.send({
25
- waited: waitTime
21
+ router.get('/wait/:seconds?', async (req, res) => {
22
+ const seconds = parseInt(req.params.seconds ?? "1", 10);
23
+ const waitTime = isNaN(seconds) ? 1 : seconds;
24
+ await new Promise(resolve => setTimeout(resolve, waitTime * 1000));
25
+ res.send({
26
+ waited: waitTime
27
+ });
26
28
  });
27
- });
28
- var _default = exports.default = utilsRoutes;
29
+ return router;
30
+ };
31
+ exports.getUtilsRoutes = getUtilsRoutes;
@@ -4,5 +4,4 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  ;
7
- ;
8
7
  ;
@@ -4,12 +4,10 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _dotenv = _interopRequireDefault(require("dotenv"));
8
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
- _dotenv.default.config();
7
+ var _bootConfig = require("../config/bootConfig.cjs");
10
8
  const LOG_LEVELS = ['DEBUG', 'INFO', 'WARN', 'ERROR', 'NONE'];
11
- const currentLogLevel = (process.env.OASTLM_LOG_LEVEL || 'INFO').toUpperCase();
12
- const serviceName = process.env.OASTLM_SERVICE_NAME || 'OAS-TLM';
9
+ const currentLogLevel = (_bootConfig.bootEnvVariables.OASTLM_BOOT_LOG_LEVEL || 'INFO').toUpperCase();
10
+ const serviceName = 'OAS-Telemetry';
13
11
  function log(level, ...messages) {
14
12
  if (LOG_LEVELS.indexOf(level) >= LOG_LEVELS.indexOf(currentLogLevel)) {
15
13
  const timestamp = new Date().toISOString();
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.convertRegexRecursively = void 0;
7
+ const convertRegexRecursively = obj => {
8
+ if (Array.isArray(obj)) {
9
+ return obj.map(convertRegexRecursively);
10
+ } else if (obj && typeof obj === 'object') {
11
+ const newObj = {};
12
+ for (const key of Object.keys(obj)) {
13
+ if (key === '$regex' && typeof obj[key] === 'string') {
14
+ try {
15
+ return new RegExp(obj[key]);
16
+ } catch {
17
+ throw new Error(`Invalid regex value "${obj[key]}"`);
18
+ }
19
+ } else {
20
+ newObj[key] = convertRegexRecursively(obj[key]);
21
+ }
22
+ }
23
+ return newObj;
24
+ }
25
+ return obj;
26
+ };
27
+ exports.convertRegexRecursively = convertRegexRecursively;
@@ -0,0 +1,11 @@
1
+ import dotenv from 'dotenv';
2
+ if (process.env.NODE_ENV !== 'test') {
3
+ dotenv.config();
4
+ }
5
+ // This variables can NOT be configured via oasTelemetry(config)
6
+ // They are used at the import of the library
7
+ export const bootEnvVariables = {
8
+ OASTLM_BOOT_ENV: process.env.OASTLM_BOOT_ENV || process.env.NODE_ENV || 'production',
9
+ OASTLM_BOOT_MODULE_DISABLED: process.env.OASTLM_BOOT_MODULE_DISABLED === 'true',
10
+ OASTLM_BOOT_LOG_LEVEL: process.env.OASTLM_BOOT_LOG_LEVEL || 'INFO',
11
+ };
@@ -0,0 +1,126 @@
1
+ import merge from 'lodash.merge';
2
+ // Environment-level config (highest priority)
3
+ // If NOT defined, it should return UNDEFINED so it dose not override the userConfig or defaultConfig.
4
+ // Thats why we use getParsedEnvVar with no default value.
5
+ const loadEnv = () => {
6
+ return {
7
+ general: {
8
+ baseUrl: getParsedEnvVar("OASTLM_CONFIG_GENERAL_BASE_URL"),
9
+ specFileName: getParsedEnvVar("OASTLM_CONFIG_GENERAL_SPEC_FILE_NAME"),
10
+ // spec Not settable via env
11
+ },
12
+ auth: {
13
+ enabled: getParsedEnvVar("OASTLM_CONFIG_AUTH_ENABLED", (v) => v === "true"),
14
+ apiKeyMaxAge: getParsedEnvVar("OASTLM_CONFIG_AUTH_API_KEY_MAX_AGE", (v) => parseInt(v, 10)),
15
+ password: getParsedEnvVar("OASTLM_CONFIG_AUTH_PASSWORD"),
16
+ jwtSecret: getParsedEnvVar("OASTLM_CONFIG_AUTH_JWT_SECRET"),
17
+ },
18
+ traces: {
19
+ memoryExporter: {
20
+ enabled: getParsedEnvVar("OASTLM_CONFIG_TRACES_MEMORY_EXPORTER_ENABLED", (v) => v === "true"),
21
+ retentionTimeSeconds: getParsedEnvVar("OASTLM_CONFIG_TRACES_MEMORY_EXPORTER_RETENTION_TIME_SECONDS", (v) => parseInt(v, 10)),
22
+ // filters NOT settable via env
23
+ }
24
+ },
25
+ metrics: {
26
+ mainMetricReaderOptions: {
27
+ exportIntervalMillis: getParsedEnvVar("OASTLM_CONFIG_METRICS_MAIN_READER_EXPORT_INTERVAL", (v) => parseInt(v, 10)),
28
+ // metricProducers NOT settable via env
29
+ },
30
+ memoryExporter: {
31
+ enabled: getParsedEnvVar("OASTLM_CONFIG_METRICS_MEMORY_EXPORTER_ENABLED", (v) => v === "true"),
32
+ retentionTimeSeconds: getParsedEnvVar("OASTLM_CONFIG_METRICS_MEMORY_EXPORTER_RETENTION_TIME_SECONDS", (v) => parseInt(v, 10)),
33
+ // filters NOT settable via env
34
+ }
35
+ },
36
+ logs: {
37
+ memoryExporter: {
38
+ enabled: getParsedEnvVar("OASTLM_CONFIG_LOGS_MEMORY_EXPORTER_ENABLED", (v) => v === "true"),
39
+ retentionTimeSeconds: getParsedEnvVar("OASTLM_CONFIG_LOGS_MEMORY_EXPORTER_RETENTION_TIME_SECONDS", (v) => parseInt(v, 10)),
40
+ // filters NOT settable via env
41
+ },
42
+ },
43
+ ai: {
44
+ openAIKey: getParsedEnvVar("OASTLM_CONFIG_AI_OPENAI_KEY"),
45
+ openAIModel: getParsedEnvVar("OASTLM_CONFIG_AI_OPENAI_MODEL", (v) => v || "gpt-3.5-turbo"),
46
+ extraContextPrompts: getParsedEnvVar("OASTLM_CONFIG_AI_EXTRA_CONTEXT_PROMPTS", (v) => v ? v.split(',') : []),
47
+ },
48
+ };
49
+ };
50
+ // This defines de OasTlmConfig type, which is used throughout the library.
51
+ // Please ensure that all possible types are included here, not only the defaults.
52
+ // e.g. .ai.openAIKey: null as string | null, default is null, but can be set to a string.
53
+ // NOTE: Some BOOT environment variables (e.g., OASTLM_BOOT_MODULE_DISABLED) are accessed before this config is loaded.
54
+ // This means certain settings may affect application startup behavior outside of this configuration system.
55
+ export const defaultConfig = {
56
+ general: {
57
+ baseUrl: "/telemetry",
58
+ specFileName: null, // e.g. "oas.json" or null if not provided
59
+ spec: null, // e.g. JSON.stringify(oasSpec) or null if not provided,
60
+ uiPath: "/oas-telemetry-ui", // path to the UI, e.g. "/oas-telemetry-ui" WARN: This must match the UI package's App.tsx "oas-telemetry-ui" path
61
+ },
62
+ auth: {
63
+ enabled: false,
64
+ apiKeyMaxAge: 1000 * 60 * 60, // 1 hour
65
+ password: "oas-telemetry-password",
66
+ jwtSecret: "oas-telemetry-secret",
67
+ },
68
+ ai: {
69
+ openAIKey: null,
70
+ openAIModel: "gpt-3.5-turbo",
71
+ extraContextPrompts: [], // e.g. ["Provide detailed explanations", "Use simple language"]
72
+ },
73
+ traces: {
74
+ extraExporters: [], // e.g. [new ConsoleSpanExporter()]
75
+ extraProcessors: [], // e.g. [new SimpleSpanProcessor(new ConsoleSpanExporter())]
76
+ mainProcessorOptions: {
77
+ config: undefined
78
+ },
79
+ memoryExporter: {
80
+ enabled: true, // auto start exporting.
81
+ retentionTimeSeconds: 60 * 60, // 1 hour
82
+ },
83
+ filters: [], // future feature, currently not used
84
+ },
85
+ metrics: {
86
+ mainMetricReaderOptions: {
87
+ exportIntervalMillis: 1000 * 60, // 60 seconds
88
+ metricProducers: [], // experimental by OpenTelemetry, not used by OAS-TLM yet
89
+ },
90
+ extraReaders: [], // e.g. [new PrometheusExporter()]
91
+ extraViews: [], // e.g. [new MetricView({ name: 'my_metric', labels: ['env'] })]
92
+ memoryExporter: {
93
+ enabled: true,
94
+ retentionTimeSeconds: 60 * 60, // 1 hour
95
+ },
96
+ filters: [], // future feature, currently not used
97
+ },
98
+ logs: {
99
+ extraExporters: [], // e.g. [new ConsoleLogRecordExporter()]
100
+ extraProcessors: [], // e.g. [new SimpleLogRecordProcessor(new ConsoleLogRecordExporter())]
101
+ memoryExporter: {
102
+ enabled: true,
103
+ retentionTimeSeconds: 60 * 60, // 1 hour
104
+ },
105
+ filters: [], // future feature, currently not used
106
+ },
107
+ plugins: {
108
+ enabled: true, // future feature
109
+ extraPlugins: [], // future feature
110
+ },
111
+ };
112
+ // Helper to get an environment variable with optional transform
113
+ const getParsedEnvVar = (envKey, transform) => {
114
+ const rawValue = process.env[envKey];
115
+ // Treat undefined and "" in env as undefined (skip)
116
+ if (rawValue === undefined || rawValue === "")
117
+ return undefined;
118
+ if (typeof transform === 'function') {
119
+ return transform(rawValue);
120
+ }
121
+ return rawValue;
122
+ };
123
+ export const getConfig = (userConfig, fallbackConfig = defaultConfig, envConfig = loadEnv()) => {
124
+ // environment variables OVERRIDE userConfig OVERRIDE fallbackConfig
125
+ return merge({}, fallbackConfig, userConfig, envConfig);
126
+ };
package/dist/esm/index.js CHANGED
@@ -1,39 +1,28 @@
1
- import './instrumentation/index.js';
2
- import { globalOasTlmConfig } from './config.js';
3
- import { Router } from 'express';
4
- import { InMemoryExporter } from './exporters/InMemoryDbExporter.js';
1
+ import "./config/bootConfig.js"; // Load environment variables before any other imports
2
+ import './telemetry/initializeTelemetry.js'; // Initialize OpenTelemetry instrumentation
5
3
  import logger from './utils/logger.js';
6
- import { configureRoutes } from './tlmRoutes.js';
4
+ import { getConfig } from './config/config.js';
5
+ import { Router } from 'express';
6
+ import { configureRoutes } from './routesManager.js';
7
+ import { configureTelemetry } from './telemetry/telemetryConfigurator.js';
8
+ import { bootEnvVariables } from "./config/bootConfig.js";
7
9
  /**
8
- * Returns the Oas Telemetry middleware. The parameters are the same as `globalOasTlmConfig`.
10
+ * Returns the OAS-Telemetry middleware.
9
11
  * All parameters are optional. However, either `spec` or `specFileName` must be provided to enable endpoint filtering.
10
12
  */
11
13
  export default function oasTelemetry(oasTlmInputConfig) {
12
14
  const router = Router();
13
- if (process.env.OASTLM_MODULE_DISABLED === 'true') {
15
+ // This environment variable cannot be set via the config object,
16
+ // as it is required to disable OpenTelemetry SDK initialization,
17
+ // which occurs during the first import at the top of this file.
18
+ if (bootEnvVariables.OASTLM_BOOT_MODULE_DISABLED) {
14
19
  return router;
15
20
  }
16
- if (oasTlmInputConfig) {
17
- logger.info("User provided config");
18
- // Override global config with user provided config
19
- for (const key in globalOasTlmConfig) {
20
- globalOasTlmConfig[key] = oasTlmInputConfig[key] ?? globalOasTlmConfig[key];
21
- }
22
- }
23
- logger.info("BaseURL: ", globalOasTlmConfig.baseURL);
24
- globalOasTlmConfig.dynamicSpanExporter.changeExporter(globalOasTlmConfig.exporter ?? new InMemoryExporter());
25
- if (globalOasTlmConfig.spec)
26
- logger.info(`Spec content provided`);
27
- else {
28
- if (globalOasTlmConfig.specFileName != "")
29
- logger.info(`Spec file used for telemetry: ${globalOasTlmConfig.specFileName}`);
30
- else {
31
- console.error("No spec available !");
32
- }
33
- }
34
- if (globalOasTlmConfig.autoActivate) {
35
- globalOasTlmConfig.dynamicSpanExporter.exporter?.start();
36
- }
37
- configureRoutes(router);
21
+ const oasTlmConfig = getConfig(oasTlmInputConfig);
22
+ logger.info("BaseUrl: ", oasTlmConfig.general.baseUrl);
23
+ if (!oasTlmConfig.general.spec && !oasTlmConfig.general.specFileName)
24
+ logger.warn("No spec provided, endpoint filtering will not be available. Please provide either `spec` or `specFileName` in the configuration.");
25
+ configureTelemetry(oasTlmConfig);
26
+ configureRoutes(router, oasTlmConfig);
38
27
  return router;
39
28
  }
@@ -1,18 +1,19 @@
1
1
  import { json } from "express";
2
2
  import logger from "./utils/logger.js";
3
3
  import cors from 'cors';
4
- import { globalOasTlmConfig } from "./config.js";
5
- import metricsRoutes from "./tlm-metric/metricsRoutes.js";
4
+ import { getTraceRoutes } from "./tlm-trace/traceRoutes.js";
5
+ import { getMetricsRoutes } from "./tlm-metric/metricsRoutes.js";
6
+ import { getLogRoutes } from "./tlm-log/logRoutes.js";
6
7
  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') {
8
+ import { getAuthRoutes } from './tlm-auth/authRoutes.js';
9
+ import { getUIRoutes } from './tlm-ui/uiRoutes.js';
10
+ import { getAuthMiddleware } from "./tlm-auth/authMiddleware.js";
11
+ import { getUtilsRoutes } from "./tlm-util/utilRoutes.js";
12
+ import { getAIRoutes } from "./tlm-ai/aiRoutes.js";
13
+ import { bootEnvVariables } from "./config/bootConfig.js";
14
+ import { getPluginRoutes } from "./tlm-plugin/pluginRoutes.js";
15
+ export const configureRoutes = (router, oasTlmConfig) => {
16
+ if (bootEnvVariables.OASTLM_BOOT_ENV === 'development') {
16
17
  logger.info("Running in development mode, enabling CORS for all origins");
17
18
  router.use(cors({
18
19
  origin: '*', // Permitir todas las solicitudes en desarrollo
@@ -26,19 +27,23 @@ export const configureRoutes = (router) => {
26
27
  }
27
28
  return json({ limit: '10mb' })(req, res, next);
28
29
  });
29
- const allAuthMiddlewares = getWrappedMiddlewares(() => globalOasTlmConfig.authEnabled, [cookieParser(), authRoutes, authMiddleware]);
30
- const baseURL = globalOasTlmConfig.baseURL;
31
- router.use(baseURL, allAuthMiddlewares);
30
+ const allAuthMiddlewares = getWrappedMiddlewares(() => oasTlmConfig.auth.enabled, [cookieParser(), getAuthRoutes(oasTlmConfig), getAuthMiddleware(oasTlmConfig)]);
31
+ const baseUrl = oasTlmConfig.general.baseUrl;
32
+ router.use(baseUrl, allAuthMiddlewares);
33
+ router.use(baseUrl + "/traces", getTraceRoutes());
34
+ router.use(baseUrl + "/metrics", getMetricsRoutes());
35
+ router.use(baseUrl + "/logs", getLogRoutes());
36
+ router.use(baseUrl + "/ai", getWrappedMiddlewares(() => oasTlmConfig.ai.openAIKey !== null, [getAIRoutes(oasTlmConfig)]));
32
37
  // 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);
38
+ router.use(baseUrl + "/oas-telemetry-ui", getUIRoutes());
39
+ router.use(baseUrl + "/utils", getUtilsRoutes(oasTlmConfig));
40
+ router.use(baseUrl + "/plugins", getPluginRoutes());
41
+ router.get(baseUrl + '/health', (_req, res) => {
42
+ res.status(200).send({ status: 'OK' });
43
+ });
39
44
  //redirect to the UI when accessing the base URL
40
- router.get(baseURL, (req, res) => {
41
- res.redirect(baseURL + "/oas-telemetry-ui");
45
+ router.get(baseUrl, (req, res) => {
46
+ res.redirect(baseUrl + "/oas-telemetry-ui");
42
47
  });
43
48
  };
44
49
  /**
@@ -1,17 +1,22 @@
1
1
  import { hrTimeToMicroseconds } from '@opentelemetry/core';
2
2
  import { ExportResultCode } from '@opentelemetry/core';
3
- import { removeCircularRefs, applyNesting } from '../utils/circular.js';
4
3
  import Datastore from '@seald-io/nedb';
5
4
  import MiniSearch from 'minisearch';
6
- export class InMemoryLogRecordExporter {
7
- constructor() {
8
- this._db = new Datastore();
5
+ import { applyNesting, removeCircularRefs } from '../utils/circular.js';
6
+ import { Enabler } from '../wrappers.js';
7
+ import logger from '../../../utils/logger.js';
8
+ export class InMemoryDbLogExporter extends Enabler {
9
+ constructor(retentionTimeInSeconds = 3600) {
10
+ super();
11
+ this._retentionTimeInSeconds = retentionTimeInSeconds;
12
+ this._db = new Datastore({ timestampData: true });
13
+ this._db.ensureIndex({ fieldName: 'createdAt' });
9
14
  this._miniSearch = new MiniSearch({
10
15
  fields: ['body'],
11
16
  storeFields: ['_id'],
12
17
  idField: '_id',
13
18
  });
14
- this._stopped = false;
19
+ this._startCleanupJob();
15
20
  }
16
21
  /*
17
22
  * SUPER WARNING:
@@ -25,7 +30,7 @@ export class InMemoryLogRecordExporter {
25
30
  * @param resultCallback
26
31
  */
27
32
  export(logs, resultCallback) {
28
- if (this._stopped) {
33
+ if (!this.isEnabled()) {
29
34
  resultCallback({ code: ExportResultCode.SUCCESS });
30
35
  return;
31
36
  }
@@ -57,7 +62,7 @@ export class InMemoryLogRecordExporter {
57
62
  if (messageSearch) {
58
63
  const searchResults = this._miniSearch.search(messageSearch);
59
64
  const ids = searchResults.map((result) => result._id);
60
- console.dir(`MiniSearch found ${ids.length} results for search term "${messageSearch}"`, { depth: 3 });
65
+ logger.debug(`MiniSearch found ${ids.length} results for search term "${messageSearch}"`, { depth: 3 });
61
66
  // Add MiniSearch results to the query
62
67
  query._id = { $in: ids };
63
68
  }
@@ -68,7 +73,7 @@ export class InMemoryLogRecordExporter {
68
73
  if (result.code === ExportResultCode.SUCCESS) {
69
74
  this._db.find({}, (err, docs) => {
70
75
  if (err) {
71
- console.dir(err);
76
+ logger.debug(err);
72
77
  callback(err, []);
73
78
  return;
74
79
  }
@@ -80,15 +85,6 @@ export class InMemoryLogRecordExporter {
80
85
  }
81
86
  });
82
87
  }
83
- start() {
84
- this._stopped = false;
85
- }
86
- stop() {
87
- this._stopped = true;
88
- }
89
- isRunning() {
90
- return !this._stopped;
91
- }
92
88
  getFinishedLogs() {
93
89
  return this._db.getAllData();
94
90
  }
@@ -114,6 +110,10 @@ export class InMemoryLogRecordExporter {
114
110
  attributes: logRecord.attributes,
115
111
  };
116
112
  }
113
+ set retentionTimeInSeconds(retentionTimeInSeconds) {
114
+ this._retentionTimeInSeconds = retentionTimeInSeconds;
115
+ logger.info(`InMemoryDbLogExporter retention time set to ${this._retentionTimeInSeconds} seconds`);
116
+ }
117
117
  _insertLogs(logsToInsert, resultCallback) {
118
118
  this._db.insert(logsToInsert, (err, newDocs) => {
119
119
  if (err) {
@@ -127,4 +127,18 @@ export class InMemoryLogRecordExporter {
127
127
  });
128
128
  return;
129
129
  }
130
+ _startCleanupJob() {
131
+ const interval = 1000;
132
+ setInterval(() => {
133
+ const expirationDate = new Date(Date.now() - this._retentionTimeInSeconds * 1000);
134
+ this._db.remove({ createdAt: { $lt: expirationDate } }, { multi: true }, (err, numRemoved) => {
135
+ if (err) {
136
+ logger.error('Error in TTL cleanup:', err);
137
+ }
138
+ else if (numRemoved > 0) {
139
+ logger.debug(`TTL cleanup: removed ${numRemoved} expired logs`);
140
+ }
141
+ });
142
+ }, interval);
143
+ }
130
144
  }