Files
smartmetrics/ts/smartmetrics.sysusage.ts

95 lines
2.9 KiB
TypeScript

import * as fs from 'fs';
import * as os from 'os';
export interface ISystemUsageResult {
cpuPercent: number; // 0-100% system-wide CPU utilization
memTotalBytes: number; // total physical RAM
memAvailableBytes: number; // available memory
memUsedBytes: number; // memTotal - memAvailable
memUsedPercent: number; // 0-100%
loadAvg1: number; // 1-min load average
loadAvg5: number; // 5-min load average
loadAvg15: number; // 15-min load average
}
// History for system CPU delta tracking
interface ICpuSnapshot {
idle: number;
total: number;
}
let prevCpuSnapshot: ICpuSnapshot | null = null;
function readProcStat(): ICpuSnapshot | null {
try {
const content = fs.readFileSync('/proc/stat', 'utf8');
const firstLine = content.split('\n')[0]; // "cpu user nice system idle iowait irq softirq steal ..."
const parts = firstLine.split(/\s+/).slice(1).map(Number);
// parts: [user, nice, system, idle, iowait, irq, softirq, steal, ...]
const idle = parts[3] + (parts[4] || 0); // idle + iowait
const total = parts.reduce((sum, v) => sum + v, 0);
return { idle, total };
} catch {
return null;
}
}
function getMemoryInfo(): { totalBytes: number; availableBytes: number } {
try {
const content = fs.readFileSync('/proc/meminfo', 'utf8');
let memTotal = 0;
let memAvailable = 0;
for (const line of content.split('\n')) {
if (line.startsWith('MemTotal:')) {
memTotal = parseInt(line.split(/\s+/)[1], 10) * 1024; // kB to bytes
} else if (line.startsWith('MemAvailable:')) {
memAvailable = parseInt(line.split(/\s+/)[1], 10) * 1024;
}
}
if (memTotal > 0 && memAvailable > 0) {
return { totalBytes: memTotal, availableBytes: memAvailable };
}
} catch {
// fall through to os fallback
}
// Fallback using os module
const totalBytes = os.totalmem();
const availableBytes = os.freemem();
return { totalBytes, availableBytes };
}
export async function getSystemUsage(): Promise<ISystemUsageResult> {
// CPU
let cpuPercent = 0;
const currentSnapshot = readProcStat();
if (currentSnapshot && prevCpuSnapshot) {
const totalDelta = currentSnapshot.total - prevCpuSnapshot.total;
const idleDelta = currentSnapshot.idle - prevCpuSnapshot.idle;
if (totalDelta > 0) {
cpuPercent = ((totalDelta - idleDelta) / totalDelta) * 100;
}
}
if (currentSnapshot) {
prevCpuSnapshot = currentSnapshot;
}
// Memory
const mem = getMemoryInfo();
const memUsedBytes = mem.totalBytes - mem.availableBytes;
const memUsedPercent = mem.totalBytes > 0 ? (memUsedBytes / mem.totalBytes) * 100 : 0;
// Load averages
const [loadAvg1, loadAvg5, loadAvg15] = os.loadavg();
return {
cpuPercent,
memTotalBytes: mem.totalBytes,
memAvailableBytes: mem.availableBytes,
memUsedBytes,
memUsedPercent,
loadAvg1,
loadAvg5,
loadAvg15,
};
}