@4pm/cli 1.4.1 → 1.4.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/dist/index.js +113 -25
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -33309,9 +33309,47 @@ async function readCgroup(file) {
|
|
|
33309
33309
|
return null;
|
|
33310
33310
|
}
|
|
33311
33311
|
}
|
|
33312
|
+
function parseKv(text) {
|
|
33313
|
+
const map = /* @__PURE__ */ new Map();
|
|
33314
|
+
if (!text) return map;
|
|
33315
|
+
for (const line of text.split("\n")) {
|
|
33316
|
+
const [k, v] = line.trim().split(/\s+/);
|
|
33317
|
+
if (k && v !== void 0) {
|
|
33318
|
+
const n = Number(v);
|
|
33319
|
+
if (Number.isFinite(n)) map.set(k, n);
|
|
33320
|
+
}
|
|
33321
|
+
}
|
|
33322
|
+
return map;
|
|
33323
|
+
}
|
|
33324
|
+
function parsePressureSome(text) {
|
|
33325
|
+
if (!text) return void 0;
|
|
33326
|
+
const some = text.split("\n").find((l) => l.startsWith("some "));
|
|
33327
|
+
const m = some?.match(/avg10=([\d.]+)/);
|
|
33328
|
+
const n = m ? Number(m[1]) : NaN;
|
|
33329
|
+
return Number.isFinite(n) ? clampPct(n) : void 0;
|
|
33330
|
+
}
|
|
33331
|
+
function parseIoStat(text) {
|
|
33332
|
+
if (!text) return null;
|
|
33333
|
+
let rBytes = 0;
|
|
33334
|
+
let wBytes = 0;
|
|
33335
|
+
for (const line of text.split("\n")) {
|
|
33336
|
+
const r = line.match(/\brbytes=(\d+)/);
|
|
33337
|
+
const w = line.match(/\bwbytes=(\d+)/);
|
|
33338
|
+
if (r) rBytes += Number(r[1]);
|
|
33339
|
+
if (w) wBytes += Number(w[1]);
|
|
33340
|
+
}
|
|
33341
|
+
return { rBytes, wBytes };
|
|
33342
|
+
}
|
|
33343
|
+
function parseMaybeMax(text) {
|
|
33344
|
+
if (text === null) return null;
|
|
33345
|
+
if (text === "max") return null;
|
|
33346
|
+
const n = Number(text);
|
|
33347
|
+
return Number.isFinite(n) ? n : null;
|
|
33348
|
+
}
|
|
33312
33349
|
function createWorkerMetricsSampler(diskPath) {
|
|
33313
33350
|
const cgroupV2 = existsSync4(`${CGROUP}/cpu.stat`) && existsSync4(`${CGROUP}/memory.current`);
|
|
33314
|
-
let
|
|
33351
|
+
let cgPrev = null;
|
|
33352
|
+
let osPrev = null;
|
|
33315
33353
|
async function cgroupCpuCount() {
|
|
33316
33354
|
const raw = await readCgroup("cpu.max");
|
|
33317
33355
|
if (raw) {
|
|
@@ -33323,22 +33361,6 @@ function createWorkerMetricsSampler(diskPath) {
|
|
|
33323
33361
|
}
|
|
33324
33362
|
return cpus().length;
|
|
33325
33363
|
}
|
|
33326
|
-
async function cgroupCpuPct(cpuCount) {
|
|
33327
|
-
const stat2 = await readCgroup("cpu.stat");
|
|
33328
|
-
const m = stat2?.match(/usage_usec\s+(\d+)/);
|
|
33329
|
-
const usageUsec = m ? Number(m[1]) : NaN;
|
|
33330
|
-
const now = Date.now();
|
|
33331
|
-
if (!Number.isFinite(usageUsec)) return 0;
|
|
33332
|
-
if (!prev) {
|
|
33333
|
-
prev = { busy: usageUsec, ref: now };
|
|
33334
|
-
return 0;
|
|
33335
|
-
}
|
|
33336
|
-
const dUsage = usageUsec - prev.busy;
|
|
33337
|
-
const dWall = (now - prev.ref) * 1e3;
|
|
33338
|
-
prev = { busy: usageUsec, ref: now };
|
|
33339
|
-
if (dWall <= 0) return 0;
|
|
33340
|
-
return clampPct(dUsage / (dWall * cpuCount) * 100);
|
|
33341
|
-
}
|
|
33342
33364
|
function osCpuPct() {
|
|
33343
33365
|
let busy = 0;
|
|
33344
33366
|
let total = 0;
|
|
@@ -33347,13 +33369,13 @@ function createWorkerMetricsSampler(diskPath) {
|
|
|
33347
33369
|
busy += t.user + t.nice + t.sys + t.irq;
|
|
33348
33370
|
total += t.user + t.nice + t.sys + t.irq + t.idle;
|
|
33349
33371
|
}
|
|
33350
|
-
if (!
|
|
33351
|
-
|
|
33372
|
+
if (!osPrev) {
|
|
33373
|
+
osPrev = { busy, total };
|
|
33352
33374
|
return 0;
|
|
33353
33375
|
}
|
|
33354
|
-
const dBusy = busy -
|
|
33355
|
-
const dTotal = total -
|
|
33356
|
-
|
|
33376
|
+
const dBusy = busy - osPrev.busy;
|
|
33377
|
+
const dTotal = total - osPrev.total;
|
|
33378
|
+
osPrev = { busy, total };
|
|
33357
33379
|
if (dTotal <= 0) return 0;
|
|
33358
33380
|
return clampPct(dBusy / dTotal * 100);
|
|
33359
33381
|
}
|
|
@@ -33367,9 +33389,74 @@ function createWorkerMetricsSampler(diskPath) {
|
|
|
33367
33389
|
return { usedGb: 0, totalGb: 0 };
|
|
33368
33390
|
}
|
|
33369
33391
|
}
|
|
33392
|
+
async function cgroupExtended(cpuCount, now) {
|
|
33393
|
+
const [cpuStatRaw, memStatRaw, ioStatRaw, cpuPsi, memPsi, ioPsi, swapCurRaw, swapMaxRaw, memEventsRaw, pidsCurRaw, pidsMaxRaw] = await Promise.all([
|
|
33394
|
+
readCgroup("cpu.stat"),
|
|
33395
|
+
readCgroup("memory.stat"),
|
|
33396
|
+
readCgroup("io.stat"),
|
|
33397
|
+
readCgroup("cpu.pressure"),
|
|
33398
|
+
readCgroup("memory.pressure"),
|
|
33399
|
+
readCgroup("io.pressure"),
|
|
33400
|
+
readCgroup("memory.swap.current"),
|
|
33401
|
+
readCgroup("memory.swap.max"),
|
|
33402
|
+
readCgroup("memory.events"),
|
|
33403
|
+
readCgroup("pids.current"),
|
|
33404
|
+
readCgroup("pids.max")
|
|
33405
|
+
]);
|
|
33406
|
+
const cpuStat = parseKv(cpuStatRaw);
|
|
33407
|
+
const usageUsec = cpuStat.get("usage_usec") ?? NaN;
|
|
33408
|
+
const nrThrottled = cpuStat.get("nr_throttled") ?? 0;
|
|
33409
|
+
const nrPeriods = cpuStat.get("nr_periods") ?? 0;
|
|
33410
|
+
const io = parseIoStat(ioStatRaw);
|
|
33411
|
+
const extra = {};
|
|
33412
|
+
extra.cpuPressurePct = parsePressureSome(cpuPsi);
|
|
33413
|
+
extra.memPressurePct = parsePressureSome(memPsi);
|
|
33414
|
+
extra.ioPressurePct = parsePressureSome(ioPsi);
|
|
33415
|
+
const memStat = parseKv(memStatRaw);
|
|
33416
|
+
if (memStat.has("anon")) extra.memAnonMb = Math.round(memStat.get("anon") / MB);
|
|
33417
|
+
if (memStat.has("file")) extra.memCacheMb = Math.round(memStat.get("file") / MB);
|
|
33418
|
+
if (swapCurRaw !== null) extra.swapUsedMb = Math.round(Number(swapCurRaw) / MB);
|
|
33419
|
+
if (swapMaxRaw !== null) {
|
|
33420
|
+
const max = parseMaybeMax(swapMaxRaw);
|
|
33421
|
+
extra.swapTotalMb = max === null ? null : Math.round(max / MB);
|
|
33422
|
+
}
|
|
33423
|
+
const memEvents = parseKv(memEventsRaw);
|
|
33424
|
+
if (memEvents.has("oom_kill")) extra.oomKills = memEvents.get("oom_kill");
|
|
33425
|
+
if (pidsCurRaw !== null) {
|
|
33426
|
+
const n = Number(pidsCurRaw);
|
|
33427
|
+
if (Number.isFinite(n)) extra.pidsCurrent = n;
|
|
33428
|
+
}
|
|
33429
|
+
if (pidsMaxRaw !== null) extra.pidsMax = parseMaybeMax(pidsMaxRaw);
|
|
33430
|
+
let cpuPct = 0;
|
|
33431
|
+
if (Number.isFinite(usageUsec)) {
|
|
33432
|
+
if (cgPrev) {
|
|
33433
|
+
const dWallUsec = (now - cgPrev.wallMs) * 1e3;
|
|
33434
|
+
if (dWallUsec > 0) cpuPct = clampPct((usageUsec - cgPrev.usageUsec) / (dWallUsec * cpuCount) * 100);
|
|
33435
|
+
const dPeriods = nrPeriods - cgPrev.nrPeriods;
|
|
33436
|
+
if (dPeriods > 0) extra.cpuThrottledPct = clampPct((nrThrottled - cgPrev.nrThrottled) / dPeriods * 100);
|
|
33437
|
+
if (io) {
|
|
33438
|
+
const dSec = (now - cgPrev.wallMs) / 1e3;
|
|
33439
|
+
if (dSec > 0) {
|
|
33440
|
+
extra.diskReadMbps = round1((io.rBytes - cgPrev.ioR) / MB / dSec);
|
|
33441
|
+
extra.diskWriteMbps = round1((io.wBytes - cgPrev.ioW) / MB / dSec);
|
|
33442
|
+
}
|
|
33443
|
+
}
|
|
33444
|
+
}
|
|
33445
|
+
cgPrev = {
|
|
33446
|
+
usageUsec,
|
|
33447
|
+
nrThrottled,
|
|
33448
|
+
nrPeriods,
|
|
33449
|
+
ioR: io?.rBytes ?? 0,
|
|
33450
|
+
ioW: io?.wBytes ?? 0,
|
|
33451
|
+
wallMs: now
|
|
33452
|
+
};
|
|
33453
|
+
}
|
|
33454
|
+
return { cpuPct, extra };
|
|
33455
|
+
}
|
|
33370
33456
|
return {
|
|
33371
33457
|
async sample() {
|
|
33372
|
-
const
|
|
33458
|
+
const now = Date.now();
|
|
33459
|
+
const at = new Date(now).toISOString();
|
|
33373
33460
|
const { usedGb: diskUsedGb, totalGb: diskTotalGb } = await disk();
|
|
33374
33461
|
const base = { platform: platform(), arch: arch(), diskUsedGb, diskTotalGb, at };
|
|
33375
33462
|
if (cgroupV2) {
|
|
@@ -33378,14 +33465,15 @@ function createWorkerMetricsSampler(diskPath) {
|
|
|
33378
33465
|
const memTotalBytes = memMaxRaw && memMaxRaw !== "max" ? Number(memMaxRaw) : totalmem();
|
|
33379
33466
|
const memUsedBytes = memCurRaw ? Number(memCurRaw) : totalmem() - freemem();
|
|
33380
33467
|
const cpuCount = await cgroupCpuCount();
|
|
33381
|
-
const cpuPct = await
|
|
33468
|
+
const { cpuPct, extra } = await cgroupExtended(cpuCount, now);
|
|
33382
33469
|
return {
|
|
33383
33470
|
...base,
|
|
33384
33471
|
source: "cgroup",
|
|
33385
33472
|
cpuCount,
|
|
33386
33473
|
cpuPct,
|
|
33387
33474
|
memUsedMb: Math.round(memUsedBytes / MB),
|
|
33388
|
-
memTotalMb: Math.round(memTotalBytes / MB)
|
|
33475
|
+
memTotalMb: Math.round(memTotalBytes / MB),
|
|
33476
|
+
...extra
|
|
33389
33477
|
};
|
|
33390
33478
|
}
|
|
33391
33479
|
const total = totalmem();
|