@arcblock/pm2-prom-module 2.6.4 → 2.6.5
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/core/pm2.js +0 -46
- package/package.json +7 -3
- package/utils/docker.js +64 -30
- package/utils/index.js +1 -2
package/core/pm2.js
CHANGED
|
@@ -142,11 +142,6 @@ const detectActiveApps = () => {
|
|
|
142
142
|
workingApp.updateStatus(entry.status);
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
|
-
// Collect statistic from apps. Do it after all APPS created
|
|
146
|
-
if (activePM2Ids.size > 0) {
|
|
147
|
-
// logger.debug(`Collect app metrics from PIDs ${Array.from(activePM2Ids)}`);
|
|
148
|
-
sendCollectStaticticBusEvent(Array.from(activePM2Ids));
|
|
149
|
-
}
|
|
150
145
|
// Update metric with available apps
|
|
151
146
|
metrics_1.metricAvailableApps === null || metrics_1.metricAvailableApps === void 0 ? void 0 : metrics_1.metricAvailableApps.set(Object.keys(APPS).length);
|
|
152
147
|
// Get all pids to monit
|
|
@@ -205,7 +200,6 @@ const detectActiveApps = () => {
|
|
|
205
200
|
});
|
|
206
201
|
};
|
|
207
202
|
const startPm2Connect = (conf) => {
|
|
208
|
-
const logger = (0, logger_1.getLogger)();
|
|
209
203
|
pm2_1.default.connect((err) => {
|
|
210
204
|
var _a;
|
|
211
205
|
if (err)
|
|
@@ -220,32 +214,6 @@ const startPm2Connect = (conf) => {
|
|
|
220
214
|
(0, metrics_1.initDynamicGaugeMetricClients)(additionalMetrics);
|
|
221
215
|
}
|
|
222
216
|
detectActiveApps();
|
|
223
|
-
// Collect statistic from running apps
|
|
224
|
-
pm2_1.default.launchBus((err, bus) => {
|
|
225
|
-
if (err)
|
|
226
|
-
return console.error(err.stack || err);
|
|
227
|
-
logger.debug('Start bus listener');
|
|
228
|
-
bus.on('process:msg', (packet) => {
|
|
229
|
-
if (packet.process &&
|
|
230
|
-
packet.raw &&
|
|
231
|
-
packet.raw.topic === 'pm2-prom-module:metrics' &&
|
|
232
|
-
packet.raw.data) {
|
|
233
|
-
const { name, pm_id } = packet.process;
|
|
234
|
-
/*logger.debug(
|
|
235
|
-
`Got message from app=${name} and pid=${pm_id}. Message=${JSON.stringify(
|
|
236
|
-
packet.raw.data
|
|
237
|
-
)}`
|
|
238
|
-
);*/
|
|
239
|
-
if (name && APPS[name] && packet.raw.data.metrics) {
|
|
240
|
-
(0, app_2.processAppMetrics)(conf, {
|
|
241
|
-
pmId: pm_id,
|
|
242
|
-
appName: name,
|
|
243
|
-
appResponse: packet.raw.data,
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
});
|
|
248
|
-
});
|
|
249
217
|
// Start timer to update available apps
|
|
250
218
|
setInterval(() => {
|
|
251
219
|
detectActiveApps();
|
|
@@ -296,17 +264,3 @@ function processWorkingApp(workingApp) {
|
|
|
296
264
|
});
|
|
297
265
|
});
|
|
298
266
|
}
|
|
299
|
-
function sendCollectStaticticBusEvent(pm2Ids) {
|
|
300
|
-
// Request available metrics from all running apps
|
|
301
|
-
pm2Ids.forEach((pm2id) => {
|
|
302
|
-
pm2_1.default.sendDataToProcessId(pm2id, {
|
|
303
|
-
topic: 'pm2-prom-module:collect',
|
|
304
|
-
data: {},
|
|
305
|
-
// Required fields by pm2 but we do not use them
|
|
306
|
-
id: pm2id,
|
|
307
|
-
}, (err) => {
|
|
308
|
-
if (err)
|
|
309
|
-
return console.error(`pm2-prom-module: sendDataToProcessId ${err.stack || err}`);
|
|
310
|
-
});
|
|
311
|
-
});
|
|
312
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arcblock/pm2-prom-module",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.5",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -8,13 +8,16 @@
|
|
|
8
8
|
"main": "index.js",
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"@abtnode/util": "^1.16.44",
|
|
11
|
+
"@types/dockerode": "^3.3.42",
|
|
12
|
+
"dockerode": "^4.0.7",
|
|
11
13
|
"internal-ip": "^6.2.0",
|
|
14
|
+
"lodash": "^4.17.21",
|
|
12
15
|
"pidusage": "^3.0.2",
|
|
13
|
-
"pm2": "^
|
|
16
|
+
"pm2": "^6.0.8",
|
|
14
17
|
"pmx": "beta",
|
|
15
18
|
"prom-client": "^15.1.3",
|
|
16
19
|
"xbytes": "^1.9.1",
|
|
17
|
-
"zx": "^
|
|
20
|
+
"zx": "^8.8.0"
|
|
18
21
|
},
|
|
19
22
|
"scripts": {
|
|
20
23
|
"predev": "export PM2_HOME=~/.arcblock/abtnode && pm2 delete @arcblock/pm2-prom-module && pm2 uninstall @arcblock/pm2-prom-module || true && npm run build",
|
|
@@ -46,6 +49,7 @@
|
|
|
46
49
|
"prefix": "pm2"
|
|
47
50
|
},
|
|
48
51
|
"devDependencies": {
|
|
52
|
+
"@types/fs-extra": "^11.0.4",
|
|
49
53
|
"@types/node": "^18.19.50",
|
|
50
54
|
"@types/pidusage": "^2.0.5",
|
|
51
55
|
"bumpp": "^10.1.0",
|
package/utils/docker.js
CHANGED
|
@@ -12,16 +12,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.
|
|
15
|
+
exports.getCPULimit = exports.getFreeMemory = exports.getUsedMemory = exports.getBlockletServerInfo = exports.getAvailableMemory = exports.hasDockerLimitFiles = void 0;
|
|
16
|
+
exports.getDockerStats = getDockerStats;
|
|
16
17
|
const promises_1 = require("node:fs/promises");
|
|
17
18
|
const node_os_1 = __importDefault(require("node:os"));
|
|
18
19
|
const cpu_1 = require("./cpu");
|
|
19
|
-
const
|
|
20
|
-
const xbytes_1 = __importDefault(require("xbytes"));
|
|
20
|
+
const dockerode_1 = __importDefault(require("dockerode"));
|
|
21
21
|
const get_ip_1 = __importDefault(require("@abtnode/util/lib/get-ip"));
|
|
22
22
|
const internal_ip_1 = require("internal-ip");
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
const uniq_1 = __importDefault(require("lodash/uniq"));
|
|
24
|
+
// 初始化 Docker 客户端
|
|
25
|
+
const docker = new dockerode_1.default();
|
|
25
26
|
//const MEMORY_AVAILABLE = '/sys/fs/cgroup/memory.limit_in_bytes';
|
|
26
27
|
//const MEMORY_USED = '/sys/fs/cgroup/memory.usage_in_bytes';
|
|
27
28
|
const MEMORY_AVAILABLE = '/sys/fs/cgroup/memory.max';
|
|
@@ -97,7 +98,7 @@ const getUsedMemory = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
97
98
|
return usedMemory;
|
|
98
99
|
}
|
|
99
100
|
}
|
|
100
|
-
catch (
|
|
101
|
+
catch (_a) {
|
|
101
102
|
return 0;
|
|
102
103
|
}
|
|
103
104
|
});
|
|
@@ -126,7 +127,7 @@ const getFreeMemory = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
126
127
|
return systemFreeMem;
|
|
127
128
|
}
|
|
128
129
|
}
|
|
129
|
-
catch (
|
|
130
|
+
catch (_a) {
|
|
130
131
|
return 0;
|
|
131
132
|
}
|
|
132
133
|
});
|
|
@@ -146,41 +147,74 @@ const getCPULimit = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
146
147
|
}
|
|
147
148
|
}
|
|
148
149
|
}
|
|
149
|
-
catch (
|
|
150
|
+
catch (_a) { }
|
|
150
151
|
return count;
|
|
151
152
|
});
|
|
152
153
|
exports.getCPULimit = getCPULimit;
|
|
154
|
+
/**
|
|
155
|
+
* 获取单个容器的统计信息
|
|
156
|
+
*/
|
|
157
|
+
function getContainerStats(containerId) {
|
|
158
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
159
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
160
|
+
try {
|
|
161
|
+
const container = docker.getContainer(containerId);
|
|
162
|
+
const stats = yield container.stats({ stream: false });
|
|
163
|
+
// 内存使用信息
|
|
164
|
+
const memoryUsage = ((_a = stats.memory_stats) === null || _a === void 0 ? void 0 : _a.usage) || 0;
|
|
165
|
+
const memoryLimit = ((_b = stats.memory_stats) === null || _b === void 0 ? void 0 : _b.limit) || 0;
|
|
166
|
+
// CPU使用信息
|
|
167
|
+
const cpuStats = (_c = stats.cpu_stats) === null || _c === void 0 ? void 0 : _c.cpu_usage;
|
|
168
|
+
const preCpuStats = (_d = stats.precpu_stats) === null || _d === void 0 ? void 0 : _d.cpu_usage;
|
|
169
|
+
let cpuPercent = 0;
|
|
170
|
+
if (cpuStats && preCpuStats && ((_e = stats.cpu_stats) === null || _e === void 0 ? void 0 : _e.system_cpu_usage) && ((_f = stats.precpu_stats) === null || _f === void 0 ? void 0 : _f.system_cpu_usage)) {
|
|
171
|
+
// 计算容器CPU使用时间的增量(纳秒)
|
|
172
|
+
const cpuDelta = cpuStats.total_usage - preCpuStats.total_usage;
|
|
173
|
+
// 计算系统CPU时间的增量(纳秒)
|
|
174
|
+
const systemDelta = stats.cpu_stats.system_cpu_usage - stats.precpu_stats.system_cpu_usage;
|
|
175
|
+
if (systemDelta > 0 && cpuDelta >= 0) {
|
|
176
|
+
// 获取系统可用的CPU核心数
|
|
177
|
+
const onlineCpus = ((_g = stats.cpu_stats) === null || _g === void 0 ? void 0 : _g.online_cpus) || node_os_1.default.cpus().length;
|
|
178
|
+
// Docker CPU使用率计算公式:
|
|
179
|
+
// CPU% = (容器CPU增量 / 系统CPU增量) * CPU核心数 * 100%
|
|
180
|
+
//
|
|
181
|
+
// 解释:
|
|
182
|
+
// - cpuDelta: 容器在两次采样间隔内使用的CPU时间
|
|
183
|
+
// - systemDelta: 系统在两次采样间隔内所有CPU核心的总时间
|
|
184
|
+
// - 比值 (cpuDelta/systemDelta) 表示容器占用系统总CPU时间的比例
|
|
185
|
+
// - 乘以核心数是因为Docker的统计方式:单核100%使用时,在N核系统上显示为N*100%
|
|
186
|
+
cpuPercent = (cpuDelta / systemDelta) * onlineCpus * 100;
|
|
187
|
+
// 确保结果为非负数且不超过理论最大值
|
|
188
|
+
cpuPercent = Math.max(0, Math.min(cpuPercent, onlineCpus * 100));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
name: containerId,
|
|
193
|
+
cpuUsage: Math.round(cpuPercent * 100) / 100, // 保留2位小数
|
|
194
|
+
memoryUsage: memoryUsage,
|
|
195
|
+
totalMemory: memoryLimit,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
console.error(`Failed to get stats for container ${containerId}:`, error.message);
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
}
|
|
153
204
|
function getDockerStats(ids) {
|
|
154
205
|
return __awaiter(this, void 0, void 0, function* () {
|
|
155
206
|
try {
|
|
156
207
|
if (!ids.length) {
|
|
157
208
|
return [];
|
|
158
209
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
const statsRows = result.stdout
|
|
164
|
-
.split('\n')
|
|
165
|
-
.filter(Boolean)
|
|
166
|
-
.map((x) => JSON.parse(x));
|
|
167
|
-
const stats = statsRows.map((x) => {
|
|
168
|
-
const [memoryUsage, totalMemory] = x.MemUsage.split('/').map((x) => xbytes_1.default.parseSize(x.trim()));
|
|
169
|
-
return {
|
|
170
|
-
name: x.Name,
|
|
171
|
-
cpuUsage: +x.CPUPerc.replace('%', ''),
|
|
172
|
-
memoryUsage: memoryUsage,
|
|
173
|
-
totalMemory: totalMemory,
|
|
174
|
-
};
|
|
175
|
-
});
|
|
176
|
-
return ids.map((id) => {
|
|
177
|
-
return stats.find((x) => x.name === id);
|
|
178
|
-
});
|
|
210
|
+
// 并行获取所有容器的统计信息
|
|
211
|
+
const results = yield Promise.all((0, uniq_1.default)(ids).map(id => getContainerStats(id)));
|
|
212
|
+
// 过滤出成功的结果
|
|
213
|
+
return results.filter((stat) => stat !== null);
|
|
179
214
|
}
|
|
180
215
|
catch (error) {
|
|
181
|
-
console.error(error);
|
|
216
|
+
console.error('Error getting Docker stats:', error);
|
|
182
217
|
return [];
|
|
183
218
|
}
|
|
184
219
|
});
|
|
185
220
|
}
|
|
186
|
-
exports.getDockerStats = getDockerStats;
|
package/utils/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.toUndescore =
|
|
3
|
+
exports.toUndescore = toUndescore;
|
|
4
4
|
function toUndescore(str) {
|
|
5
5
|
return str.toLowerCase().replace(/\s+/g, '_');
|
|
6
6
|
}
|
|
7
|
-
exports.toUndescore = toUndescore;
|