mirror of
https://github.com/RGJorge/ContainerFlow.git
synced 2026-08-03 07:21:42 +02:00
v0.0.30
This commit is contained in:
+39
-4
@@ -1,6 +1,34 @@
|
||||
import { docker } from "./docker";
|
||||
import type { Service, Stats, DockerEvent } from "../shared/types";
|
||||
|
||||
/** Compute real memory usage by subtracting reclaimable page cache.
|
||||
* Mirrors `docker stats` CLI logic. Works for cgroup v1 and v2.
|
||||
*
|
||||
* Why: memory_stats.usage includes the kernel page cache (file-backed pages
|
||||
* the kernel keeps in RAM "just in case"). That cache is INSTANTLY reclaimable
|
||||
* under memory pressure and is NOT real usage. Containers with heavy I/O
|
||||
* (DBs, collectors) appear at 90-100% when actually using 10-15%.
|
||||
*
|
||||
* Returns: { real, cache, anon, total, limit } all in bytes. */
|
||||
export function computeMemoryBreakdown(memoryStats: any): {
|
||||
real: number;
|
||||
cache: number;
|
||||
anon: number;
|
||||
total: number;
|
||||
limit: number;
|
||||
} {
|
||||
const total = memoryStats?.usage ?? 0;
|
||||
const limit = memoryStats?.limit ?? 0;
|
||||
const s = memoryStats?.stats ?? {};
|
||||
// cgroup v2: 'inactive_file'
|
||||
// cgroup v1: 'total_inactive_file' (recursive) or 'cache' (legacy)
|
||||
const cache = s.inactive_file ?? s.total_inactive_file ?? s.cache ?? 0;
|
||||
// anon = process memory (heap, stack). cgroup v2: 'anon'. cgroup v1: 'rss' or 'total_rss'.
|
||||
const anon = s.anon ?? s.total_rss ?? s.rss ?? 0;
|
||||
const real = Math.max(0, total - cache);
|
||||
return { real, cache, anon, total, limit };
|
||||
}
|
||||
|
||||
export async function pollStats(services: Service[]): Promise<Stats[]> {
|
||||
const running = services.filter((s) => s.state === "running");
|
||||
const results: Stats[] = [];
|
||||
@@ -30,14 +58,21 @@ export async function pollStats(services: Service[]): Promise<Stats[]> {
|
||||
? (cpuHost * 100000 / svc.cpu_quota)
|
||||
: cpuHost;
|
||||
|
||||
const memUsage = raw.memory_stats.usage || 0;
|
||||
const memLimit = raw.memory_stats.limit || 1;
|
||||
const mb = computeMemoryBreakdown(raw.memory_stats);
|
||||
const memLimit = mb.limit || 1;
|
||||
const TO_MB = 1024 * 1024;
|
||||
|
||||
results.push({
|
||||
service: svc.uid,
|
||||
cpu: parseFloat(cpu.toFixed(2)),
|
||||
mem_mb: parseFloat((memUsage / 1024 / 1024).toFixed(1)),
|
||||
mem_percent: parseFloat(((memUsage / memLimit) * 100).toFixed(1)),
|
||||
mem_mb: parseFloat((mb.real / TO_MB).toFixed(1)),
|
||||
mem_percent: parseFloat(((mb.real / memLimit) * 100).toFixed(1)),
|
||||
mem_breakdown: {
|
||||
anon_mb: parseFloat((mb.anon / TO_MB).toFixed(1)),
|
||||
cache_mb: parseFloat((mb.cache / TO_MB).toFixed(1)),
|
||||
total_mb: parseFloat((mb.total / TO_MB).toFixed(1)),
|
||||
limit_mb: parseFloat((mb.limit / TO_MB).toFixed(1)),
|
||||
},
|
||||
});
|
||||
} catch {
|
||||
// Container may have stopped between discovery and stats
|
||||
|
||||
Reference in New Issue
Block a user