95 lines
2.9 KiB
TypeScript
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,
|
|
};
|
|
}
|