





















@@ -4,17 +4,29 @@ const [statsFile, maxMemoryRaw, maxCpuRaw, label = "docker"] = process.argv.slic
44const maxMemoryMiB = Number(maxMemoryRaw);
55const maxCpuPercent = Number(maxCpuRaw);
667+function assertFiniteLimit(value, raw, name) {
8+if (!Number.isFinite(value) || value < 0) {
9+throw new Error(`${name} must be a finite non-negative number. Got: ${JSON.stringify(raw)}`);
10+}
11+}
12+713function parseMemoryMiB(raw) {
814const value =
915String(raw || "")
1016.split("/")[0]
1117?.trim() || "";
1218const match = /^([0-9.]+)\s*([KMGT]?i?B)$/iu.exec(value);
1319if (!match) {
14-return 0;
20+return undefined;
1521}
1622const amount = Number(match[1]);
23+if (!Number.isFinite(amount)) {
24+return undefined;
25+}
1726const unit = match[2].toLowerCase();
27+if (unit === "b") {
28+return amount / 1024 / 1024;
29+}
1830if (unit === "kb" || unit === "kib") {
1931return amount / 1024;
2032}
@@ -27,33 +39,52 @@ function parseMemoryMiB(raw) {
2739if (unit === "tb" || unit === "tib") {
2840return amount * 1024 * 1024;
2941}
30-return 0;
42+return undefined;
43+}
44+45+function parseCpuPercent(raw) {
46+const parsed = Number(String(raw || "").replace(/%$/u, ""));
47+return Number.isFinite(parsed) ? parsed : undefined;
48+}
49+50+function assertSampleValue(value, raw, name, label) {
51+if (value === undefined) {
52+throw new Error(
53+`docker stats sample for ${label} had invalid ${name}: ${JSON.stringify(raw)}`,
54+);
55+}
3156}
32573358const lines = fs.existsSync(statsFile)
3459 ? fs.readFileSync(statsFile, "utf8").split(/\r?\n/u).filter(Boolean)
3560 : [];
3661let maxObservedMemoryMiB = 0;
3762let maxObservedCpuPercent = 0;
63+let parsedSamples = 0;
64+65+assertFiniteLimit(maxMemoryMiB, maxMemoryRaw, "max memory MiB");
66+assertFiniteLimit(maxCpuPercent, maxCpuRaw, "max CPU percent");
38673968for (const line of lines) {
4069let parsed;
4170try {
4271parsed = JSON.parse(line);
4372} catch {
44-continue;
73+throw new Error(`docker stats sample for ${label} was not valid JSON`);
4574}
46-maxObservedMemoryMiB = Math.max(maxObservedMemoryMiB, parseMemoryMiB(parsed.MemUsage));
47-maxObservedCpuPercent = Math.max(
48-maxObservedCpuPercent,
49-Number(String(parsed.CPUPerc || "0").replace(/%$/u, "")) || 0,
50-);
75+const observedMemoryMiB = parseMemoryMiB(parsed.MemUsage);
76+const observedCpuPercent = parseCpuPercent(parsed.CPUPerc);
77+assertSampleValue(observedMemoryMiB, parsed.MemUsage, "MemUsage", label);
78+assertSampleValue(observedCpuPercent, parsed.CPUPerc, "CPUPerc", label);
79+parsedSamples += 1;
80+maxObservedMemoryMiB = Math.max(maxObservedMemoryMiB, observedMemoryMiB);
81+maxObservedCpuPercent = Math.max(maxObservedCpuPercent, observedCpuPercent);
5182}
52835384console.log(
54-`${label} resource peak: memory=${maxObservedMemoryMiB.toFixed(1)}MiB cpu=${maxObservedCpuPercent.toFixed(1)}% samples=${lines.length}`,
85+`${label} resource peak: memory=${maxObservedMemoryMiB.toFixed(1)}MiB cpu=${maxObservedCpuPercent.toFixed(1)}% samples=${parsedSamples}`,
5586);
56-if (lines.length === 0) {
87+if (parsedSamples === 0) {
5788throw new Error(`no docker stats samples captured for ${label}`);
5889}
5990if (maxObservedMemoryMiB > maxMemoryMiB) {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。