@oas-tools/oas-telemetry 0.6.1 → 0.7.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +442 -442
- package/dist/{config.cjs → cjs/config.cjs} +6 -7
- package/dist/{exporters → cjs/exporters}/InMemoryDBMetricsExporter.cjs +5 -40
- package/dist/cjs/exporters/InMemoryDbExporter.cjs +87 -0
- package/dist/cjs/exporters/InMemoryLogRecordExporter.cjs +110 -0
- package/dist/{exporters → cjs/exporters}/consoleExporter.cjs +2 -7
- package/dist/{exporters → cjs/exporters}/dynamicExporter.cjs +12 -19
- package/dist/cjs/index.cjs +43 -0
- package/dist/cjs/instrumentation/index.cjs +28 -0
- package/dist/cjs/instrumentation/logs.cjs +46 -0
- package/dist/cjs/instrumentation/metrics.cjs +27 -0
- package/dist/cjs/instrumentation/traces.cjs +19 -0
- package/dist/{openTelemetry.cjs → cjs/openTelemetry.cjs} +6 -8
- package/dist/{systemMetrics.cjs → cjs/systemMetrics.cjs} +7 -7
- package/dist/cjs/tlm-ai/agent.cjs +79 -0
- package/dist/cjs/tlm-ai/aiController.cjs +69 -0
- package/dist/cjs/tlm-ai/aiRoutes.cjs +13 -0
- package/dist/cjs/tlm-ai/knownMicroservices.cjs +13 -0
- package/dist/cjs/tlm-ai/tools.cjs +504 -0
- package/dist/{routes/authRoutes.cjs → cjs/tlm-auth/authController.cjs} +21 -28
- package/dist/{middleware → cjs/tlm-auth}/authMiddleware.cjs +1 -1
- package/dist/cjs/tlm-auth/authRoutes.cjs +14 -0
- package/dist/cjs/tlm-log/logController.cjs +55 -0
- package/dist/cjs/tlm-log/logRoutes.cjs +13 -0
- package/dist/{routes → cjs/tlm-metric}/metricsRoutes.cjs +1 -2
- package/dist/{controllers → cjs/tlm-plugin}/pluginController.cjs +31 -41
- package/dist/cjs/tlm-plugin/pluginRoutes.cjs +13 -0
- package/dist/{controllers/telemetryController.cjs → cjs/tlm-trace/traceController.cjs} +8 -19
- package/dist/cjs/tlm-trace/traceRoutes.cjs +17 -0
- package/dist/cjs/tlm-ui/uiController.cjs +27 -0
- package/dist/cjs/tlm-ui/uiRoutes.cjs +31 -0
- package/dist/cjs/tlm-util/utilController.cjs +63 -0
- package/dist/cjs/tlm-util/utilRoutes.cjs +12 -0
- package/dist/cjs/tlmRoutes.cjs +79 -0
- package/dist/cjs/types/index.cjs +8 -0
- package/dist/cjs/utils/circular.cjs +90 -0
- package/dist/cjs/utils/logger.cjs +28 -0
- package/{src → dist/esm}/config.js +20 -23
- package/{src → dist/esm}/exporters/InMemoryDBMetricsExporter.js +57 -111
- package/dist/esm/exporters/InMemoryDbExporter.js +87 -0
- package/dist/esm/exporters/InMemoryLogRecordExporter.js +95 -0
- package/{src → dist/esm}/exporters/consoleExporter.js +38 -47
- package/{src → dist/esm}/exporters/dynamicExporter.js +50 -62
- package/dist/esm/index.js +39 -0
- package/dist/esm/instrumentation/index.js +26 -0
- package/dist/esm/instrumentation/logs.js +34 -0
- package/dist/esm/instrumentation/metrics.js +18 -0
- package/dist/esm/instrumentation/traces.js +12 -0
- package/{src → dist/esm}/openTelemetry.js +50 -58
- package/dist/esm/systemMetrics.js +82 -0
- package/dist/esm/tlm-ai/agent.js +68 -0
- package/dist/esm/tlm-ai/aiController.js +45 -0
- package/dist/esm/tlm-ai/aiRoutes.js +7 -0
- package/dist/esm/tlm-ai/knownMicroservices.js +5 -0
- package/dist/esm/tlm-ai/tools.js +490 -0
- package/dist/esm/tlm-auth/authController.js +41 -0
- package/{src/middleware → dist/esm/tlm-auth}/authMiddleware.js +12 -14
- package/dist/esm/tlm-auth/authRoutes.js +7 -0
- package/dist/esm/tlm-log/logController.js +36 -0
- package/dist/esm/tlm-log/logRoutes.js +7 -0
- package/{src/controllers → dist/esm/tlm-metric}/metricsController.js +28 -30
- package/{src/routes → dist/esm/tlm-metric}/metricsRoutes.js +8 -15
- package/{src/controllers → dist/esm/tlm-plugin}/pluginController.js +103 -115
- package/dist/esm/tlm-plugin/pluginRoutes.js +7 -0
- package/dist/esm/tlm-trace/traceController.js +54 -0
- package/dist/esm/tlm-trace/traceRoutes.js +11 -0
- package/dist/esm/tlm-ui/uiController.js +20 -0
- package/dist/esm/tlm-ui/uiRoutes.js +23 -0
- package/dist/esm/tlm-util/utilController.js +57 -0
- package/dist/esm/tlm-util/utilRoutes.js +6 -0
- package/dist/esm/tlmRoutes.js +72 -0
- package/dist/esm/types/index.js +4 -0
- package/dist/esm/utils/circular.js +84 -0
- package/dist/esm/utils/logger.js +19 -0
- package/dist/types/config.d.ts +6 -0
- package/dist/types/exporters/InMemoryDBMetricsExporter.d.ts +15 -0
- package/dist/types/exporters/InMemoryDbExporter.d.ts +24 -0
- package/dist/types/exporters/InMemoryLogRecordExporter.d.ts +27 -0
- package/dist/types/exporters/consoleExporter.d.ts +13 -0
- package/dist/types/exporters/dynamicExporter.d.ts +25 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/instrumentation/index.d.ts +1 -0
- package/dist/types/instrumentation/logs.d.ts +1 -0
- package/dist/types/instrumentation/metrics.d.ts +1 -0
- package/dist/types/instrumentation/traces.d.ts +1 -0
- package/dist/types/openTelemetry.d.ts +1 -0
- package/dist/types/systemMetrics.d.ts +26 -0
- package/dist/types/tlm-ai/agent.d.ts +1 -0
- package/dist/types/tlm-ai/aiController.d.ts +4 -0
- package/dist/types/tlm-ai/aiRoutes.d.ts +2 -0
- package/dist/types/tlm-ai/knownMicroservices.d.ts +6 -0
- package/dist/types/tlm-ai/tools.d.ts +45 -0
- package/dist/types/tlm-auth/authController.d.ts +4 -0
- package/dist/types/tlm-auth/authMiddleware.d.ts +2 -0
- package/dist/types/tlm-auth/authRoutes.d.ts +2 -0
- package/dist/types/tlm-log/logController.d.ts +4 -0
- package/dist/types/tlm-log/logRoutes.d.ts +2 -0
- package/dist/types/tlm-metric/metricsController.d.ts +4 -0
- package/dist/types/tlm-metric/metricsRoutes.d.ts +2 -0
- package/dist/types/tlm-plugin/pluginController.d.ts +3 -0
- package/dist/types/tlm-plugin/pluginRoutes.d.ts +2 -0
- package/dist/types/tlm-trace/traceController.d.ts +7 -0
- package/dist/types/tlm-trace/traceRoutes.d.ts +2 -0
- package/dist/types/tlm-ui/uiController.d.ts +8 -0
- package/dist/types/tlm-ui/uiRoutes.d.ts +2 -0
- package/dist/types/tlm-util/utilController.d.ts +3 -0
- package/dist/types/tlm-util/utilRoutes.d.ts +2 -0
- package/dist/types/tlmRoutes.d.ts +2 -0
- package/dist/types/types/index.d.ts +56 -0
- package/dist/types/utils/circular.d.ts +31 -0
- package/dist/types/utils/logger.d.ts +9 -0
- package/dist/ui/assets/index-BNhZBPi2.css +1 -0
- package/dist/ui/assets/index-DxGAMrAl.js +401 -0
- package/dist/ui/index.html +14 -0
- package/dist/ui/vite.svg +1 -0
- package/package.json +80 -77
- package/dist/controllers/uiController.cjs +0 -78
- package/dist/exporters/InMemoryDbExporter.cjs +0 -178
- package/dist/index.cjs +0 -110
- package/dist/routes/telemetryRoutes.cjs +0 -31
- package/dist/services/uiService.cjs +0 -1520
- package/src/controllers/telemetryController.js +0 -69
- package/src/controllers/uiController.js +0 -69
- package/src/dev/ui/login.html +0 -32
- package/src/exporters/InMemoryDbExporter.js +0 -181
- package/src/index.js +0 -114
- package/src/routes/authRoutes.js +0 -53
- package/src/routes/telemetryRoutes.js +0 -38
- package/src/services/uiService.js +0 -1520
- package/src/systemMetrics.js +0 -102
- /package/dist/{controllers → cjs/tlm-metric}/metricsController.cjs +0 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.configureRoutes = void 0;
|
|
7
|
+
var _express = require("express");
|
|
8
|
+
var _logger = _interopRequireDefault(require("./utils/logger.cjs"));
|
|
9
|
+
var _cors = _interopRequireDefault(require("cors"));
|
|
10
|
+
var _config = require("./config.cjs");
|
|
11
|
+
var _metricsRoutes = _interopRequireDefault(require("./tlm-metric/metricsRoutes.cjs"));
|
|
12
|
+
var _cookieParser = _interopRequireDefault(require("cookie-parser"));
|
|
13
|
+
var _authRoutes = _interopRequireDefault(require("./tlm-auth/authRoutes.cjs"));
|
|
14
|
+
var _uiRoutes = _interopRequireDefault(require("./tlm-ui/uiRoutes.cjs"));
|
|
15
|
+
var _traceRoutes = _interopRequireDefault(require("./tlm-trace/traceRoutes.cjs"));
|
|
16
|
+
var _authMiddleware = require("./tlm-auth/authMiddleware.cjs");
|
|
17
|
+
var _utilRoutes = _interopRequireDefault(require("./tlm-util/utilRoutes.cjs"));
|
|
18
|
+
var _logRoutes = _interopRequireDefault(require("./tlm-log/logRoutes.cjs"));
|
|
19
|
+
var _aiRoutes = _interopRequireDefault(require("./tlm-ai/aiRoutes.cjs"));
|
|
20
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
21
|
+
const configureRoutes = router => {
|
|
22
|
+
if (process.env.OASTLM_ENV === 'development') {
|
|
23
|
+
_logger.default.info("Running in development mode, enabling CORS for all origins");
|
|
24
|
+
router.use((0, _cors.default)({
|
|
25
|
+
origin: '*',
|
|
26
|
+
// Permitir todas las solicitudes en desarrollo
|
|
27
|
+
methods: ['GET', 'POST', 'PUT', 'DELETE'],
|
|
28
|
+
allowedHeaders: ['Content-Type', 'Authorization']
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
router.use((req, res, next) => {
|
|
32
|
+
if (req.body !== undefined) {
|
|
33
|
+
return next(); // Already parsed, no need to parse again.
|
|
34
|
+
}
|
|
35
|
+
return (0, _express.json)()(req, res, next);
|
|
36
|
+
});
|
|
37
|
+
const allAuthMiddlewares = getWrappedMiddlewares(() => _config.globalOasTlmConfig.authEnabled, [(0, _cookieParser.default)(), _authRoutes.default, _authMiddleware.authMiddleware]);
|
|
38
|
+
const baseURL = _config.globalOasTlmConfig.baseURL;
|
|
39
|
+
router.use(baseURL, allAuthMiddlewares);
|
|
40
|
+
// WARNING: This path must be the same as the one used in the UI package App.tsx "oas-telemetry-ui"
|
|
41
|
+
router.use(baseURL + "/traces", _traceRoutes.default);
|
|
42
|
+
router.use(baseURL + "/metrics", _metricsRoutes.default);
|
|
43
|
+
router.use(baseURL + "/logs", _logRoutes.default);
|
|
44
|
+
router.use(baseURL + "/ai", getWrappedMiddlewares(() => process.env.OASTLM_AI_OPENAI_API_KEY !== null && process.env.OASTLM_AI_OPENAI_API_KEY !== "", [_aiRoutes.default]));
|
|
45
|
+
router.use(baseURL + "/oas-telemetry-ui", _uiRoutes.default);
|
|
46
|
+
router.use(baseURL + "/utils", _utilRoutes.default);
|
|
47
|
+
//redirect to the UI when accessing the base URL
|
|
48
|
+
router.get(baseURL, (req, res) => {
|
|
49
|
+
res.redirect(baseURL + "/oas-telemetry-ui");
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* This function wraps the provided middleware functions with a condition callback.
|
|
54
|
+
* If the condition callback returns true, the middleware/router will be executed.
|
|
55
|
+
* If the condition callback returns false, the middleware/router will be skipped.
|
|
56
|
+
*
|
|
57
|
+
* @callback {function} conditionCallback A callback function that returns a boolean to determine if the middleware should be used.
|
|
58
|
+
* @param {Array} middlewares An array of middleware or routers to be wrapped.
|
|
59
|
+
* @returns {Array} An array of wrapped middleware functions.
|
|
60
|
+
*/
|
|
61
|
+
exports.configureRoutes = configureRoutes;
|
|
62
|
+
function getWrappedMiddlewares(conditionCallback, middlewares) {
|
|
63
|
+
return middlewares.map(middleware => {
|
|
64
|
+
return function (req, res, next) {
|
|
65
|
+
if (conditionCallback()) {
|
|
66
|
+
if (typeof middleware === 'function') {
|
|
67
|
+
// look for handle property, if it exists, it's a router. If not call middleware
|
|
68
|
+
if (middleware.handle) {
|
|
69
|
+
middleware.handle(req, res, next);
|
|
70
|
+
} else {
|
|
71
|
+
middleware(req, res, next);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
} else {
|
|
75
|
+
next();
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.applyNesting = applyNesting;
|
|
7
|
+
exports.convertToNestedObject = convertToNestedObject;
|
|
8
|
+
exports.removeCircularRefs = removeCircularRefs;
|
|
9
|
+
function removeCircularRefs(obj) {
|
|
10
|
+
// const seen = new WeakMap(); // Used to keep track of visited objects
|
|
11
|
+
// Replacer function to handle circular references
|
|
12
|
+
function replacer(key, value) {
|
|
13
|
+
if (key === "_spanProcessor") {
|
|
14
|
+
return "oas-telemetry skips this field to avoid circular reference";
|
|
15
|
+
}
|
|
16
|
+
// GENERIC CIRCULAR REFERENCE HANDLING
|
|
17
|
+
// if (typeof value === "object" && value !== null) {
|
|
18
|
+
// // If the object has been visited before, return the name prefixed with "CIRCULAR+"
|
|
19
|
+
// if (seen.has(value)) {
|
|
20
|
+
// return `CIRCULAR${key}`;
|
|
21
|
+
// }
|
|
22
|
+
// seen.set(value, key); // Mark the object as visited with its name
|
|
23
|
+
// }
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
// Convert the object to a string and then parse it back
|
|
27
|
+
// This will trigger the replacer function to handle circular references
|
|
28
|
+
const jsonString = JSON.stringify(obj, replacer);
|
|
29
|
+
return JSON.parse(jsonString);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Recursively converts dot-separated keys in an object to nested objects.
|
|
33
|
+
*
|
|
34
|
+
* @param {any} obj - The object to process.
|
|
35
|
+
* @returns {any} - The object with all dot-separated keys converted to nested objects.
|
|
36
|
+
* @example
|
|
37
|
+
* // Input:
|
|
38
|
+
* // {
|
|
39
|
+
* // "http.method": "GET",
|
|
40
|
+
* // "http.url": "http://example.com",
|
|
41
|
+
* // "nested.obj.key": "value"
|
|
42
|
+
* // }
|
|
43
|
+
* // Output:
|
|
44
|
+
* // {
|
|
45
|
+
* // "http": {
|
|
46
|
+
* // "method": "GET",
|
|
47
|
+
* // "url": "http://example.com"
|
|
48
|
+
* // },
|
|
49
|
+
* // "nested": {
|
|
50
|
+
* // "obj": {
|
|
51
|
+
* // "key": "value"
|
|
52
|
+
* // }
|
|
53
|
+
* // }
|
|
54
|
+
* // }
|
|
55
|
+
*/
|
|
56
|
+
function convertToNestedObject(obj) {
|
|
57
|
+
const result = {};
|
|
58
|
+
for (const key in obj) {
|
|
59
|
+
const keys = key.split('.');
|
|
60
|
+
let temp = result;
|
|
61
|
+
for (let i = 0; i < keys.length; i++) {
|
|
62
|
+
const currentKey = keys[i];
|
|
63
|
+
if (i === keys.length - 1) {
|
|
64
|
+
// Last key, set the value
|
|
65
|
+
temp[currentKey] = obj[key];
|
|
66
|
+
} else {
|
|
67
|
+
// Intermediate key, ensure the object exists
|
|
68
|
+
if (!temp[currentKey]) {
|
|
69
|
+
temp[currentKey] = {};
|
|
70
|
+
}
|
|
71
|
+
temp = temp[currentKey];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Applies nesting to all dot-separated keys within an object.
|
|
79
|
+
*/
|
|
80
|
+
function applyNesting(obj) {
|
|
81
|
+
for (const key in obj) {
|
|
82
|
+
const value = obj[key];
|
|
83
|
+
if (Array.isArray(value)) {
|
|
84
|
+
obj[key] = value.map(item => typeof item === 'object' && item !== null ? applyNesting(item) : item);
|
|
85
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
86
|
+
obj[key] = applyNesting(value);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return convertToNestedObject(obj);
|
|
90
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
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();
|
|
10
|
+
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';
|
|
13
|
+
function log(level, ...messages) {
|
|
14
|
+
if (LOG_LEVELS.indexOf(level) >= LOG_LEVELS.indexOf(currentLogLevel)) {
|
|
15
|
+
const timestamp = new Date().toISOString();
|
|
16
|
+
console.log(`${timestamp} [${serviceName}] [${level}]:`, ...messages);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
var _default = exports.default = {
|
|
20
|
+
debug: (...messages) => log('DEBUG', ...messages),
|
|
21
|
+
info: (...messages) => log('INFO', ...messages),
|
|
22
|
+
log: (...messages) => log('INFO', ...messages),
|
|
23
|
+
// Alias for info
|
|
24
|
+
warn: (...messages) => log('WARN', ...messages),
|
|
25
|
+
error: (...messages) => log('ERROR', ...messages),
|
|
26
|
+
currentLogLevel
|
|
27
|
+
};
|
|
28
|
+
module.exports = exports.default;
|
|
@@ -1,23 +1,20 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
};
|
|
21
|
-
//5 name alternatives. one for globals
|
|
22
|
-
|
|
23
|
-
export default {globalOasTlmConfig}
|
|
1
|
+
import DynamicExporter from "./exporters/dynamicExporter.js";
|
|
2
|
+
import { InMemoryDBMetricsExporter } from "./exporters/InMemoryDBMetricsExporter.js";
|
|
3
|
+
import { InMemoryLogRecordExporter } from "./exporters/InMemoryLogRecordExporter.js";
|
|
4
|
+
//Environment variables
|
|
5
|
+
//OASTLM_MODULE_DISABLED = 'true' //Disables the module (empty middleware and no tracing)
|
|
6
|
+
export const globalOasTlmConfig = {
|
|
7
|
+
dynamicSpanExporter: new DynamicExporter(),
|
|
8
|
+
metricsExporter: new InMemoryDBMetricsExporter(),
|
|
9
|
+
logExporter: new InMemoryLogRecordExporter(),
|
|
10
|
+
metricsExporterInterval: 1000 * 30, // milliseconds
|
|
11
|
+
baseURL: "/telemetry",
|
|
12
|
+
spec: null,
|
|
13
|
+
specFileName: "",
|
|
14
|
+
autoActivate: true,
|
|
15
|
+
authEnabled: false,
|
|
16
|
+
apiKeyMaxAge: 1000 * 60 * 60, // 1 hour
|
|
17
|
+
password: "oas-telemetry-password",
|
|
18
|
+
jwtSecret: "oas-telemetry-secret",
|
|
19
|
+
};
|
|
20
|
+
export default { globalOasTlmConfig };
|
|
@@ -1,111 +1,57 @@
|
|
|
1
|
-
import { ExportResultCode } from '@opentelemetry/core';
|
|
2
|
-
import dataStore from '@seald-io/nedb';
|
|
3
|
-
|
|
4
|
-
export class InMemoryDBMetricsExporter {
|
|
5
|
-
constructor() {
|
|
6
|
-
this._metrics = new dataStore();
|
|
7
|
-
this._stopped = false;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
console.error('Error exporting metrics\n' + error.message + '\n' + error.stack);
|
|
25
|
-
return resultCallback({
|
|
26
|
-
code: ExportResultCode.FAILED,
|
|
27
|
-
error: new Error('Error exporting metrics\n' + error.message + '\n' + error.stack),
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
this._metrics.
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
reset() {
|
|
59
|
-
this._metrics = new dataStore();
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
getFinishedMetrics() {
|
|
63
|
-
return this._metrics.getAllData();
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function convertToNestedObject(obj) {
|
|
68
|
-
const result = {};
|
|
69
|
-
|
|
70
|
-
for (const key in obj) {
|
|
71
|
-
const keys = key.split('.');
|
|
72
|
-
let temp = result;
|
|
73
|
-
|
|
74
|
-
for (let i = 0; i < keys.length; i++) {
|
|
75
|
-
const currentKey = keys[i];
|
|
76
|
-
|
|
77
|
-
if (i === keys.length - 1) {
|
|
78
|
-
// Last key, set the value
|
|
79
|
-
temp[currentKey] = obj[key];
|
|
80
|
-
} else {
|
|
81
|
-
// Intermediate key, ensure the object exists
|
|
82
|
-
if (!temp[currentKey]) {
|
|
83
|
-
temp[currentKey] = {};
|
|
84
|
-
}
|
|
85
|
-
temp = temp[currentKey];
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return result;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Applies nesting to all dot-separated keys within an object.
|
|
95
|
-
*
|
|
96
|
-
* @param {Object} obj - The object to apply nesting to.
|
|
97
|
-
* @returns {Object} - The transformed object with nested structures.
|
|
98
|
-
*/
|
|
99
|
-
function applyNesting(obj) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
for (const key in obj) {
|
|
103
|
-
if (typeof obj[key] === 'object' && obj[key] !== null) {
|
|
104
|
-
obj[key] = applyNesting(obj[key]);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
return obj;
|
|
110
|
-
}
|
|
111
|
-
|
|
1
|
+
import { ExportResultCode } from '@opentelemetry/core';
|
|
2
|
+
import dataStore from '@seald-io/nedb';
|
|
3
|
+
import { applyNesting } from '../utils/circular.js';
|
|
4
|
+
export class InMemoryDBMetricsExporter {
|
|
5
|
+
constructor() {
|
|
6
|
+
this._metrics = new dataStore();
|
|
7
|
+
this._stopped = false;
|
|
8
|
+
}
|
|
9
|
+
export(metrics, resultCallback) {
|
|
10
|
+
try {
|
|
11
|
+
if (!this._stopped) {
|
|
12
|
+
// metrics = metrics?.scopeMetrics;
|
|
13
|
+
const cleanMetrics = applyNesting(metrics);
|
|
14
|
+
this._metrics.insert(cleanMetrics, (err, _newDoc) => {
|
|
15
|
+
if (err) {
|
|
16
|
+
console.error('Insertion Error:', err);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
setTimeout(() => resultCallback({ code: ExportResultCode.SUCCESS }), 0);
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
console.error('Error exporting metrics\n' + error.message + '\n' + error.stack);
|
|
25
|
+
return resultCallback({
|
|
26
|
+
code: ExportResultCode.FAILED,
|
|
27
|
+
error: new Error('Error exporting metrics\n' + error.message + '\n' + error.stack),
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
start() {
|
|
32
|
+
this._stopped = false;
|
|
33
|
+
}
|
|
34
|
+
stop() {
|
|
35
|
+
this._stopped = true;
|
|
36
|
+
}
|
|
37
|
+
isRunning() {
|
|
38
|
+
return !this._stopped;
|
|
39
|
+
}
|
|
40
|
+
shutdown() {
|
|
41
|
+
this._stopped = true;
|
|
42
|
+
this._metrics = new dataStore();
|
|
43
|
+
return this.forceFlush();
|
|
44
|
+
}
|
|
45
|
+
forceFlush() {
|
|
46
|
+
return Promise.resolve();
|
|
47
|
+
}
|
|
48
|
+
find(search, callback) {
|
|
49
|
+
this._metrics.find(search, callback);
|
|
50
|
+
}
|
|
51
|
+
reset() {
|
|
52
|
+
this._metrics = new dataStore();
|
|
53
|
+
}
|
|
54
|
+
getFinishedMetrics() {
|
|
55
|
+
return this._metrics.getAllData();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { ExportResultCode } from '@opentelemetry/core';
|
|
2
|
+
//import in memory database
|
|
3
|
+
import dataStore from '@seald-io/nedb';
|
|
4
|
+
import logger from '../utils/logger.js';
|
|
5
|
+
import { applyNesting, removeCircularRefs } from '../utils/circular.js';
|
|
6
|
+
export class InMemoryExporter {
|
|
7
|
+
constructor() {
|
|
8
|
+
// Overrided by dynamic exporter
|
|
9
|
+
this.plugins = [];
|
|
10
|
+
this._spans = new dataStore();
|
|
11
|
+
this._stopped = true;
|
|
12
|
+
}
|
|
13
|
+
;
|
|
14
|
+
export(readableSpans, resultCallback) {
|
|
15
|
+
try {
|
|
16
|
+
if (!this._stopped) {
|
|
17
|
+
// Prepare spans to be inserted into the in-memory database (remove circular references and convert to nested objects)
|
|
18
|
+
const cleanSpans = readableSpans
|
|
19
|
+
.map(nestedSpan => removeCircularRefs(nestedSpan)) // to avoid JSON parsing error
|
|
20
|
+
.map(span => applyNesting(span)) // to avoid dot notation in keys (neDB does not support dot notation in keys)
|
|
21
|
+
.filter(span => !span?.attributes?.http?.target?.includes("/telemetry")); // to avoid telemetry spans
|
|
22
|
+
// Insert spans into the in-memory database
|
|
23
|
+
this._spans.insert(cleanSpans, (err, _newDoc) => {
|
|
24
|
+
// p = {name, plugin
|
|
25
|
+
this.plugins.forEach((pluginResource, i) => {
|
|
26
|
+
cleanSpans.forEach((span) => {
|
|
27
|
+
logger.debug(`Sending span <${span._id}> to plugin (Plugin #${i}) <${pluginResource.name}>`);
|
|
28
|
+
logger.debug(`Span: \n<${JSON.stringify(span, null, 2)}`);
|
|
29
|
+
//TODO: This should be called newSpan instead of newTrace
|
|
30
|
+
pluginResource.plugin.newTrace(span);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
if (err) {
|
|
34
|
+
console.error(err);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
setTimeout(() => resultCallback({ code: ExportResultCode.SUCCESS }), 0);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
console.error('Error exporting spans\n' + error.message + '\n' + error.stack);
|
|
43
|
+
return resultCallback({
|
|
44
|
+
code: ExportResultCode.FAILED,
|
|
45
|
+
error: new Error('Error exporting spans\n' + error.message + '\n' + error.stack),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
;
|
|
50
|
+
start() {
|
|
51
|
+
this._stopped = false;
|
|
52
|
+
}
|
|
53
|
+
;
|
|
54
|
+
stop() {
|
|
55
|
+
this._stopped = true;
|
|
56
|
+
}
|
|
57
|
+
;
|
|
58
|
+
isRunning() {
|
|
59
|
+
return !this._stopped;
|
|
60
|
+
}
|
|
61
|
+
;
|
|
62
|
+
shutdown() {
|
|
63
|
+
this._stopped = true;
|
|
64
|
+
this._spans = new dataStore();
|
|
65
|
+
return this.forceFlush();
|
|
66
|
+
}
|
|
67
|
+
;
|
|
68
|
+
/**
|
|
69
|
+
* Exports any pending spans in the exporter
|
|
70
|
+
*/
|
|
71
|
+
forceFlush() {
|
|
72
|
+
return Promise.resolve();
|
|
73
|
+
}
|
|
74
|
+
;
|
|
75
|
+
//err,docs
|
|
76
|
+
find(search, callback) {
|
|
77
|
+
this._spans.find(search, callback);
|
|
78
|
+
}
|
|
79
|
+
reset() {
|
|
80
|
+
this._spans = new dataStore();
|
|
81
|
+
}
|
|
82
|
+
;
|
|
83
|
+
getFinishedSpans() {
|
|
84
|
+
return this._spans.getAllData();
|
|
85
|
+
}
|
|
86
|
+
;
|
|
87
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { hrTimeToMicroseconds } from '@opentelemetry/core';
|
|
2
|
+
import { ExportResultCode } from '@opentelemetry/core';
|
|
3
|
+
import { removeCircularRefs, applyNesting } from '../utils/circular.js';
|
|
4
|
+
import Datastore from '@seald-io/nedb';
|
|
5
|
+
import MiniSearch from 'minisearch';
|
|
6
|
+
export class InMemoryLogRecordExporter {
|
|
7
|
+
constructor() {
|
|
8
|
+
this._db = new Datastore();
|
|
9
|
+
this._miniSearch = new MiniSearch({
|
|
10
|
+
fields: ['body'],
|
|
11
|
+
storeFields: ['_id'],
|
|
12
|
+
idField: '_id',
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
/*
|
|
16
|
+
* SUPER WARNING:
|
|
17
|
+
* Do NOT use console.log, console.error, or any logger inside this class's export function.
|
|
18
|
+
* Doing so will cause an infinite loop.
|
|
19
|
+
* Only console.dir is allowed, as it is not tracked by our log export implementation.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Export logs.
|
|
23
|
+
* @param logs
|
|
24
|
+
* @param resultCallback
|
|
25
|
+
*/
|
|
26
|
+
export(logs, resultCallback) {
|
|
27
|
+
const logsToInsert = logs.map(logRecord => {
|
|
28
|
+
// Remove circular references first, then apply nesting, then export info
|
|
29
|
+
const formattedLog = this._formatLogRecord(logRecord);
|
|
30
|
+
const cleanedLog = removeCircularRefs(formattedLog);
|
|
31
|
+
const nestedLog = applyNesting(cleanedLog);
|
|
32
|
+
return nestedLog;
|
|
33
|
+
});
|
|
34
|
+
this._db.insert(logsToInsert, (err, newDocs) => {
|
|
35
|
+
if (err) {
|
|
36
|
+
console.dir(err);
|
|
37
|
+
resultCallback({ code: ExportResultCode.FAILED });
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
// console.dir(newDocs, { depth: 3 });
|
|
41
|
+
newDocs.forEach((doc) => this._miniSearch.add(doc));
|
|
42
|
+
resultCallback({ code: ExportResultCode.SUCCESS });
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
reset() {
|
|
46
|
+
this._db = new Datastore();
|
|
47
|
+
this._miniSearch = new MiniSearch({
|
|
48
|
+
fields: ['body'],
|
|
49
|
+
storeFields: ['_id'],
|
|
50
|
+
idField: '_id',
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Shutdown the exporter.
|
|
55
|
+
*/
|
|
56
|
+
async shutdown() {
|
|
57
|
+
this._db = null;
|
|
58
|
+
this._miniSearch = null;
|
|
59
|
+
}
|
|
60
|
+
find(query, messageSearch, callback) {
|
|
61
|
+
if (messageSearch) {
|
|
62
|
+
const searchResults = this._miniSearch.search(messageSearch);
|
|
63
|
+
const ids = searchResults.map((result) => result._id);
|
|
64
|
+
console.dir(`MiniSearch found ${ids.length} results for search term "${messageSearch}"`, { depth: 3 });
|
|
65
|
+
// Add MiniSearch results to the query
|
|
66
|
+
query._id = { $in: ids };
|
|
67
|
+
}
|
|
68
|
+
this._db.find(query, callback);
|
|
69
|
+
}
|
|
70
|
+
getFinishedSpans() {
|
|
71
|
+
return this._db.getAllData();
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* @copyright The OpenTelemetry Authors
|
|
75
|
+
* @license Apache-2.0
|
|
76
|
+
* converts logRecord info into more readable format
|
|
77
|
+
* @param logRecord
|
|
78
|
+
*/
|
|
79
|
+
_formatLogRecord(logRecord) {
|
|
80
|
+
return {
|
|
81
|
+
resource: {
|
|
82
|
+
attributes: logRecord.resource.attributes,
|
|
83
|
+
},
|
|
84
|
+
instrumentationScope: logRecord.instrumentationScope,
|
|
85
|
+
timestamp: hrTimeToMicroseconds(logRecord.hrTime) || Date.now(),
|
|
86
|
+
traceId: logRecord.spanContext?.traceId,
|
|
87
|
+
spanId: logRecord.spanContext?.spanId,
|
|
88
|
+
traceFlags: logRecord.spanContext?.traceFlags,
|
|
89
|
+
severityText: logRecord.severityText,
|
|
90
|
+
severityNumber: logRecord.severityNumber,
|
|
91
|
+
body: logRecord.body,
|
|
92
|
+
attributes: logRecord.attributes,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|