@oas-tools/oas-telemetry 0.2.0 → 0.2.2
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 +200 -200
- package/README.md +133 -133
- package/dist/exporters/InMemoryDbExporter.cjs +91 -12
- package/dist/index.cjs +88 -32
- package/dist/ui.cjs +676 -549
- package/package.json +69 -63
- package/src/exporters/InMemoryDbExporter.js +174 -89
- package/src/index.js +255 -190
- package/src/telemetry.js +25 -25
- package/src/ui.js +678 -552
package/README.md
CHANGED
|
@@ -1,133 +1,133 @@
|
|
|
1
|
-
# OAS TELEMETRY
|
|
2
|
-
|
|
3
|
-
OAS Telemetry offers an express middleware designed for collecting telemetry data using Open Telemetry in applications built using the OpenAPI Specification (OAS). This middleware allows developers to easily incorporate telemetry functionality into their APIs.
|
|
4
|
-
|
|
5
|
-
OAS Telemetry provides a set of endpoints that can be accessed to perform various actions related to telemetry data, such as starting and stopping data collection, resetting telemetry data, listing collected data, and searching for specific telemetry records. These endpoints can be easily integrated into an Express.js application, providing developers with a convenient way to manage and analyze telemetry data.
|
|
6
|
-
|
|
7
|
-
Additionally, OAS Telemetry offers customization options, allowing developers to configure the telemetry middleware according to their specific requirements.
|
|
8
|
-
|
|
9
|
-
Overall, OAS Telemetry will serve as a valuable tool for developers looking to gain insights into the operation and performance of their OAS-based APIs, enabling them to monitor, debug, and optimize their applications effectively.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
## Usage
|
|
16
|
-
To use the middelware add this two lines in your index.js (ESM):
|
|
17
|
-
```js
|
|
18
|
-
import oasTelemetry from 'oas-telemetry';
|
|
19
|
-
import {readFileSync} from 'fs';
|
|
20
|
-
|
|
21
|
-
app.use(oasTelemetry({
|
|
22
|
-
spec : readFileSync('./spec/oas.yaml',{ encoding: 'utf8', flag: 'r' })
|
|
23
|
-
}))
|
|
24
|
-
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## Custom Configuration
|
|
28
|
-
|
|
29
|
-
You can also customize the telemetry configuration by passing options to the middleware function. For example:
|
|
30
|
-
```js
|
|
31
|
-
const customTelemetryConfig = {
|
|
32
|
-
exporter: myCustomExporter,
|
|
33
|
-
spec: /* OAS content in json or yaml */
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
app.use(oasTelemetry(customTelemetryConfig));
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## Telemetry UI
|
|
40
|
-
|
|
41
|
-
You can access the telemetry UI in the endpoint ``/telemetry``
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
## API Telemetry Endpoints
|
|
45
|
-
|
|
46
|
-
OAS Telemetry middleware adds the following endpoints to your Express application:
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
- /telemetry/start: Start telemetry data collection.
|
|
50
|
-
- /telemetry/stop: Stop telemetry data collection.
|
|
51
|
-
- /telemetry/status: Get status of telemetry.
|
|
52
|
-
- /telemetry/reset: Reset telemetry data.
|
|
53
|
-
- /telemetry/list: List all telemetry data.
|
|
54
|
-
- /telemetry/find (POST): Search telemetry data.
|
|
55
|
-
- /telemetry/heapStats: Shows v8 heapStats.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
## Simple Example [ES Module](https://nodejs.org/docs/latest/api/esm.html) (*.mjs)
|
|
59
|
-
```js index.mjs
|
|
60
|
-
import oasTelemetry from '@oas-tools/oas-telemetry';
|
|
61
|
-
import express from 'express';
|
|
62
|
-
|
|
63
|
-
const app = express();
|
|
64
|
-
const port = 3000;
|
|
65
|
-
|
|
66
|
-
const spec = { "paths": {
|
|
67
|
-
"/api/v1/pets": {
|
|
68
|
-
"get": {
|
|
69
|
-
"summary": "Get pets",
|
|
70
|
-
"responses":{
|
|
71
|
-
"200": {
|
|
72
|
-
"description": "Success"
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
app.use(oasTelemetry({
|
|
81
|
-
spec : JSON.stringify(spec)
|
|
82
|
-
}))
|
|
83
|
-
|
|
84
|
-
app.use(express.json());
|
|
85
|
-
|
|
86
|
-
app.get("/api/v1/pets", (req, res) => {
|
|
87
|
-
res.send([{ name: "rocky"},{ name: "pikachu"}]);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
app.listen(port, () => {
|
|
91
|
-
console.log(`Example app listening at http://localhost:${port}`);
|
|
92
|
-
console.log(`Telemetry portal available at http://localhost:${port}/telemetry`);
|
|
93
|
-
});
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
## Simple Example [Common.js Module](https://nodejs.org/docs/latest/api/modules.html) (*.cjs)
|
|
97
|
-
```js index.cjs
|
|
98
|
-
let oasTelemetry = require('@oas-tools/oas-telemetry');
|
|
99
|
-
let express = require('express');
|
|
100
|
-
|
|
101
|
-
const app = express();
|
|
102
|
-
const port = 3000;
|
|
103
|
-
|
|
104
|
-
const spec = { "paths": {
|
|
105
|
-
"/api/v1/pets": {
|
|
106
|
-
"get": {
|
|
107
|
-
"summary": "Get pets",
|
|
108
|
-
"responses":{
|
|
109
|
-
"200": {
|
|
110
|
-
"description": "Success"
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
app.use(oasTelemetry({
|
|
119
|
-
spec : JSON.stringify(spec)
|
|
120
|
-
}))
|
|
121
|
-
|
|
122
|
-
app.use(express.json());
|
|
123
|
-
|
|
124
|
-
app.get("/api/v1/pets", (req, res) => {
|
|
125
|
-
res.send([{ name: "rocky"},{ name: "pikachu"}]);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
app.listen(port, () => {
|
|
129
|
-
console.log(`Example app listening at http://localhost:${port}`);
|
|
130
|
-
console.log(`Telemetry portal available at http://localhost:${port}/telemetry`);
|
|
131
|
-
});
|
|
132
|
-
```
|
|
133
|
-
|
|
1
|
+
# OAS TELEMETRY
|
|
2
|
+
|
|
3
|
+
OAS Telemetry offers an express middleware designed for collecting telemetry data using Open Telemetry in applications built using the OpenAPI Specification (OAS). This middleware allows developers to easily incorporate telemetry functionality into their APIs.
|
|
4
|
+
|
|
5
|
+
OAS Telemetry provides a set of endpoints that can be accessed to perform various actions related to telemetry data, such as starting and stopping data collection, resetting telemetry data, listing collected data, and searching for specific telemetry records. These endpoints can be easily integrated into an Express.js application, providing developers with a convenient way to manage and analyze telemetry data.
|
|
6
|
+
|
|
7
|
+
Additionally, OAS Telemetry offers customization options, allowing developers to configure the telemetry middleware according to their specific requirements.
|
|
8
|
+
|
|
9
|
+
Overall, OAS Telemetry will serve as a valuable tool for developers looking to gain insights into the operation and performance of their OAS-based APIs, enabling them to monitor, debug, and optimize their applications effectively.
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
To use the middelware add this two lines in your index.js (ESM):
|
|
17
|
+
```js
|
|
18
|
+
import oasTelemetry from 'oas-telemetry';
|
|
19
|
+
import {readFileSync} from 'fs';
|
|
20
|
+
|
|
21
|
+
app.use(oasTelemetry({
|
|
22
|
+
spec : readFileSync('./spec/oas.yaml',{ encoding: 'utf8', flag: 'r' })
|
|
23
|
+
}))
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Custom Configuration
|
|
28
|
+
|
|
29
|
+
You can also customize the telemetry configuration by passing options to the middleware function. For example:
|
|
30
|
+
```js
|
|
31
|
+
const customTelemetryConfig = {
|
|
32
|
+
exporter: myCustomExporter,
|
|
33
|
+
spec: /* OAS content in json or yaml */
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
app.use(oasTelemetry(customTelemetryConfig));
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Telemetry UI
|
|
40
|
+
|
|
41
|
+
You can access the telemetry UI in the endpoint ``/telemetry``
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
## API Telemetry Endpoints
|
|
45
|
+
|
|
46
|
+
OAS Telemetry middleware adds the following endpoints to your Express application:
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
- /telemetry/start: Start telemetry data collection.
|
|
50
|
+
- /telemetry/stop: Stop telemetry data collection.
|
|
51
|
+
- /telemetry/status: Get status of telemetry.
|
|
52
|
+
- /telemetry/reset: Reset telemetry data.
|
|
53
|
+
- /telemetry/list: List all telemetry data.
|
|
54
|
+
- /telemetry/find (POST): Search telemetry data.
|
|
55
|
+
- /telemetry/heapStats: Shows v8 heapStats.
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
## Simple Example [ES Module](https://nodejs.org/docs/latest/api/esm.html) (*.mjs)
|
|
59
|
+
```js index.mjs
|
|
60
|
+
import oasTelemetry from '@oas-tools/oas-telemetry';
|
|
61
|
+
import express from 'express';
|
|
62
|
+
|
|
63
|
+
const app = express();
|
|
64
|
+
const port = 3000;
|
|
65
|
+
|
|
66
|
+
const spec = { "paths": {
|
|
67
|
+
"/api/v1/pets": {
|
|
68
|
+
"get": {
|
|
69
|
+
"summary": "Get pets",
|
|
70
|
+
"responses":{
|
|
71
|
+
"200": {
|
|
72
|
+
"description": "Success"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
app.use(oasTelemetry({
|
|
81
|
+
spec : JSON.stringify(spec)
|
|
82
|
+
}))
|
|
83
|
+
|
|
84
|
+
app.use(express.json());
|
|
85
|
+
|
|
86
|
+
app.get("/api/v1/pets", (req, res) => {
|
|
87
|
+
res.send([{ name: "rocky"},{ name: "pikachu"}]);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
app.listen(port, () => {
|
|
91
|
+
console.log(`Example app listening at http://localhost:${port}`);
|
|
92
|
+
console.log(`Telemetry portal available at http://localhost:${port}/telemetry`);
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Simple Example [Common.js Module](https://nodejs.org/docs/latest/api/modules.html) (*.cjs)
|
|
97
|
+
```js index.cjs
|
|
98
|
+
let oasTelemetry = require('@oas-tools/oas-telemetry');
|
|
99
|
+
let express = require('express');
|
|
100
|
+
|
|
101
|
+
const app = express();
|
|
102
|
+
const port = 3000;
|
|
103
|
+
|
|
104
|
+
const spec = { "paths": {
|
|
105
|
+
"/api/v1/pets": {
|
|
106
|
+
"get": {
|
|
107
|
+
"summary": "Get pets",
|
|
108
|
+
"responses":{
|
|
109
|
+
"200": {
|
|
110
|
+
"description": "Success"
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
app.use(oasTelemetry({
|
|
119
|
+
spec : JSON.stringify(spec)
|
|
120
|
+
}))
|
|
121
|
+
|
|
122
|
+
app.use(express.json());
|
|
123
|
+
|
|
124
|
+
app.get("/api/v1/pets", (req, res) => {
|
|
125
|
+
res.send([{ name: "rocky"},{ name: "pikachu"}]);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
app.listen(port, () => {
|
|
129
|
+
console.log(`Example app listening at http://localhost:${port}`);
|
|
130
|
+
console.log(`Telemetry portal available at http://localhost:${port}/telemetry`);
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
@@ -7,21 +7,36 @@ exports.InMemoryExporter = void 0;
|
|
|
7
7
|
var _core = require("@opentelemetry/core");
|
|
8
8
|
var _nedb = _interopRequireDefault(require("nedb"));
|
|
9
9
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
10
|
+
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; }
|
|
11
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
12
|
+
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); }
|
|
13
|
+
let dbglog = () => {};
|
|
14
|
+
if (process.env.OTDEBUG == "true") dbglog = console.log;
|
|
15
|
+
|
|
10
16
|
//import in memory database
|
|
11
17
|
|
|
12
18
|
class InMemoryExporter {
|
|
13
19
|
constructor() {
|
|
14
20
|
this._spans = new _nedb.default();
|
|
15
|
-
this._stopped =
|
|
21
|
+
this._stopped = true;
|
|
16
22
|
}
|
|
17
23
|
export(readableSpans, resultCallback) {
|
|
18
24
|
try {
|
|
19
25
|
if (!this._stopped) {
|
|
20
|
-
//
|
|
21
|
-
const cleanSpans = readableSpans.map(
|
|
26
|
+
// Prepare spans to be inserted into the in-memory database (remove circular references and convert to nested objects)
|
|
27
|
+
const cleanSpans = readableSpans.map(nestedSpan => removeCircularRefs(nestedSpan)) // to avoid JSON parsing error
|
|
28
|
+
.map(span => applyNesting(span)) // to avoid dot notation in keys (neDB does not support dot notation in keys)
|
|
29
|
+
.filter(span => !span.attributes?.http?.target?.includes("/telemetry")); // to avoid telemetry spans
|
|
22
30
|
|
|
23
31
|
// Insert spans into the in-memory database
|
|
24
32
|
this._spans.insert(cleanSpans, (err, newDoc) => {
|
|
33
|
+
InMemoryExporter.plugins.forEach((p, i) => {
|
|
34
|
+
cleanSpans.forEach(t => {
|
|
35
|
+
dbglog(`Sending trace <${t._id}> to plugin (Plugin #${i}) <${p.name}>`);
|
|
36
|
+
dbglog(`Trace: \n<${JSON.stringify(t, null, 2)}`);
|
|
37
|
+
p.newTrace(t);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
25
40
|
if (err) {
|
|
26
41
|
console.error(err);
|
|
27
42
|
return;
|
|
@@ -50,8 +65,8 @@ class InMemoryExporter {
|
|
|
50
65
|
this._spans = new _nedb.default();
|
|
51
66
|
return this.forceFlush();
|
|
52
67
|
}
|
|
53
|
-
/**
|
|
54
|
-
* Exports any pending spans in the exporter
|
|
68
|
+
/**
|
|
69
|
+
* Exports any pending spans in the exporter
|
|
55
70
|
*/
|
|
56
71
|
forceFlush() {
|
|
57
72
|
return Promise.resolve();
|
|
@@ -62,9 +77,15 @@ class InMemoryExporter {
|
|
|
62
77
|
getFinishedSpans() {
|
|
63
78
|
return this._spans;
|
|
64
79
|
}
|
|
80
|
+
activatePlugin(plugin) {
|
|
81
|
+
dbglog(`Activating plugin <${plugin.getName()}>...`);
|
|
82
|
+
InMemoryExporter.plugins.push(plugin);
|
|
83
|
+
dbglog(`Plugin <${plugin.getName()}> active (Total active plugins: ${InMemoryExporter.plugins.length})`);
|
|
84
|
+
}
|
|
65
85
|
}
|
|
66
86
|
exports.InMemoryExporter = InMemoryExporter;
|
|
67
|
-
|
|
87
|
+
_defineProperty(InMemoryExporter, "plugins", []);
|
|
88
|
+
function removeCircularRefs(obj) {
|
|
68
89
|
const seen = new WeakMap(); // Used to keep track of visited objects
|
|
69
90
|
|
|
70
91
|
// Replacer function to handle circular references
|
|
@@ -86,10 +107,68 @@ function removeCircular(obj) {
|
|
|
86
107
|
// Convert the object to a string and then parse it back
|
|
87
108
|
// This will trigger the replacer function to handle circular references
|
|
88
109
|
const jsonString = JSON.stringify(obj, replacer);
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
110
|
+
return JSON.parse(jsonString);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Recursively converts dot-separated keys in an object to nested objects.
|
|
115
|
+
*
|
|
116
|
+
* @param {Object} obj - The object to process.
|
|
117
|
+
* @returns {Object} - The object with all dot-separated keys converted to nested objects.
|
|
118
|
+
* @example
|
|
119
|
+
* // Input:
|
|
120
|
+
* // {
|
|
121
|
+
* // "http.method": "GET",
|
|
122
|
+
* // "http.url": "http://example.com",
|
|
123
|
+
* // "nested.obj.key": "value"
|
|
124
|
+
* // }
|
|
125
|
+
* // Output:
|
|
126
|
+
* // {
|
|
127
|
+
* // "http": {
|
|
128
|
+
* // "method": "GET",
|
|
129
|
+
* // "url": "http://example.com"
|
|
130
|
+
* // },
|
|
131
|
+
* // "nested": {
|
|
132
|
+
* // "obj": {
|
|
133
|
+
* // "key": "value"
|
|
134
|
+
* // }
|
|
135
|
+
* // }
|
|
136
|
+
* // }
|
|
137
|
+
*/
|
|
138
|
+
function convertToNestedObject(obj) {
|
|
139
|
+
const result = {};
|
|
140
|
+
for (const key in obj) {
|
|
141
|
+
const keys = key.split('.');
|
|
142
|
+
let temp = result;
|
|
143
|
+
for (let i = 0; i < keys.length; i++) {
|
|
144
|
+
const currentKey = keys[i];
|
|
145
|
+
if (i === keys.length - 1) {
|
|
146
|
+
// Last key, set the value
|
|
147
|
+
temp[currentKey] = obj[key];
|
|
148
|
+
} else {
|
|
149
|
+
// Intermediate key, ensure the object exists
|
|
150
|
+
if (!temp[currentKey]) {
|
|
151
|
+
temp[currentKey] = {};
|
|
152
|
+
}
|
|
153
|
+
temp = temp[currentKey];
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Applies nesting to all dot-separated keys within an object.
|
|
162
|
+
*
|
|
163
|
+
* @param {Object} obj - The object to apply nesting to.
|
|
164
|
+
* @returns {Object} - The transformed object with nested structures.
|
|
165
|
+
*/
|
|
166
|
+
function applyNesting(obj) {
|
|
167
|
+
// Recursively apply convertToNestedObject to each level of the object
|
|
168
|
+
for (const key in obj) {
|
|
169
|
+
if (typeof obj[key] === 'object' && obj[key] !== null) {
|
|
170
|
+
obj[key] = applyNesting(obj[key]);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return convertToNestedObject(obj);
|
|
95
174
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -10,11 +10,14 @@ var _v = _interopRequireDefault(require("v8"));
|
|
|
10
10
|
var _fs = require("fs");
|
|
11
11
|
var _path = _interopRequireDefault(require("path"));
|
|
12
12
|
var _jsYaml = _interopRequireDefault(require("js-yaml"));
|
|
13
|
-
var _url = require("url");
|
|
14
13
|
var _ui = _interopRequireDefault(require("./ui.cjs"));
|
|
14
|
+
var _axios = _interopRequireDefault(require("axios"));
|
|
15
15
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
16
16
|
// telemetryMiddleware.js
|
|
17
17
|
|
|
18
|
+
let dbglog = () => {};
|
|
19
|
+
if (process.env.OTDEBUG == "true") dbglog = console.log;
|
|
20
|
+
let plugins = [];
|
|
18
21
|
let telemetryStatus = {
|
|
19
22
|
active: true
|
|
20
23
|
};
|
|
@@ -25,19 +28,18 @@ let telemetryConfig = {
|
|
|
25
28
|
};
|
|
26
29
|
function oasTelemetry(tlConfig) {
|
|
27
30
|
if (tlConfig) {
|
|
28
|
-
|
|
31
|
+
dbglog('Telemetry config provided');
|
|
29
32
|
telemetryConfig = tlConfig;
|
|
30
33
|
if (telemetryConfig.exporter == undefined) telemetryConfig.exporter = _telemetry.inMemoryExporter;
|
|
31
34
|
}
|
|
32
|
-
if (telemetryConfig.spec)
|
|
33
|
-
if (telemetryConfig.specFileName != "")
|
|
34
|
-
console.
|
|
35
|
+
if (telemetryConfig.spec) dbglog(`Spec content provided`);else {
|
|
36
|
+
if (telemetryConfig.specFileName != "") dbglog(`Spec file used for telemetry: ${telemetryConfig.specFileName}`);else {
|
|
37
|
+
console.error("No spec available !");
|
|
35
38
|
}
|
|
36
39
|
}
|
|
37
40
|
const router = (0, _express.Router)();
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
if (telemetryConfig.baseURL) baseURL = telemetryConfig.baseURL;
|
|
42
|
+
router.use((0, _express.json)());
|
|
41
43
|
router.get(baseURL, mainPage);
|
|
42
44
|
router.get(baseURL + "/detail/*", detailPage);
|
|
43
45
|
router.get(baseURL + "/spec", specLoader);
|
|
@@ -49,6 +51,8 @@ function oasTelemetry(tlConfig) {
|
|
|
49
51
|
router.get(baseURL + "/list", listTelemetry);
|
|
50
52
|
router.post(baseURL + "/find", findTelemetry);
|
|
51
53
|
router.get(baseURL + "/heapStats", heapStats);
|
|
54
|
+
router.get(baseURL + "/plugins", listPlugins);
|
|
55
|
+
router.post(baseURL + "/plugins", registerPlugin);
|
|
52
56
|
return router;
|
|
53
57
|
}
|
|
54
58
|
const apiPage = (req, res) => {
|
|
@@ -87,7 +91,7 @@ const specLoader = (req, res) => {
|
|
|
87
91
|
res.setHeader('Content-Type', 'application/json');
|
|
88
92
|
res.send(json);
|
|
89
93
|
} catch (e) {
|
|
90
|
-
console.
|
|
94
|
+
console.error(`ERROR loading spec file ${telemetryConfig.specFileName}: ${e}`);
|
|
91
95
|
}
|
|
92
96
|
} else {
|
|
93
97
|
if (telemetryConfig.spec) {
|
|
@@ -98,7 +102,7 @@ const specLoader = (req, res) => {
|
|
|
98
102
|
try {
|
|
99
103
|
spec = JSON.stringify(_jsYaml.default.load(telemetryConfig.spec), null, 2);
|
|
100
104
|
} catch (ey) {
|
|
101
|
-
console.
|
|
105
|
+
console.error(`Error parsing spec: ${ej} - ${ey}`);
|
|
102
106
|
}
|
|
103
107
|
}
|
|
104
108
|
if (!spec) {
|
|
@@ -112,16 +116,17 @@ const specLoader = (req, res) => {
|
|
|
112
116
|
};
|
|
113
117
|
const startTelemetry = (req, res) => {
|
|
114
118
|
telemetryConfig.exporter.start();
|
|
115
|
-
telemetryStatus.active = true;
|
|
116
119
|
res.send('Telemetry started');
|
|
117
120
|
};
|
|
118
121
|
const stopTelemetry = (req, res) => {
|
|
119
122
|
telemetryConfig.exporter.stop();
|
|
120
|
-
telemetryStatus.active = false;
|
|
121
123
|
res.send('Telemetry stopped');
|
|
122
124
|
};
|
|
123
125
|
const statusTelemetry = (req, res) => {
|
|
124
|
-
|
|
126
|
+
const status = !telemetryConfig.exporter._stopped || false;
|
|
127
|
+
res.send({
|
|
128
|
+
active: status
|
|
129
|
+
});
|
|
125
130
|
};
|
|
126
131
|
const resetTelemetry = (req, res) => {
|
|
127
132
|
telemetryConfig.exporter.reset();
|
|
@@ -141,25 +146,6 @@ const listTelemetry = (req, res) => {
|
|
|
141
146
|
});
|
|
142
147
|
});
|
|
143
148
|
};
|
|
144
|
-
const findTelemetry = (req, res) => {
|
|
145
|
-
const spansDB = telemetryConfig.exporter.getFinishedSpans();
|
|
146
|
-
const search = req.body;
|
|
147
|
-
spansDB.find(search, (err, docs) => {
|
|
148
|
-
if (err) {
|
|
149
|
-
console.error(err);
|
|
150
|
-
res.send({
|
|
151
|
-
spansCount: "error",
|
|
152
|
-
spans: []
|
|
153
|
-
});
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
const spans = docs;
|
|
157
|
-
res.send({
|
|
158
|
-
spansCount: spans.length,
|
|
159
|
-
spans: spans
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
};
|
|
163
149
|
const heapStats = (req, res) => {
|
|
164
150
|
var heapStats = _v.default.getHeapStatistics();
|
|
165
151
|
|
|
@@ -171,4 +157,74 @@ const heapStats = (req, res) => {
|
|
|
171
157
|
roundedHeapStats['units'] = 'MB';
|
|
172
158
|
res.send(roundedHeapStats);
|
|
173
159
|
};
|
|
160
|
+
const findTelemetry = (req, res) => {
|
|
161
|
+
const spansDB = telemetryConfig.exporter.getFinishedSpans();
|
|
162
|
+
const body = req.body;
|
|
163
|
+
const search = body?.search ? body.search : {};
|
|
164
|
+
if (body?.flags?.containsRegex) {
|
|
165
|
+
try {
|
|
166
|
+
body.config?.regexIds?.forEach(regexId => {
|
|
167
|
+
search[regexId] = new RegExp(search[regexId]);
|
|
168
|
+
});
|
|
169
|
+
} catch (e) {
|
|
170
|
+
console.error(e);
|
|
171
|
+
res.status(404).send({
|
|
172
|
+
spansCount: 0,
|
|
173
|
+
spans: [],
|
|
174
|
+
error: e
|
|
175
|
+
});
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
spansDB.find(search, (err, docs) => {
|
|
179
|
+
if (err) {
|
|
180
|
+
console.error(err);
|
|
181
|
+
res.status(404).send({
|
|
182
|
+
spansCount: 0,
|
|
183
|
+
spans: [],
|
|
184
|
+
error: err
|
|
185
|
+
});
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const spans = docs;
|
|
189
|
+
res.send({
|
|
190
|
+
spansCount: spans.length,
|
|
191
|
+
spans: spans
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
const listPlugins = (req, res) => {
|
|
197
|
+
res.send(plugins.map(p => {
|
|
198
|
+
return {
|
|
199
|
+
id: p.id,
|
|
200
|
+
url: p.url,
|
|
201
|
+
active: p.active
|
|
202
|
+
};
|
|
203
|
+
}));
|
|
204
|
+
};
|
|
205
|
+
const registerPlugin = (req, res) => {
|
|
206
|
+
let pluginResource = req.body;
|
|
207
|
+
dbglog(`Plugin Registration Request: = ${JSON.stringify(req.body, null, 2)}...`);
|
|
208
|
+
dbglog(`Getting plugin at ${pluginResource.url}...`);
|
|
209
|
+
_axios.default.get(pluginResource.url).then(response => {
|
|
210
|
+
dbglog(`Plugin fetched.`);
|
|
211
|
+
const pluginCode = response.data;
|
|
212
|
+
dbglog("Plugin size: " + pluginCode.length);
|
|
213
|
+
var plugin;
|
|
214
|
+
eval(pluginCode);
|
|
215
|
+
plugin.load(pluginResource.config);
|
|
216
|
+
if (plugin.isConfigured()) {
|
|
217
|
+
dbglog(`Loaded plugin <${plugin.getName()}>`);
|
|
218
|
+
pluginResource.plugin = plugin;
|
|
219
|
+
pluginResource.name = plugin.getName();
|
|
220
|
+
pluginResource.active = true;
|
|
221
|
+
plugins.push(pluginResource);
|
|
222
|
+
_telemetry.inMemoryExporter.activatePlugin(pluginResource.plugin);
|
|
223
|
+
res.status(201).send(`Plugin registered`);
|
|
224
|
+
} else {
|
|
225
|
+
console.error(`Plugin <${plugin.getName()}> can not be configured`);
|
|
226
|
+
res.status(400).send(`Plugin configuration problem`);
|
|
227
|
+
}
|
|
228
|
+
}).catch(err => console.error("registerPlugin:" + err));
|
|
229
|
+
};
|
|
174
230
|
module.exports = exports.default;
|