@oas-tools/oas-telemetry 0.3.0 → 0.5.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/LICENSE +0 -0
- package/README.md +151 -133
- package/dist/client.cjs +14 -0
- package/dist/config.cjs +27 -0
- package/dist/controllers/pluginController.cjs +118 -0
- package/dist/controllers/telemetryController.cjs +92 -0
- package/dist/controllers/uiController.cjs +78 -0
- package/dist/exporters/InMemoryDbExporter.cjs +45 -42
- package/dist/exporters/consoleExporter.cjs +52 -0
- package/dist/exporters/dynamicExporter.cjs +64 -0
- package/dist/index.cjs +61 -248
- package/dist/middleware/auth.cjs +17 -0
- package/dist/middleware/authMiddleware.cjs +19 -0
- package/dist/openTelemetry.cjs +20 -0
- package/dist/routes/authRoutes.cjs +79 -0
- package/dist/routes/telemetryRoutes.cjs +31 -0
- package/{src/ui.js → dist/services/uiService.cjs} +1140 -813
- package/dist/telemetry.cjs +0 -0
- package/dist/types/exporters/InMemoryDbExporter.d.ts +16 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/telemetry.d.ts +2 -0
- package/dist/types/ui.d.ts +4 -0
- package/dist/ui.cjs +0 -0
- package/package.json +75 -71
- package/src/config.js +19 -0
- package/src/controllers/pluginController.js +115 -0
- package/src/controllers/telemetryController.js +68 -0
- package/src/controllers/uiController.js +69 -0
- package/src/dev/ui/login.html +32 -0
- package/src/exporters/InMemoryDbExporter.js +180 -175
- package/src/exporters/consoleExporter.js +47 -0
- package/src/exporters/dynamicExporter.js +62 -0
- package/src/index.js +85 -307
- package/src/middleware/authMiddleware.js +14 -0
- package/src/openTelemetry.js +22 -0
- package/src/routes/authRoutes.js +53 -0
- package/src/routes/telemetryRoutes.js +38 -0
- package/src/services/uiService.js +1520 -0
- package/src/telemetry.js +0 -25
|
@@ -17,6 +17,8 @@ if (process.env.OTDEBUG == "true") dbglog = console.log;
|
|
|
17
17
|
|
|
18
18
|
class InMemoryExporter {
|
|
19
19
|
constructor() {
|
|
20
|
+
// Overrided by dynamic exporter
|
|
21
|
+
_defineProperty(this, "plugins", []);
|
|
20
22
|
this._spans = new _nedb.default();
|
|
21
23
|
this._stopped = true;
|
|
22
24
|
}
|
|
@@ -27,15 +29,15 @@ class InMemoryExporter {
|
|
|
27
29
|
const cleanSpans = readableSpans.map(nestedSpan => removeCircularRefs(nestedSpan)) // to avoid JSON parsing error
|
|
28
30
|
.map(span => applyNesting(span)) // to avoid dot notation in keys (neDB does not support dot notation in keys)
|
|
29
31
|
.filter(span => !span.attributes?.http?.target?.includes("/telemetry")); // to avoid telemetry spans
|
|
30
|
-
|
|
31
32
|
// Insert spans into the in-memory database
|
|
32
33
|
this._spans.insert(cleanSpans, (err, newDoc) => {
|
|
33
|
-
|
|
34
|
+
// p = {name, plugin
|
|
35
|
+
this.plugins.forEach((pluginResource, i) => {
|
|
34
36
|
cleanSpans.forEach(t => {
|
|
35
|
-
dbglog(`Sending trace <${t._id}> to plugin (Plugin #${i}) <${
|
|
37
|
+
dbglog(`Sending trace <${t._id}> to plugin (Plugin #${i}) <${pluginResource.name}>`);
|
|
36
38
|
dbglog(`Trace: \n<${JSON.stringify(t, null, 2)}`);
|
|
37
39
|
//TODO: This should be called newSpan instead of newTrace
|
|
38
|
-
|
|
40
|
+
pluginResource.plugin.newTrace(t);
|
|
39
41
|
});
|
|
40
42
|
});
|
|
41
43
|
if (err) {
|
|
@@ -61,31 +63,32 @@ class InMemoryExporter {
|
|
|
61
63
|
stop() {
|
|
62
64
|
this._stopped = true;
|
|
63
65
|
}
|
|
66
|
+
isRunning() {
|
|
67
|
+
return !this._stopped;
|
|
68
|
+
}
|
|
64
69
|
shutdown() {
|
|
65
70
|
this._stopped = true;
|
|
66
71
|
this._spans = new _nedb.default();
|
|
67
72
|
return this.forceFlush();
|
|
68
73
|
}
|
|
69
|
-
/**
|
|
70
|
-
* Exports any pending spans in the exporter
|
|
74
|
+
/**
|
|
75
|
+
* Exports any pending spans in the exporter
|
|
71
76
|
*/
|
|
72
77
|
forceFlush() {
|
|
73
78
|
return Promise.resolve();
|
|
74
79
|
}
|
|
80
|
+
//err,docs
|
|
81
|
+
find(search, callback) {
|
|
82
|
+
this._spans.find(search, callback);
|
|
83
|
+
}
|
|
75
84
|
reset() {
|
|
76
85
|
this._spans = new _nedb.default();
|
|
77
86
|
}
|
|
78
87
|
getFinishedSpans() {
|
|
79
|
-
return this._spans;
|
|
80
|
-
}
|
|
81
|
-
activatePlugin(plugin) {
|
|
82
|
-
dbglog(`Activating plugin <${plugin.getName()}>...`);
|
|
83
|
-
InMemoryExporter.plugins.push(plugin);
|
|
84
|
-
dbglog(`Plugin <${plugin.getName()}> active (Total active plugins: ${InMemoryExporter.plugins.length})`);
|
|
88
|
+
return this._spans.getAllData();
|
|
85
89
|
}
|
|
86
90
|
}
|
|
87
91
|
exports.InMemoryExporter = InMemoryExporter;
|
|
88
|
-
_defineProperty(InMemoryExporter, "plugins", []);
|
|
89
92
|
function removeCircularRefs(obj) {
|
|
90
93
|
const seen = new WeakMap(); // Used to keep track of visited objects
|
|
91
94
|
|
|
@@ -111,30 +114,30 @@ function removeCircularRefs(obj) {
|
|
|
111
114
|
return JSON.parse(jsonString);
|
|
112
115
|
}
|
|
113
116
|
|
|
114
|
-
/**
|
|
115
|
-
* Recursively converts dot-separated keys in an object to nested objects.
|
|
116
|
-
*
|
|
117
|
-
* @param {Object} obj - The object to process.
|
|
118
|
-
* @returns {Object} - The object with all dot-separated keys converted to nested objects.
|
|
119
|
-
* @example
|
|
120
|
-
* // Input:
|
|
121
|
-
* // {
|
|
122
|
-
* // "http.method": "GET",
|
|
123
|
-
* // "http.url": "http://example.com",
|
|
124
|
-
* // "nested.obj.key": "value"
|
|
125
|
-
* // }
|
|
126
|
-
* // Output:
|
|
127
|
-
* // {
|
|
128
|
-
* // "http": {
|
|
129
|
-
* // "method": "GET",
|
|
130
|
-
* // "url": "http://example.com"
|
|
131
|
-
* // },
|
|
132
|
-
* // "nested": {
|
|
133
|
-
* // "obj": {
|
|
134
|
-
* // "key": "value"
|
|
135
|
-
* // }
|
|
136
|
-
* // }
|
|
137
|
-
* // }
|
|
117
|
+
/**
|
|
118
|
+
* Recursively converts dot-separated keys in an object to nested objects.
|
|
119
|
+
*
|
|
120
|
+
* @param {Object} obj - The object to process.
|
|
121
|
+
* @returns {Object} - The object with all dot-separated keys converted to nested objects.
|
|
122
|
+
* @example
|
|
123
|
+
* // Input:
|
|
124
|
+
* // {
|
|
125
|
+
* // "http.method": "GET",
|
|
126
|
+
* // "http.url": "http://example.com",
|
|
127
|
+
* // "nested.obj.key": "value"
|
|
128
|
+
* // }
|
|
129
|
+
* // Output:
|
|
130
|
+
* // {
|
|
131
|
+
* // "http": {
|
|
132
|
+
* // "method": "GET",
|
|
133
|
+
* // "url": "http://example.com"
|
|
134
|
+
* // },
|
|
135
|
+
* // "nested": {
|
|
136
|
+
* // "obj": {
|
|
137
|
+
* // "key": "value"
|
|
138
|
+
* // }
|
|
139
|
+
* // }
|
|
140
|
+
* // }
|
|
138
141
|
*/
|
|
139
142
|
function convertToNestedObject(obj) {
|
|
140
143
|
const result = {};
|
|
@@ -158,11 +161,11 @@ function convertToNestedObject(obj) {
|
|
|
158
161
|
return result;
|
|
159
162
|
}
|
|
160
163
|
|
|
161
|
-
/**
|
|
162
|
-
* Applies nesting to all dot-separated keys within an object.
|
|
163
|
-
*
|
|
164
|
-
* @param {Object} obj - The object to apply nesting to.
|
|
165
|
-
* @returns {Object} - The transformed object with nested structures.
|
|
164
|
+
/**
|
|
165
|
+
* Applies nesting to all dot-separated keys within an object.
|
|
166
|
+
*
|
|
167
|
+
* @param {Object} obj - The object to apply nesting to.
|
|
168
|
+
* @returns {Object} - The transformed object with nested structures.
|
|
166
169
|
*/
|
|
167
170
|
function applyNesting(obj) {
|
|
168
171
|
// Recursively apply convertToNestedObject to each level of the object
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.ConsoleExporter = void 0;
|
|
7
|
+
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
8
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
9
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
10
|
+
class ConsoleExporter {
|
|
11
|
+
constructor() {
|
|
12
|
+
// PLUGIN SYSTEM -----------------------------------------------------------
|
|
13
|
+
_defineProperty(this, "plugins", []);
|
|
14
|
+
}
|
|
15
|
+
// OPEN TELEMETRY EXPORTER INTERFACE ---------------------------------------
|
|
16
|
+
export(readableSpans, resultCallback) {
|
|
17
|
+
console.log('ConsoleExporter | Received spans: ', readableSpans.length);
|
|
18
|
+
setTimeout(() => resultCallback({
|
|
19
|
+
code: 0
|
|
20
|
+
}), 0);
|
|
21
|
+
}
|
|
22
|
+
shutdown() {
|
|
23
|
+
return this.forceFlush();
|
|
24
|
+
}
|
|
25
|
+
forceFlush() {
|
|
26
|
+
return Promise.resolve();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// OAS-TOOLS OAS-TELEMETRY EXPORTER INTERFACE ---------------------------------------
|
|
30
|
+
|
|
31
|
+
start() {
|
|
32
|
+
console.log("Exporter started");
|
|
33
|
+
}
|
|
34
|
+
stop() {
|
|
35
|
+
console.log("Exporter stopped");
|
|
36
|
+
}
|
|
37
|
+
reset() {
|
|
38
|
+
console.log("Exporter reset");
|
|
39
|
+
}
|
|
40
|
+
isRunning() {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
find(search, callback) {
|
|
44
|
+
console.log("Getting finished spans");
|
|
45
|
+
callback(null, []);
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
async getFinishedSpans() {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.ConsoleExporter = ConsoleExporter;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = exports.DynamicExporter = void 0;
|
|
7
|
+
var _consoleExporter = require("./consoleExporter.cjs");
|
|
8
|
+
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
9
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
10
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
11
|
+
/**
|
|
12
|
+
* DynamicExporter is a class that can be used to dynamically change the exporter used by OpenTelemetry.
|
|
13
|
+
* This is useful when you want to change the exporter at runtime.
|
|
14
|
+
* Links start, stop and export methods to the Real exporter.
|
|
15
|
+
*/
|
|
16
|
+
class DynamicExporter {
|
|
17
|
+
/**
|
|
18
|
+
* @returns {Array<PluginResource>} Returns the list of plugins registered in the exporter
|
|
19
|
+
*/
|
|
20
|
+
getPlugins() {
|
|
21
|
+
return this.exporter.plugins;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Registers a plugin in the exporter
|
|
26
|
+
* @param {PluginResource} pluginResource The plugin to be registered
|
|
27
|
+
* @returns {void}
|
|
28
|
+
*/
|
|
29
|
+
pushPlugin(pluginResource) {
|
|
30
|
+
if (!this.exporter.plugins) {
|
|
31
|
+
this.exporter.plugins = [];
|
|
32
|
+
}
|
|
33
|
+
this.exporter.plugins.push(pluginResource);
|
|
34
|
+
}
|
|
35
|
+
activatePlugin(pluginId) {
|
|
36
|
+
let plugins = this.exporter.plugins;
|
|
37
|
+
if (plugins) {
|
|
38
|
+
// plugin.active = true;
|
|
39
|
+
plugins.forEach(plugin => {
|
|
40
|
+
if (plugin.id === pluginId) {
|
|
41
|
+
plugin.active = true;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
constructor() {
|
|
47
|
+
_defineProperty(this, "exporter", void 0);
|
|
48
|
+
let defaultExporter = new _consoleExporter.ConsoleExporter();
|
|
49
|
+
this.exporter = defaultExporter;
|
|
50
|
+
this.export = (readableSpans, resultCallback) => defaultExporter.export(readableSpans, resultCallback);
|
|
51
|
+
this.shutdown = () => defaultExporter.shutdown();
|
|
52
|
+
this.forceFlush = () => defaultExporter.forceFlush();
|
|
53
|
+
}
|
|
54
|
+
changeExporter(newExporter) {
|
|
55
|
+
this.exporter = newExporter;
|
|
56
|
+
// OpenTelemetry methods
|
|
57
|
+
this.export = (readableSpans, resultCallback) => newExporter.export(readableSpans, resultCallback);
|
|
58
|
+
this.shutdown = () => newExporter.shutdown();
|
|
59
|
+
this.forceFlush = () => newExporter.forceFlush();
|
|
60
|
+
// Other methods should be called directly from the exporter: globalOasTlmConfig.dynamicExporter.exporter.method()
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
exports.DynamicExporter = DynamicExporter;
|
|
64
|
+
var _default = exports.default = DynamicExporter;
|
package/dist/index.cjs
CHANGED
|
@@ -4,264 +4,77 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = oasTelemetry;
|
|
7
|
-
|
|
7
|
+
require("./openTelemetry.cjs");
|
|
8
|
+
var _config = require("./config.cjs");
|
|
9
|
+
var _cookieParser = _interopRequireDefault(require("cookie-parser"));
|
|
8
10
|
var _express = require("express");
|
|
9
|
-
var
|
|
10
|
-
var
|
|
11
|
-
var
|
|
12
|
-
var
|
|
13
|
-
var _ui = _interopRequireDefault(require("./ui.cjs"));
|
|
14
|
-
var _axios = _interopRequireDefault(require("axios"));
|
|
15
|
-
var _importFromString = require("import-from-string");
|
|
11
|
+
var _authMiddleware = require("./middleware/authMiddleware.cjs");
|
|
12
|
+
var _authRoutes = _interopRequireDefault(require("./routes/authRoutes.cjs"));
|
|
13
|
+
var _telemetryRoutes = require("./routes/telemetryRoutes.cjs");
|
|
14
|
+
var _InMemoryDbExporter = require("./exporters/InMemoryDbExporter.cjs");
|
|
16
15
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
17
|
-
// telemetryMiddleware.js
|
|
18
|
-
|
|
19
16
|
let dbglog = () => {};
|
|
20
17
|
if (process.env.OTDEBUG == "true") dbglog = console.log;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Returns the Oas Telemetry middleware. The parameters are the same as `globalOasTlmConfig`.
|
|
21
|
+
* All parameters are optional. However, either `spec` or `specFileName` must be provided to enable endpoint filtering.
|
|
22
|
+
*
|
|
23
|
+
* @param {Object} OasTlmConfig Configuration object.
|
|
24
|
+
* @param {string} [OasTlmConfig.baseURL="/telemetry"] The base URL for the telemetry routes.
|
|
25
|
+
* @param {Object} [OasTlmConfig.spec] The OpenAPI spec object.
|
|
26
|
+
* @param {string} [OasTlmConfig.specFileName] Alternative to `spec`: the path to the OpenAPI spec file.
|
|
27
|
+
* @param {boolean} [OasTlmConfig.autoActivate=true] Whether to start telemetry automatically on load.
|
|
28
|
+
* @param {number} [OasTlmConfig.apiKeyMaxAge=1800000] The maximum age of the API key in milliseconds.
|
|
29
|
+
* @param {string} [OasTlmConfig.defaultApiKey] The default API key to use.
|
|
30
|
+
* @param {OasTlmExporter} [OasTlmConfig.exporter=InMemoryExporter] The exporter to use. Must implement the `OasTlmExporter` interface.
|
|
31
|
+
* @returns {Router} The middleware router for Oas Telemetry.
|
|
32
|
+
*/
|
|
33
|
+
function oasTelemetry(OasTlmConfig) {
|
|
34
|
+
const router = (0, _express.Router)();
|
|
35
|
+
if (process.env.OASTLM_MODULE_DISABLED === 'true') {
|
|
36
|
+
return router;
|
|
35
37
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
;
|
|
39
|
+
if (OasTlmConfig) {
|
|
40
|
+
console.log("User provided config");
|
|
41
|
+
// Global = user-provided || default, for each key
|
|
42
|
+
for (const key in _config.globalOasTlmConfig) {
|
|
43
|
+
_config.globalOasTlmConfig[key] = OasTlmConfig[key] ?? _config.globalOasTlmConfig[key];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
console.log("baseURL: ", _config.globalOasTlmConfig.baseURL);
|
|
47
|
+
_config.globalOasTlmConfig.dynamicExporter.changeExporter(OasTlmConfig.exporter ?? new _InMemoryDbExporter.InMemoryExporter());
|
|
48
|
+
if (_config.globalOasTlmConfig.spec) dbglog(`Spec content provided`);else {
|
|
49
|
+
if (_config.globalOasTlmConfig.specFileName != "") dbglog(`Spec file used for telemetry: ${_config.globalOasTlmConfig.specFileName}`);else {
|
|
38
50
|
console.error("No spec available !");
|
|
39
51
|
}
|
|
40
52
|
}
|
|
41
|
-
|
|
42
|
-
|
|
53
|
+
router.use((0, _cookieParser.default)());
|
|
54
|
+
const baseURL = _config.globalOasTlmConfig.baseURL;
|
|
43
55
|
router.use((0, _express.json)());
|
|
44
|
-
router.
|
|
45
|
-
router.
|
|
46
|
-
router.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
router.get(baseURL + "/status", statusTelemetry);
|
|
51
|
-
router.get(baseURL + "/reset", resetTelemetry);
|
|
52
|
-
router.get(baseURL + "/list", listTelemetry);
|
|
53
|
-
router.post(baseURL + "/find", findTelemetry);
|
|
54
|
-
router.get(baseURL + "/heapStats", heapStats);
|
|
55
|
-
router.get(baseURL + "/plugins", listPlugins);
|
|
56
|
-
router.post(baseURL + "/plugins", registerPlugin);
|
|
56
|
+
router.use(baseURL, _authRoutes.default);
|
|
57
|
+
router.use(baseURL, _authMiddleware.authMiddleware); // Add the auth middleware
|
|
58
|
+
router.use(baseURL, _telemetryRoutes.telemetryRoutes);
|
|
59
|
+
if (_config.globalOasTlmConfig.autoActivate) {
|
|
60
|
+
_config.globalOasTlmConfig.dynamicExporter.exporter?.start();
|
|
61
|
+
}
|
|
57
62
|
return router;
|
|
58
63
|
}
|
|
59
|
-
const apiPage = (req, res) => {
|
|
60
|
-
let text = `
|
|
61
|
-
<h1>Telemetry API routes:</h1>
|
|
62
|
-
<ul>
|
|
63
|
-
<li><a href="/telemetry/start">/telemetry/start</a></li>
|
|
64
|
-
<li><a href="/telemetry/stop">/telemetry/stop</a></li>
|
|
65
|
-
<li><a href="/telemetry/status">/telemetry/status</a></li>
|
|
66
|
-
<li><a href="/telemetry/reset">/telemetry/reset</a></li>
|
|
67
|
-
<li><a href="/telemetry/list">/telemetry/list</a></li>
|
|
68
|
-
<li><a href="/telemetry/heapStats">/telemetry/heapStats</a></li>
|
|
69
|
-
<li>/telemetry/find [POST]</li>
|
|
70
|
-
</ul>
|
|
71
|
-
`;
|
|
72
|
-
res.send(text);
|
|
73
|
-
};
|
|
74
|
-
const mainPage = (req, res) => {
|
|
75
|
-
res.set('Content-Type', 'text/html');
|
|
76
|
-
res.send((0, _ui.default)().main);
|
|
77
|
-
};
|
|
78
|
-
const detailPage = (req, res) => {
|
|
79
|
-
res.set('Content-Type', 'text/html');
|
|
80
|
-
res.send((0, _ui.default)().detail);
|
|
81
|
-
};
|
|
82
|
-
const specLoader = (req, res) => {
|
|
83
|
-
if (telemetryConfig.specFileName) {
|
|
84
|
-
try {
|
|
85
|
-
const data = (0, _fs.readFileSync)(telemetryConfig.specFileName, {
|
|
86
|
-
encoding: 'utf8',
|
|
87
|
-
flag: 'r'
|
|
88
|
-
});
|
|
89
|
-
const extension = _path.default.extname(telemetryConfig.specFileName);
|
|
90
|
-
let json = data;
|
|
91
|
-
if (extension == _jsYaml.default) json = JSON.stringify(_jsYaml.default.SafeLoad(data), null, 2);
|
|
92
|
-
res.setHeader('Content-Type', 'application/json');
|
|
93
|
-
res.send(json);
|
|
94
|
-
} catch (e) {
|
|
95
|
-
console.error(`ERROR loading spec file ${telemetryConfig.specFileName}: ${e}`);
|
|
96
|
-
}
|
|
97
|
-
} else {
|
|
98
|
-
if (telemetryConfig.spec) {
|
|
99
|
-
let spec = false;
|
|
100
|
-
try {
|
|
101
|
-
spec = JSON.parse(telemetryConfig.spec);
|
|
102
|
-
} catch (ej) {
|
|
103
|
-
try {
|
|
104
|
-
spec = JSON.stringify(_jsYaml.default.load(telemetryConfig.spec), null, 2);
|
|
105
|
-
} catch (ey) {
|
|
106
|
-
console.error(`Error parsing spec: ${ej} - ${ey}`);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
if (!spec) {
|
|
110
|
-
res.status(404);
|
|
111
|
-
} else {
|
|
112
|
-
res.setHeader('Content-Type', 'application/json');
|
|
113
|
-
res.send(spec);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
const startTelemetry = (req, res) => {
|
|
119
|
-
telemetryConfig.exporter.start();
|
|
120
|
-
res.send('Telemetry started');
|
|
121
|
-
};
|
|
122
|
-
const stopTelemetry = (req, res) => {
|
|
123
|
-
telemetryConfig.exporter.stop();
|
|
124
|
-
res.send('Telemetry stopped');
|
|
125
|
-
};
|
|
126
|
-
const statusTelemetry = (req, res) => {
|
|
127
|
-
const status = !telemetryConfig.exporter._stopped || false;
|
|
128
|
-
res.send({
|
|
129
|
-
active: status
|
|
130
|
-
});
|
|
131
|
-
};
|
|
132
|
-
const resetTelemetry = (req, res) => {
|
|
133
|
-
telemetryConfig.exporter.reset();
|
|
134
|
-
res.send('Telemetry reset');
|
|
135
|
-
};
|
|
136
|
-
const listTelemetry = (req, res) => {
|
|
137
|
-
const spansDB = telemetryConfig.exporter.getFinishedSpans();
|
|
138
|
-
spansDB.find({}, (err, docs) => {
|
|
139
|
-
if (err) {
|
|
140
|
-
console.error(err);
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
const spans = docs;
|
|
144
|
-
res.send({
|
|
145
|
-
spansCount: spans.length,
|
|
146
|
-
spans: spans
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
};
|
|
150
|
-
const heapStats = (req, res) => {
|
|
151
|
-
var heapStats = _v.default.getHeapStatistics();
|
|
152
64
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
search[regexId] = new RegExp(search[regexId]);
|
|
169
|
-
});
|
|
170
|
-
} catch (e) {
|
|
171
|
-
console.error(e);
|
|
172
|
-
res.status(404).send({
|
|
173
|
-
spansCount: 0,
|
|
174
|
-
spans: [],
|
|
175
|
-
error: e
|
|
176
|
-
});
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
spansDB.find(search, (err, docs) => {
|
|
180
|
-
if (err) {
|
|
181
|
-
console.error(err);
|
|
182
|
-
res.status(404).send({
|
|
183
|
-
spansCount: 0,
|
|
184
|
-
spans: [],
|
|
185
|
-
error: err
|
|
186
|
-
});
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
const spans = docs;
|
|
190
|
-
res.send({
|
|
191
|
-
spansCount: spans.length,
|
|
192
|
-
spans: spans
|
|
193
|
-
});
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
const listPlugins = (req, res) => {
|
|
198
|
-
res.send(plugins.map(p => {
|
|
199
|
-
return {
|
|
200
|
-
id: p.id,
|
|
201
|
-
url: p.url,
|
|
202
|
-
active: p.active
|
|
203
|
-
};
|
|
204
|
-
}));
|
|
205
|
-
};
|
|
206
|
-
const registerPlugin = async (req, res) => {
|
|
207
|
-
let pluginResource = req.body;
|
|
208
|
-
dbglog(`Plugin Registration Request: = ${JSON.stringify(req.body, null, 2)}...`);
|
|
209
|
-
dbglog(`Getting plugin at ${pluginResource.url}...`);
|
|
210
|
-
let pluginCode;
|
|
211
|
-
if (!pluginResource.url && !pluginResource.code) {
|
|
212
|
-
res.status(400).send(`Plugin code or URL must be provided`);
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
|
-
let module;
|
|
216
|
-
try {
|
|
217
|
-
if (pluginResource.code) {
|
|
218
|
-
pluginCode = pluginResource.code;
|
|
219
|
-
} else {
|
|
220
|
-
const response = await _axios.default.get(pluginResource.url);
|
|
221
|
-
pluginCode = response.data;
|
|
222
|
-
}
|
|
223
|
-
if (!pluginCode) {
|
|
224
|
-
res.status(400).send(`Plugin code could not be loaded`);
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
dbglog("Plugin size: " + pluginCode?.length);
|
|
228
|
-
if (pluginResource?.moduleFormat && pluginResource.moduleFormat.toUpperCase() == "ESM") {
|
|
229
|
-
console.log("ESM detected");
|
|
230
|
-
module = await (0, _importFromString.importFromString)(pluginCode);
|
|
231
|
-
} else {
|
|
232
|
-
console.log("CJS detected (default)");
|
|
233
|
-
module = await (0, _importFromString.requireFromString)(pluginCode);
|
|
234
|
-
console.log(module);
|
|
235
|
-
}
|
|
236
|
-
} catch (error) {
|
|
237
|
-
console.error(`Error loading plugin: ${error}`);
|
|
238
|
-
res.status(400).send(`Error loading plugin: ${error}`);
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
if (module.plugin == undefined) {
|
|
242
|
-
res.status(400).send(`Plugin code should export a "plugin" object`);
|
|
243
|
-
console.log("Error in plugin code: no plugin object exported");
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
for (let requiredFunction of ["load", "getName", "isConfigured"]) {
|
|
247
|
-
if (module.plugin[requiredFunction] == undefined) {
|
|
248
|
-
res.status(400).send(`The plugin code exports a "plugin" object, however it should have a "${requiredFunction}" method`);
|
|
249
|
-
console.log("Error in plugin code: some required functions are missing");
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
let plugin = module.plugin;
|
|
254
|
-
if (plugin.isConfigured()) {
|
|
255
|
-
dbglog(`Loaded plugin <${plugin.getName()}>`);
|
|
256
|
-
pluginResource.plugin = plugin;
|
|
257
|
-
pluginResource.name = plugin.getName();
|
|
258
|
-
pluginResource.active = true;
|
|
259
|
-
plugins.push(pluginResource);
|
|
260
|
-
_telemetry.inMemoryExporter.activatePlugin(pluginResource.plugin);
|
|
261
|
-
res.status(201).send(`Plugin registered`);
|
|
262
|
-
} else {
|
|
263
|
-
console.error(`Plugin <${plugin.getName()}> can not be configured`);
|
|
264
|
-
res.status(400).send(`Plugin configuration problem`);
|
|
265
|
-
}
|
|
266
|
-
};
|
|
65
|
+
/**
|
|
66
|
+
* @typedef OasTlmExporter
|
|
67
|
+
* Represents an exporter that processes and manages telemetry data.
|
|
68
|
+
* Any custom exporter must implement these methods.
|
|
69
|
+
*
|
|
70
|
+
* @method {void} start() Starts the exporter, allowing it to process data.
|
|
71
|
+
* @method {void} stop() Stops the exporter and halts data processing.
|
|
72
|
+
* @method {void} reset() Resets the internal state of the exporter (e.g., clears buffers or data stores).
|
|
73
|
+
* @method {boolean} isRunning() Returns whether the exporter is actively processing data.
|
|
74
|
+
* @method {Array} getFinishedSpans() Retrieves the collected spans from the exporter.
|
|
75
|
+
* @method {any} export(ReadableSpan, SpanExporterResultCallback) Exports spans.
|
|
76
|
+
* @method {Promise<void>} shutdown() Gracefully shuts down the exporter, flushing data if necessary.
|
|
77
|
+
* @method {Promise<void>} forceFlush() Exports any pending data that has not yet been processed.
|
|
78
|
+
* @property {Array} plugins An array of plugins that can be activated by the exporter.
|
|
79
|
+
*/
|
|
267
80
|
module.exports = exports.default;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = auth;
|
|
7
|
+
function auth(req, res, next) {
|
|
8
|
+
const apiKey = req.query.apiKey || req.body.apiKey;
|
|
9
|
+
if (apiKey === process.env.APIKEY) {
|
|
10
|
+
next();
|
|
11
|
+
} else {
|
|
12
|
+
res.status(401).send({
|
|
13
|
+
valid: false
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
module.exports = exports.default;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.authMiddleware = authMiddleware;
|
|
7
|
+
var _config = require("../config.cjs");
|
|
8
|
+
var _jsonwebtoken = _interopRequireDefault(require("jsonwebtoken"));
|
|
9
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
10
|
+
function authMiddleware(req, res, next) {
|
|
11
|
+
const apiKey = req.cookies.apiKey;
|
|
12
|
+
if (apiKey) {
|
|
13
|
+
const decoded = _jsonwebtoken.default.verify(apiKey, _config.globalOasTlmConfig.jwtSecret);
|
|
14
|
+
if (decoded.password === _config.globalOasTlmConfig.password) {
|
|
15
|
+
return next();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
res.status(401).redirect(_config.globalOasTlmConfig.baseURL + '/login');
|
|
19
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _sdkNode = require("@opentelemetry/sdk-node");
|
|
4
|
+
var _resources = require("@opentelemetry/resources");
|
|
5
|
+
var _instrumentationHttp = require("@opentelemetry/instrumentation-http");
|
|
6
|
+
var _config = require("./config.cjs");
|
|
7
|
+
// import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
|
|
8
|
+
|
|
9
|
+
// DynamicExporter allows changing to any exporter at runtime;
|
|
10
|
+
const traceExporter = _config.globalOasTlmConfig.dynamicExporter;
|
|
11
|
+
const sdk = new _sdkNode.NodeSDK({
|
|
12
|
+
resource: new _resources.Resource({
|
|
13
|
+
service: 'oas-telemetry-service'
|
|
14
|
+
}),
|
|
15
|
+
traceExporter,
|
|
16
|
+
instrumentations: [new _instrumentationHttp.HttpInstrumentation()]
|
|
17
|
+
});
|
|
18
|
+
if (process.env.OASTLM_MODULE_DISABLED !== 'true') {
|
|
19
|
+
sdk.start();
|
|
20
|
+
}
|