fix: CPU via cgroup v2 usage_usec (mesure precise conteneur LXC) + RAM formule free

This commit is contained in:
manus-admin 2026-06-01 01:39:27 +02:00
parent 664963b8f7
commit 78ba7b9f54
1 changed files with 30 additions and 9 deletions

View File

@ -186,17 +186,38 @@ function getServerMetrics() {
// Lecture directe de /proc (monté depuis l'hôte via le namespace PID du conteneur) // Lecture directe de /proc (monté depuis l'hôte via le namespace PID du conteneur)
// Pas besoin de nsenter : /proc dans le conteneur reflète l'hôte // Pas besoin de nsenter : /proc dans le conteneur reflète l'hôte
// CPU : delta /proc/stat sur 300ms // CPU : mesure via cgroup v2 usage_usec (méthode précise pour conteneur LXC)
// Fallback sur /proc/stat normalisé par nproc si cgroup v2 non disponible
let cpuUsage = 0; let cpuUsage = 0;
try { try {
const parseCpuLine = (line) => line.trim().split(/\s+/).slice(1).map(Number); const ncpu = parseInt(execSync('nproc').toString().trim()) || 1;
const s1 = parseCpuLine(fs.readFileSync('/proc/stat', 'utf8').split('\n').find(l => l.startsWith('cpu '))); const cgroupPath = '/sys/fs/cgroup/cpu.stat';
execSync("sleep 0.3"); const readUsageUsec = () => {
const s2 = parseCpuLine(fs.readFileSync('/proc/stat', 'utf8').split('\n').find(l => l.startsWith('cpu '))); const stat = fs.readFileSync(cgroupPath, 'utf8');
const idle1 = s1[3], total1 = s1.reduce((a,b)=>a+b,0); const m = stat.match(/^usage_usec\s+(\d+)/m);
const idle2 = s2[3], total2 = s2.reduce((a,b)=>a+b,0); return m ? parseInt(m[1]) : null;
const dIdle = idle2 - idle1, dTotal = total2 - total1; };
cpuUsage = dTotal > 0 ? Math.round((1 - dIdle / dTotal) * 100) : 0; const u1 = readUsageUsec();
if (u1 !== null) {
// Méthode cgroup v2 : mesure la consommation CPU réelle du conteneur
execSync('sleep 0.5');
const u2 = readUsageUsec();
// delta en microsecondes / (500ms * ncpu) = % CPU du conteneur
const deltaUs = u2 - u1;
cpuUsage = Math.min(100, Math.round(deltaUs / (500000 * ncpu) * 100));
} else {
// Fallback : /proc/stat normalisé par nproc
const parseCpuLine = (line) => line.trim().split(/\s+/).slice(1).map(Number);
const s1 = parseCpuLine(fs.readFileSync('/proc/stat', 'utf8').split('\n').find(l => l.startsWith('cpu ')));
execSync('sleep 0.3');
const s2 = parseCpuLine(fs.readFileSync('/proc/stat', 'utf8').split('\n').find(l => l.startsWith('cpu ')));
const idle1 = s1[3], total1 = s1.reduce((a,b)=>a+b,0);
const idle2 = s2[3], total2 = s2.reduce((a,b)=>a+b,0);
const dIdle = idle2 - idle1, dTotal = total2 - total1;
const rawCpu = dTotal > 0 ? (1 - dIdle / dTotal) * 100 : 0;
// Normaliser par nproc pour éviter l'effet nœud physique sur LXC
cpuUsage = Math.round(rawCpu / ncpu);
}
} catch(e) {} } catch(e) {}
// RAM : lecture de /proc/meminfo (valeurs réelles via lxcfs) // RAM : lecture de /proc/meminfo (valeurs réelles via lxcfs)