@oas-tools/oas-telemetry 0.5.2 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -8
- package/dist/config.cjs +5 -0
- package/dist/controllers/metricsController.cjs +48 -0
- package/dist/exporters/InMemoryDBMetricsExporter.cjs +101 -0
- package/dist/index.cjs +2 -0
- package/dist/openTelemetry.cjs +24 -1
- package/dist/routes/metricsRoutes.cjs +15 -0
- package/dist/systemMetrics.cjs +97 -0
- package/package.json +2 -1
- package/src/config.js +4 -0
- package/src/controllers/metricsController.js +30 -0
- package/src/exporters/InMemoryDBMetricsExporter.js +111 -0
- package/src/index.js +3 -1
- package/src/openTelemetry.js +37 -15
- package/src/routes/metricsRoutes.js +15 -0
- package/src/systemMetrics.js +102 -0
package/README.md
CHANGED
|
@@ -10,25 +10,22 @@ Overall, **OAS Telemetry** will serve as a valuable tool for developers looking
|
|
|
10
10
|
|
|
11
11
|
The package now supports both **ES Module (ESM)** and **CommonJS (CJS)** formats, making it compatible with a wide range of applications. Furthermore, **OAS Telemetry** provides a range of plugins to extend its functionality, enabling developers to tailor telemetry data collection, alerting, and reporting to meet specific requirements. See the [Telemetry Plugins](#telemetry-plugins) section for more information.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
13
|
## Usage
|
|
17
14
|
|
|
18
15
|
This section provides an overview of how to install and integrate **OAS Telemetry** into your EXISTING **Express.js** application. If you want to create a new example express application with **OAS Telemetry** integrated, refer to the [Full Examples](#full-examples) section at the end of this document.
|
|
19
16
|
|
|
20
|
-
|
|
21
17
|
First, install the package using npm:
|
|
18
|
+
|
|
22
19
|
```sh
|
|
23
20
|
npm install @oas-tools/oas-telemetry
|
|
24
21
|
```
|
|
25
22
|
|
|
26
|
-
|
|
27
23
|
You can integrate the middleware into your Express application. The `spec` option is the OpenAPI Specification (OAS) content in JSON or YAML format. While this configuration is optional, it is recommended for the UI to function correctly.
|
|
28
24
|
|
|
29
25
|
### Using ES Modules (ESM)
|
|
30
26
|
|
|
31
27
|
Add the following lines to your `index.js` file:
|
|
28
|
+
|
|
32
29
|
```js
|
|
33
30
|
// This import MUST be at the top of the file
|
|
34
31
|
import oasTelemetry from '@oas-tools/oas-telemetry';
|
|
@@ -44,6 +41,7 @@ app.use(oasTelemetry({
|
|
|
44
41
|
### Using CommonJS
|
|
45
42
|
|
|
46
43
|
Add the following lines to your `index.js` file:
|
|
44
|
+
|
|
47
45
|
```js
|
|
48
46
|
// This require MUST be at the top of the file
|
|
49
47
|
const oasTelemetry = require('@oas-tools/oas-telemetry');
|
|
@@ -61,6 +59,7 @@ For complete examples of a working API with OAS Telemetry enabled, refer to the
|
|
|
61
59
|
## Custom Configuration
|
|
62
60
|
|
|
63
61
|
You can also customize the telemetry configuration by passing options to the middleware function. For example:
|
|
62
|
+
|
|
64
63
|
```js
|
|
65
64
|
const customTelemetryConfig = {
|
|
66
65
|
spec: /* OAS content in json or yaml */, // Highly recommended
|
|
@@ -82,6 +81,52 @@ app.use(oasTelemetry(customTelemetryConfig));
|
|
|
82
81
|
|
|
83
82
|
You can access the telemetry UI in the endpoint `/telemetry` (or `/custom-telemetry` if you set the `baseURL` option). This UI provides a user-friendly interface to interact with the telemetry data collected by the middleware.
|
|
84
83
|
|
|
84
|
+
## Metrics Development (Temporary)
|
|
85
|
+
|
|
86
|
+
This feature is currently in development. The following endpoints are available under <baseURL>/metrics (e.g., /telemetry/metrics):
|
|
87
|
+
|
|
88
|
+
- GET /
|
|
89
|
+
- POST /find
|
|
90
|
+
- GET /reset
|
|
91
|
+
|
|
92
|
+
Expect an array of metrics objects. Each object includes data like a timestamp, cpuUsageData, processCpuUsageData, memoryData, and processMemoryData. Example snippet for one CPU core (followed by others in the array):
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"timestamp": 1741717005911,
|
|
97
|
+
"cpuUsageData": [
|
|
98
|
+
{
|
|
99
|
+
"cpuNumber": "0",
|
|
100
|
+
"idle": 60486.234000000004,
|
|
101
|
+
"user": 1364.515,
|
|
102
|
+
"system": 1246.796,
|
|
103
|
+
"interrupt": 167,
|
|
104
|
+
"nice": 0,
|
|
105
|
+
"userP": 0.009375623379214043,
|
|
106
|
+
"systemP": 0.002992220227408737,
|
|
107
|
+
"idleP": 0.9850388988629563,
|
|
108
|
+
"interruptP": 0,
|
|
109
|
+
"niceP": 0
|
|
110
|
+
}
|
|
111
|
+
],
|
|
112
|
+
"processCpuUsageData": {
|
|
113
|
+
"user": 0.968,
|
|
114
|
+
"system": 0.32799999999999996,
|
|
115
|
+
"userP": 0,
|
|
116
|
+
"systemP": 0
|
|
117
|
+
},
|
|
118
|
+
"memoryData": {
|
|
119
|
+
"used": 15726522368,
|
|
120
|
+
"free": 18437427200,
|
|
121
|
+
"usedP": 0.4603250668280579,
|
|
122
|
+
"freeP": 0.539674933171942
|
|
123
|
+
},
|
|
124
|
+
"processMemoryData": 75988992,
|
|
125
|
+
"_id": "6mXKM8uK7xSOqJVT"
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The shape of these objects may change as development continues.
|
|
85
130
|
|
|
86
131
|
## API Telemetry Endpoints
|
|
87
132
|
|
|
@@ -104,12 +149,12 @@ OAS Telemetry supports a range of plugins to extend its functionality, allowing
|
|
|
104
149
|
One example plugin is the **Outlier Alert Over Messaging** plugin, which can be configured to send anomaly alerts to messaging platforms like Telegram. This plugin is especially useful for monitoring abnormal response times in your API, notifying selected channels to allow rapid responses to potential issues. For setup details, refer to its [README documentation](https://github.com/oas-tools/oas-telemetry-plugin-outlier-messaging/blob/main/README.md).
|
|
105
150
|
|
|
106
151
|
OAS Telemetry plugins are flexible and support both ES Modules (ESM) and CommonJS (CJS) formats, regardless of whether your application is using ESM or CJS. This compatibility ensures that plugins work seamlessly in all configurations:
|
|
152
|
+
|
|
107
153
|
- ESM applications can use plugins in either ESM or CJS format.
|
|
108
154
|
- CJS applications can use plugins in either CJS or ESM format.
|
|
109
155
|
|
|
110
156
|
This flexibility makes it easy to incorporate a wide variety of plugins in your preferred module system.
|
|
111
157
|
|
|
112
|
-
|
|
113
158
|
## Accessing Telemetry Data
|
|
114
159
|
|
|
115
160
|
Using OAS Telemetry, you can access telemetry data through the UI, the `/telemetry/list` endpoint, or the `/telemetry/find` endpoint with a POST request using a MongoDB search syntax.
|
|
@@ -117,7 +162,9 @@ Using OAS Telemetry, you can access telemetry data through the UI, the `/telemet
|
|
|
117
162
|
Note: if authentication is enabled, you must provide the correct credentials to access the telemetry data.
|
|
118
163
|
|
|
119
164
|
### Simple Search Example
|
|
165
|
+
|
|
120
166
|
To perform a simple search, send a POST request to the `/telemetry/find` endpoint with the following JSON payload:
|
|
167
|
+
|
|
121
168
|
```json
|
|
122
169
|
{
|
|
123
170
|
"search": {
|
|
@@ -132,7 +179,9 @@ To perform a simple search, send a POST request to the `/telemetry/find` endpoin
|
|
|
132
179
|
```
|
|
133
180
|
|
|
134
181
|
### Complex Search Example
|
|
182
|
+
|
|
135
183
|
For more complex searches using regex, additional parsing on the server and extra attributes in the POST request are required. Send a POST request to the `/telemetry/find` endpoint with the following JSON payload:
|
|
184
|
+
|
|
136
185
|
```json
|
|
137
186
|
{
|
|
138
187
|
"flags": {
|
|
@@ -153,19 +202,25 @@ For more complex searches using regex, additional parsing on the server and extr
|
|
|
153
202
|
```
|
|
154
203
|
|
|
155
204
|
## Full Examples
|
|
205
|
+
|
|
156
206
|
To run these examples, follow these steps:
|
|
157
207
|
|
|
158
208
|
1. Create a new folder for your project.
|
|
159
209
|
2. Navigate to the folder and initialize a new Node.js project:
|
|
210
|
+
|
|
160
211
|
```sh
|
|
161
212
|
npm init -y
|
|
162
213
|
```
|
|
214
|
+
|
|
163
215
|
3. Install the **OAS Telemetry** package:
|
|
216
|
+
|
|
164
217
|
```sh
|
|
165
218
|
npm install @oas-tools/oas-telemetry
|
|
166
219
|
```
|
|
220
|
+
|
|
167
221
|
4. Save the example code as `index.js` in the project folder.
|
|
168
222
|
5. Run the application:
|
|
223
|
+
|
|
169
224
|
```sh
|
|
170
225
|
node index.js
|
|
171
226
|
```
|
|
@@ -173,6 +228,7 @@ To run these examples, follow these steps:
|
|
|
173
228
|
Your project folder should now contain the necessary files to run the example with **OAS Telemetry** integrated.
|
|
174
229
|
|
|
175
230
|
### Simple Example [ES Module](https://nodejs.org/docs/latest/api/esm.html) (*.mjs)
|
|
231
|
+
|
|
176
232
|
```js index.mjs
|
|
177
233
|
import oasTelemetry from '@oas-tools/oas-telemetry';
|
|
178
234
|
import express from 'express';
|
|
@@ -280,6 +336,7 @@ app.get("/api/v1/clinics", (req, res) => {
|
|
|
280
336
|
```
|
|
281
337
|
|
|
282
338
|
### Simple Example [Common.js Module](https://nodejs.org/docs/latest/api/modules.html) (*.cjs)
|
|
339
|
+
|
|
283
340
|
```js index.cjs
|
|
284
341
|
let oasTelemetry = require('@oas-tools/oas-telemetry');
|
|
285
342
|
let express = require('express');
|
|
@@ -383,5 +440,3 @@ app.get("/api/v1/clinics", (req, res) => {
|
|
|
383
440
|
res.send(clinics);
|
|
384
441
|
});
|
|
385
442
|
```
|
|
386
|
-
|
|
387
|
-
|
package/dist/config.cjs
CHANGED
|
@@ -4,13 +4,18 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.globalOasTlmConfig = exports.default = void 0;
|
|
7
|
+
var _api = require("@opentelemetry/api");
|
|
7
8
|
var _dynamicExporter = _interopRequireDefault(require("./exporters/dynamicExporter.cjs"));
|
|
9
|
+
var _InMemoryDBMetricsExporter = require("./exporters/InMemoryDBMetricsExporter.cjs");
|
|
8
10
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
9
11
|
//Environment variables
|
|
10
12
|
//OASTLM_MODULE_DISABLED = 'true' //Disables the module (empty middleware and no tracing)
|
|
11
13
|
|
|
12
14
|
const globalOasTlmConfig = exports.globalOasTlmConfig = {
|
|
13
15
|
dynamicExporter: new _dynamicExporter.default(),
|
|
16
|
+
metricsExporter: new _InMemoryDBMetricsExporter.InMemoryDBMetricsExporter(),
|
|
17
|
+
systemMetricsInterval: 1000 * 5,
|
|
18
|
+
// 5 seconds
|
|
14
19
|
baseURL: "/telemetry",
|
|
15
20
|
spec: null,
|
|
16
21
|
specFileName: "",
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.resetMetrics = exports.listMetrics = exports.findMetrics = void 0;
|
|
7
|
+
var _config = require("../config.cjs");
|
|
8
|
+
const listMetrics = async (req, res) => {
|
|
9
|
+
try {
|
|
10
|
+
const metrics = await _config.globalOasTlmConfig.metricsExporter.getFinishedMetrics();
|
|
11
|
+
res.send({
|
|
12
|
+
metricsCount: metrics.length,
|
|
13
|
+
metrics: metrics
|
|
14
|
+
});
|
|
15
|
+
} catch (err) {
|
|
16
|
+
console.error(err);
|
|
17
|
+
res.status(500).send({
|
|
18
|
+
error: 'Failed to list metrics data'
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
exports.listMetrics = listMetrics;
|
|
23
|
+
const findMetrics = (req, res) => {
|
|
24
|
+
const body = req.body;
|
|
25
|
+
const search = body?.search ? body.search : {};
|
|
26
|
+
_config.globalOasTlmConfig.metricsExporter.find(search, (err, docs) => {
|
|
27
|
+
if (err) {
|
|
28
|
+
console.error(err);
|
|
29
|
+
res.status(404).send({
|
|
30
|
+
metricsCount: 0,
|
|
31
|
+
metrics: [],
|
|
32
|
+
error: err
|
|
33
|
+
});
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const metrics = docs;
|
|
37
|
+
res.send({
|
|
38
|
+
metricsCount: metrics.length,
|
|
39
|
+
metrics: metrics
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
exports.findMetrics = findMetrics;
|
|
44
|
+
const resetMetrics = (req, res) => {
|
|
45
|
+
_config.globalOasTlmConfig.metricsExporter.reset();
|
|
46
|
+
res.send('Metrics reset');
|
|
47
|
+
};
|
|
48
|
+
exports.resetMetrics = resetMetrics;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.InMemoryDBMetricsExporter = void 0;
|
|
7
|
+
var _core = require("@opentelemetry/core");
|
|
8
|
+
var _nedb = _interopRequireDefault(require("@seald-io/nedb"));
|
|
9
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
10
|
+
class InMemoryDBMetricsExporter {
|
|
11
|
+
constructor() {
|
|
12
|
+
this._metrics = new _nedb.default();
|
|
13
|
+
this._stopped = false;
|
|
14
|
+
}
|
|
15
|
+
export(metrics, resultCallback) {
|
|
16
|
+
try {
|
|
17
|
+
if (!this._stopped) {
|
|
18
|
+
// metrics = metrics?.scopeMetrics;
|
|
19
|
+
// const cleanMetrics = metrics.map(metric => applyNesting(metric));
|
|
20
|
+
this._metrics.insert(metrics, (err, newDoc) => {
|
|
21
|
+
if (err) {
|
|
22
|
+
console.error('Insertion Error:', err);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
setTimeout(() => resultCallback({
|
|
28
|
+
code: _core.ExportResultCode.SUCCESS
|
|
29
|
+
}), 0);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.error('Error exporting metrics\n' + error.message + '\n' + error.stack);
|
|
32
|
+
return resultCallback({
|
|
33
|
+
code: _core.ExportResultCode.FAILED,
|
|
34
|
+
error: new Error('Error exporting metrics\n' + error.message + '\n' + error.stack)
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
start() {
|
|
39
|
+
this._stopped = false;
|
|
40
|
+
}
|
|
41
|
+
stop() {
|
|
42
|
+
this._stopped = true;
|
|
43
|
+
}
|
|
44
|
+
isRunning() {
|
|
45
|
+
return !this._stopped;
|
|
46
|
+
}
|
|
47
|
+
shutdown() {
|
|
48
|
+
this._stopped = true;
|
|
49
|
+
this._metrics = new _nedb.default();
|
|
50
|
+
return this.forceFlush();
|
|
51
|
+
}
|
|
52
|
+
forceFlush() {
|
|
53
|
+
return Promise.resolve();
|
|
54
|
+
}
|
|
55
|
+
find(search, callback) {
|
|
56
|
+
this._metrics.find(search, callback);
|
|
57
|
+
}
|
|
58
|
+
reset() {
|
|
59
|
+
this._metrics = new _nedb.default();
|
|
60
|
+
}
|
|
61
|
+
getFinishedMetrics() {
|
|
62
|
+
return this._metrics.getAllData();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
exports.InMemoryDBMetricsExporter = InMemoryDBMetricsExporter;
|
|
66
|
+
function convertToNestedObject(obj) {
|
|
67
|
+
const result = {};
|
|
68
|
+
for (const key in obj) {
|
|
69
|
+
const keys = key.split('.');
|
|
70
|
+
let temp = result;
|
|
71
|
+
for (let i = 0; i < keys.length; i++) {
|
|
72
|
+
const currentKey = keys[i];
|
|
73
|
+
if (i === keys.length - 1) {
|
|
74
|
+
// Last key, set the value
|
|
75
|
+
temp[currentKey] = obj[key];
|
|
76
|
+
} else {
|
|
77
|
+
// Intermediate key, ensure the object exists
|
|
78
|
+
if (!temp[currentKey]) {
|
|
79
|
+
temp[currentKey] = {};
|
|
80
|
+
}
|
|
81
|
+
temp = temp[currentKey];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Applies nesting to all dot-separated keys within an object.
|
|
90
|
+
*
|
|
91
|
+
* @param {Object} obj - The object to apply nesting to.
|
|
92
|
+
* @returns {Object} - The transformed object with nested structures.
|
|
93
|
+
*/
|
|
94
|
+
function applyNesting(obj) {
|
|
95
|
+
for (const key in obj) {
|
|
96
|
+
if (typeof obj[key] === 'object' && obj[key] !== null) {
|
|
97
|
+
obj[key] = applyNesting(obj[key]);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return obj;
|
|
101
|
+
}
|
package/dist/index.cjs
CHANGED
|
@@ -12,6 +12,7 @@ var _authMiddleware = require("./middleware/authMiddleware.cjs");
|
|
|
12
12
|
var _authRoutes = _interopRequireDefault(require("./routes/authRoutes.cjs"));
|
|
13
13
|
var _telemetryRoutes = require("./routes/telemetryRoutes.cjs");
|
|
14
14
|
var _InMemoryDbExporter = require("./exporters/InMemoryDbExporter.cjs");
|
|
15
|
+
var _metricsRoutes = _interopRequireDefault(require("./routes/metricsRoutes.cjs"));
|
|
15
16
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
16
17
|
let dbglog = () => {};
|
|
17
18
|
if (process.env.OTDEBUG == "true") dbglog = console.log;
|
|
@@ -56,6 +57,7 @@ function oasTelemetry(OasTlmConfig) {
|
|
|
56
57
|
router.use((0, _express.json)());
|
|
57
58
|
router.use(baseURL, allAuthMiddlewares);
|
|
58
59
|
router.use(baseURL, _telemetryRoutes.telemetryRoutes);
|
|
60
|
+
router.use(baseURL + "/metrics", _metricsRoutes.default);
|
|
59
61
|
if (_config.globalOasTlmConfig.autoActivate) {
|
|
60
62
|
_config.globalOasTlmConfig.dynamicExporter.exporter?.start();
|
|
61
63
|
}
|
package/dist/openTelemetry.cjs
CHANGED
|
@@ -4,11 +4,14 @@ var _sdkNode = require("@opentelemetry/sdk-node");
|
|
|
4
4
|
var _resources = require("@opentelemetry/resources");
|
|
5
5
|
var _instrumentationHttp = require("@opentelemetry/instrumentation-http");
|
|
6
6
|
var _config = require("./config.cjs");
|
|
7
|
+
var _systemMetrics = require("./systemMetrics.cjs");
|
|
7
8
|
// import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
|
|
8
9
|
|
|
10
|
+
// Import system metrics functions
|
|
11
|
+
|
|
9
12
|
// DynamicExporter allows changing to any exporter at runtime;
|
|
10
13
|
const traceExporter = _config.globalOasTlmConfig.dynamicExporter;
|
|
11
|
-
//
|
|
14
|
+
// Alternative 1: Using NodeSDK
|
|
12
15
|
const sdk = new _sdkNode.NodeSDK({
|
|
13
16
|
resource: new _resources.Resource({
|
|
14
17
|
service: 'oas-telemetry-service'
|
|
@@ -16,6 +19,26 @@ const sdk = new _sdkNode.NodeSDK({
|
|
|
16
19
|
traceExporter,
|
|
17
20
|
instrumentations: [new _instrumentationHttp.HttpInstrumentation()]
|
|
18
21
|
});
|
|
22
|
+
|
|
23
|
+
// Collect and export system metrics
|
|
24
|
+
setInterval(() => {
|
|
25
|
+
const cpuUsageData = (0, _systemMetrics.getCpuUsageData)();
|
|
26
|
+
const processCpuUsageData = (0, _systemMetrics.getProcessCpuUsageData)();
|
|
27
|
+
const memoryData = (0, _systemMetrics.getMemoryData)();
|
|
28
|
+
const processMemoryData = (0, _systemMetrics.getProcessMemoryData)();
|
|
29
|
+
const metrics = {
|
|
30
|
+
timestamp: Date.now(),
|
|
31
|
+
cpuUsageData,
|
|
32
|
+
processCpuUsageData,
|
|
33
|
+
memoryData,
|
|
34
|
+
processMemoryData
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Export the collected metrics using the InMemoryDBMetricsExporter
|
|
38
|
+
const inMemoryDbMetricExporter = _config.globalOasTlmConfig.metricsExporter;
|
|
39
|
+
inMemoryDbMetricExporter.export(metrics, result => {});
|
|
40
|
+
}, _config.globalOasTlmConfig.systemMetricsInterval);
|
|
41
|
+
console.log('✅ OpenTelemetry System Metrics initialized.');
|
|
19
42
|
if (process.env.OASTLM_MODULE_DISABLED !== 'true') {
|
|
20
43
|
sdk.start();
|
|
21
44
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.metricsRoutes = exports.default = void 0;
|
|
7
|
+
var _express = require("express");
|
|
8
|
+
var _metricsController = require("../controllers/metricsController.cjs");
|
|
9
|
+
const metricsRoutes = exports.metricsRoutes = (0, _express.Router)();
|
|
10
|
+
|
|
11
|
+
// Metrics Control
|
|
12
|
+
metricsRoutes.get('/', _metricsController.listMetrics);
|
|
13
|
+
metricsRoutes.post('/find', _metricsController.findMetrics);
|
|
14
|
+
metricsRoutes.get('/reset', _metricsController.resetMetrics);
|
|
15
|
+
var _default = exports.default = metricsRoutes;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.getCpuUsageData = getCpuUsageData;
|
|
7
|
+
exports.getMemoryData = getMemoryData;
|
|
8
|
+
exports.getProcessCpuUsageData = getProcessCpuUsageData;
|
|
9
|
+
exports.getProcessMemoryData = getProcessMemoryData;
|
|
10
|
+
var _os = require("os");
|
|
11
|
+
const MILLISECOND = 1 / 1e3;
|
|
12
|
+
const MICROSECOND = 1 / 1e6;
|
|
13
|
+
let prevOsData = {
|
|
14
|
+
time: Date.now(),
|
|
15
|
+
cpus: (0, _os.cpus)()
|
|
16
|
+
};
|
|
17
|
+
function getCpuUsageData() {
|
|
18
|
+
const currentTime = Date.now();
|
|
19
|
+
const timeElapsed = currentTime - prevOsData.time;
|
|
20
|
+
const currentOsData = {
|
|
21
|
+
time: currentTime,
|
|
22
|
+
cpus: (0, _os.cpus)()
|
|
23
|
+
};
|
|
24
|
+
const usageData = currentOsData.cpus.map((cpu, cpuNumber) => {
|
|
25
|
+
const prevTimes = prevOsData.cpus[cpuNumber].times;
|
|
26
|
+
const currTimes = cpu.times;
|
|
27
|
+
const idle = currTimes.idle * MILLISECOND;
|
|
28
|
+
const user = currTimes.user * MILLISECOND;
|
|
29
|
+
const system = currTimes.sys * MILLISECOND;
|
|
30
|
+
const interrupt = currTimes.irq * MILLISECOND;
|
|
31
|
+
const nice = currTimes.nice * MILLISECOND;
|
|
32
|
+
const idleP = (currTimes.idle - prevTimes.idle) / timeElapsed;
|
|
33
|
+
const userP = (currTimes.user - prevTimes.user) / timeElapsed;
|
|
34
|
+
const systemP = (currTimes.sys - prevTimes.sys) / timeElapsed;
|
|
35
|
+
const interruptP = (currTimes.irq - prevTimes.irq) / timeElapsed;
|
|
36
|
+
const niceP = (currTimes.nice - prevTimes.nice) / timeElapsed;
|
|
37
|
+
return {
|
|
38
|
+
cpuNumber: String(cpuNumber),
|
|
39
|
+
idle,
|
|
40
|
+
user,
|
|
41
|
+
system,
|
|
42
|
+
interrupt,
|
|
43
|
+
nice,
|
|
44
|
+
userP,
|
|
45
|
+
systemP,
|
|
46
|
+
idleP,
|
|
47
|
+
interruptP,
|
|
48
|
+
niceP
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
prevOsData = currentOsData;
|
|
52
|
+
return usageData;
|
|
53
|
+
}
|
|
54
|
+
let prevProcData = {
|
|
55
|
+
time: Date.now(),
|
|
56
|
+
usage: process.cpuUsage()
|
|
57
|
+
};
|
|
58
|
+
function getProcessCpuUsageData() {
|
|
59
|
+
const currentTime = Date.now();
|
|
60
|
+
const currentUsage = process.cpuUsage();
|
|
61
|
+
const prevUsage = prevProcData.usage;
|
|
62
|
+
const timeElapsed = (currentTime - prevProcData.time) * 1000;
|
|
63
|
+
const cpusTimeElapsed = timeElapsed * prevOsData.cpus.length;
|
|
64
|
+
const user = currentUsage.user * MICROSECOND;
|
|
65
|
+
const system = currentUsage.system * MICROSECOND;
|
|
66
|
+
const userP = (currentUsage.user - prevUsage.user) / cpusTimeElapsed;
|
|
67
|
+
const systemP = (currentUsage.system - prevUsage.system) / cpusTimeElapsed;
|
|
68
|
+
prevProcData = {
|
|
69
|
+
time: currentTime,
|
|
70
|
+
usage: currentUsage
|
|
71
|
+
};
|
|
72
|
+
return {
|
|
73
|
+
user,
|
|
74
|
+
system,
|
|
75
|
+
userP,
|
|
76
|
+
systemP
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function getMemoryData() {
|
|
80
|
+
const total = (0, _os.totalmem)();
|
|
81
|
+
const free = (0, _os.freemem)();
|
|
82
|
+
const used = total - free;
|
|
83
|
+
const freeP = free / total;
|
|
84
|
+
const usedP = used / total;
|
|
85
|
+
return {
|
|
86
|
+
used: used,
|
|
87
|
+
free: free,
|
|
88
|
+
usedP: usedP,
|
|
89
|
+
freeP: freeP
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function getProcessMemoryData() {
|
|
93
|
+
if (process.memoryUsage.rss) {
|
|
94
|
+
return process.memoryUsage.rss();
|
|
95
|
+
}
|
|
96
|
+
return process.memoryUsage().rss;
|
|
97
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oas-tools/oas-telemetry",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "This package exports an Express middleware that traces requests and responses of an Express application using OpenTelemetry.",
|
|
5
5
|
"author": "Manuel Otero",
|
|
6
6
|
"contributors": [
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"default": "./src/index.js"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
+
"@opentelemetry/host-metrics": "^0.35.5",
|
|
48
49
|
"@opentelemetry/instrumentation-http": "^0.51.0",
|
|
49
50
|
"@opentelemetry/resources": "^1.24.0",
|
|
50
51
|
"@opentelemetry/sdk-node": "^0.49.1",
|
package/src/config.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
import { metrics } from "@opentelemetry/api";
|
|
1
2
|
import DynamicExporter from "./exporters/dynamicExporter.js";
|
|
3
|
+
import { InMemoryDBMetricsExporter } from "./exporters/InMemoryDBMetricsExporter.js";
|
|
2
4
|
|
|
3
5
|
//Environment variables
|
|
4
6
|
//OASTLM_MODULE_DISABLED = 'true' //Disables the module (empty middleware and no tracing)
|
|
5
7
|
|
|
6
8
|
export const globalOasTlmConfig = {
|
|
7
9
|
dynamicExporter: new DynamicExporter(),
|
|
10
|
+
metricsExporter: new InMemoryDBMetricsExporter(),
|
|
11
|
+
systemMetricsInterval: 1000 * 5, // 5 seconds
|
|
8
12
|
baseURL: "/telemetry",
|
|
9
13
|
spec: null,
|
|
10
14
|
specFileName: "",
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { globalOasTlmConfig } from '../config.js';
|
|
2
|
+
|
|
3
|
+
export const listMetrics = async (req, res) => {
|
|
4
|
+
try {
|
|
5
|
+
const metrics = await globalOasTlmConfig.metricsExporter.getFinishedMetrics();
|
|
6
|
+
res.send({ metricsCount: metrics.length, metrics: metrics });
|
|
7
|
+
} catch (err) {
|
|
8
|
+
console.error(err);
|
|
9
|
+
res.status(500).send({ error: 'Failed to list metrics data' });
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const findMetrics = (req, res) => {
|
|
14
|
+
const body = req.body;
|
|
15
|
+
const search = body?.search ? body.search : {};
|
|
16
|
+
globalOasTlmConfig.metricsExporter.find(search, (err, docs) => {
|
|
17
|
+
if (err) {
|
|
18
|
+
console.error(err);
|
|
19
|
+
res.status(404).send({ metricsCount: 0, metrics: [], error: err });
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const metrics = docs;
|
|
23
|
+
res.send({ metricsCount: metrics.length, metrics: metrics });
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const resetMetrics = (req, res) => {
|
|
28
|
+
globalOasTlmConfig.metricsExporter.reset();
|
|
29
|
+
res.send('Metrics reset');
|
|
30
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
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
|
+
export(metrics, resultCallback) {
|
|
11
|
+
try {
|
|
12
|
+
if (!this._stopped) {
|
|
13
|
+
// metrics = metrics?.scopeMetrics;
|
|
14
|
+
// const cleanMetrics = metrics.map(metric => applyNesting(metric));
|
|
15
|
+
this._metrics.insert(metrics, (err, newDoc) => {
|
|
16
|
+
if (err) {
|
|
17
|
+
console.error('Insertion Error:', err);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
setTimeout(() => resultCallback({ code: ExportResultCode.SUCCESS }), 0);
|
|
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
|
+
|
|
32
|
+
start() {
|
|
33
|
+
this._stopped = false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
stop() {
|
|
37
|
+
this._stopped = true;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
isRunning() {
|
|
41
|
+
return !this._stopped;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
shutdown() {
|
|
45
|
+
this._stopped = true;
|
|
46
|
+
this._metrics = new dataStore();
|
|
47
|
+
return this.forceFlush();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
forceFlush() {
|
|
51
|
+
return Promise.resolve();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
find(search, callback) {
|
|
55
|
+
this._metrics.find(search, callback);
|
|
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
|
+
|
package/src/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { authMiddleware } from './middleware/authMiddleware.js';
|
|
|
6
6
|
import authRoutes from './routes/authRoutes.js';
|
|
7
7
|
import { telemetryRoutes } from './routes/telemetryRoutes.js';
|
|
8
8
|
import { InMemoryExporter } from './exporters/InMemoryDbExporter.js';
|
|
9
|
+
import metricsRoutes from './routes/metricsRoutes.js';
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
let dbglog = () => { };
|
|
@@ -41,7 +42,7 @@ export default function oasTelemetry(OasTlmConfig) {
|
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
console.log("baseURL: ", globalOasTlmConfig.baseURL);
|
|
44
|
-
globalOasTlmConfig.dynamicExporter.changeExporter(
|
|
45
|
+
globalOasTlmConfig.dynamicExporter.changeExporter( globalOasTlmConfig.exporter ?? new InMemoryExporter() );
|
|
45
46
|
|
|
46
47
|
if (globalOasTlmConfig.spec)
|
|
47
48
|
dbglog(`Spec content provided`);
|
|
@@ -57,6 +58,7 @@ export default function oasTelemetry(OasTlmConfig) {
|
|
|
57
58
|
router.use(json());
|
|
58
59
|
router.use(baseURL, allAuthMiddlewares);
|
|
59
60
|
router.use(baseURL, telemetryRoutes);
|
|
61
|
+
router.use(baseURL + "/metrics", metricsRoutes);
|
|
60
62
|
|
|
61
63
|
if (globalOasTlmConfig.autoActivate) {
|
|
62
64
|
globalOasTlmConfig.dynamicExporter.exporter?.start();
|
package/src/openTelemetry.js
CHANGED
|
@@ -1,25 +1,47 @@
|
|
|
1
|
-
|
|
2
1
|
import { NodeSDK } from '@opentelemetry/sdk-node';
|
|
3
2
|
// import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
|
|
4
3
|
import { Resource } from '@opentelemetry/resources';
|
|
5
4
|
import { HttpInstrumentation } from '@opentelemetry/instrumentation-http';
|
|
6
5
|
import { globalOasTlmConfig } from './config.js';
|
|
6
|
+
import { getCpuUsageData, getProcessCpuUsageData, getMemoryData, getProcessMemoryData } from './systemMetrics.js'; // Import system metrics functions
|
|
7
|
+
|
|
8
|
+
// DynamicExporter allows changing to any exporter at runtime;
|
|
9
|
+
const traceExporter = globalOasTlmConfig.dynamicExporter;
|
|
10
|
+
// Alternative 1: Using NodeSDK
|
|
11
|
+
const sdk = new NodeSDK({
|
|
12
|
+
resource: new Resource({
|
|
13
|
+
service: 'oas-telemetry-service'
|
|
14
|
+
}),
|
|
15
|
+
traceExporter,
|
|
16
|
+
instrumentations: [new HttpInstrumentation()]
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
// Collect and export system metrics
|
|
21
|
+
setInterval(() => {
|
|
22
|
+
const cpuUsageData = getCpuUsageData();
|
|
23
|
+
const processCpuUsageData = getProcessCpuUsageData();
|
|
24
|
+
const memoryData = getMemoryData();
|
|
25
|
+
const processMemoryData = getProcessMemoryData();
|
|
26
|
+
|
|
27
|
+
const metrics = {
|
|
28
|
+
timestamp: Date.now(),
|
|
29
|
+
cpuUsageData,
|
|
30
|
+
processCpuUsageData,
|
|
31
|
+
memoryData,
|
|
32
|
+
processMemoryData,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// Export the collected metrics using the InMemoryDBMetricsExporter
|
|
36
|
+
const inMemoryDbMetricExporter = globalOasTlmConfig.metricsExporter;
|
|
37
|
+
inMemoryDbMetricExporter.export(metrics, (result) => {});
|
|
38
|
+
}, globalOasTlmConfig.systemMetricsInterval);
|
|
7
39
|
|
|
40
|
+
console.log('✅ OpenTelemetry System Metrics initialized.');
|
|
8
41
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const sdk = new NodeSDK({
|
|
13
|
-
resource: new Resource({
|
|
14
|
-
service: 'oas-telemetry-service'
|
|
15
|
-
}),
|
|
16
|
-
traceExporter,
|
|
17
|
-
instrumentations: [new HttpInstrumentation()]
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
if (process.env.OASTLM_MODULE_DISABLED !== 'true') {
|
|
21
|
-
sdk.start()
|
|
22
|
-
}
|
|
42
|
+
if (process.env.OASTLM_MODULE_DISABLED !== 'true') {
|
|
43
|
+
sdk.start()
|
|
44
|
+
}
|
|
23
45
|
|
|
24
46
|
// Alternative 2:
|
|
25
47
|
// const provider = new NodeTracerProvider();
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import {
|
|
3
|
+
listMetrics,
|
|
4
|
+
findMetrics,
|
|
5
|
+
resetMetrics
|
|
6
|
+
} from '../controllers/metricsController.js';
|
|
7
|
+
|
|
8
|
+
export const metricsRoutes = Router();
|
|
9
|
+
|
|
10
|
+
// Metrics Control
|
|
11
|
+
metricsRoutes.get('/', listMetrics);
|
|
12
|
+
metricsRoutes.post('/find', findMetrics);
|
|
13
|
+
metricsRoutes.get('/reset', resetMetrics);
|
|
14
|
+
|
|
15
|
+
export default metricsRoutes;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { cpus, totalmem, freemem } from 'os';
|
|
2
|
+
|
|
3
|
+
const MILLISECOND = 1 / 1e3;
|
|
4
|
+
const MICROSECOND = 1 / 1e6;
|
|
5
|
+
|
|
6
|
+
let prevOsData = {
|
|
7
|
+
time: Date.now(),
|
|
8
|
+
cpus: cpus(),
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export function getCpuUsageData() {
|
|
12
|
+
const currentTime = Date.now();
|
|
13
|
+
const timeElapsed = currentTime - prevOsData.time;
|
|
14
|
+
const currentOsData = { time: currentTime, cpus: cpus() };
|
|
15
|
+
|
|
16
|
+
const usageData = currentOsData.cpus.map((cpu, cpuNumber) => {
|
|
17
|
+
const prevTimes = prevOsData.cpus[cpuNumber].times;
|
|
18
|
+
const currTimes = cpu.times;
|
|
19
|
+
|
|
20
|
+
const idle = currTimes.idle * MILLISECOND;
|
|
21
|
+
const user = currTimes.user * MILLISECOND;
|
|
22
|
+
const system = currTimes.sys * MILLISECOND;
|
|
23
|
+
const interrupt = currTimes.irq * MILLISECOND;
|
|
24
|
+
const nice = currTimes.nice * MILLISECOND;
|
|
25
|
+
|
|
26
|
+
const idleP = (currTimes.idle - prevTimes.idle) / timeElapsed;
|
|
27
|
+
const userP = (currTimes.user - prevTimes.user) / timeElapsed;
|
|
28
|
+
const systemP = (currTimes.sys - prevTimes.sys) / timeElapsed;
|
|
29
|
+
const interruptP = (currTimes.irq - prevTimes.irq) / timeElapsed;
|
|
30
|
+
const niceP = (currTimes.nice - prevTimes.nice) / timeElapsed;
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
cpuNumber: String(cpuNumber),
|
|
34
|
+
idle,
|
|
35
|
+
user,
|
|
36
|
+
system,
|
|
37
|
+
interrupt,
|
|
38
|
+
nice,
|
|
39
|
+
userP,
|
|
40
|
+
systemP,
|
|
41
|
+
idleP,
|
|
42
|
+
interruptP,
|
|
43
|
+
niceP,
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
prevOsData = currentOsData;
|
|
48
|
+
|
|
49
|
+
return usageData;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let prevProcData = {
|
|
53
|
+
time: Date.now(),
|
|
54
|
+
usage: process.cpuUsage(),
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
export function getProcessCpuUsageData() {
|
|
61
|
+
const currentTime = Date.now();
|
|
62
|
+
const currentUsage = process.cpuUsage();
|
|
63
|
+
const prevUsage = prevProcData.usage;
|
|
64
|
+
const timeElapsed = (currentTime - prevProcData.time) * 1000;
|
|
65
|
+
const cpusTimeElapsed = timeElapsed * prevOsData.cpus.length;
|
|
66
|
+
|
|
67
|
+
const user = currentUsage.user * MICROSECOND;
|
|
68
|
+
const system = currentUsage.system * MICROSECOND;
|
|
69
|
+
const userP = (currentUsage.user - prevUsage.user) / cpusTimeElapsed;
|
|
70
|
+
const systemP = (currentUsage.system - prevUsage.system) / cpusTimeElapsed;
|
|
71
|
+
|
|
72
|
+
prevProcData = { time: currentTime, usage: currentUsage };
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
user,
|
|
76
|
+
system,
|
|
77
|
+
userP,
|
|
78
|
+
systemP,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function getMemoryData() {
|
|
83
|
+
const total = totalmem();
|
|
84
|
+
const free = freemem();
|
|
85
|
+
const used = total - free;
|
|
86
|
+
const freeP = free / total;
|
|
87
|
+
const usedP = used / total;
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
used: used,
|
|
91
|
+
free: free,
|
|
92
|
+
usedP: usedP,
|
|
93
|
+
freeP: freeP,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function getProcessMemoryData() {
|
|
98
|
+
if (process.memoryUsage.rss) {
|
|
99
|
+
return process.memoryUsage.rss();
|
|
100
|
+
}
|
|
101
|
+
return process.memoryUsage().rss;
|
|
102
|
+
}
|