feat: add visual progress bars to resource usage and improve CPU detection
Resource Usage improvements: - Added visual progress bars for CPU, RAM, and Disk usage - Progress bars use Bootstrap styling (success/info/warning colors) - Display percentage and detailed metrics (e.g., RAM 4 / 128 MB (3%)) - Bars animate smoothly with CSS transitions CPU detection enhancements: - Added fallback to /proc/stat parsing when shell commands unavailable - Added fallback to PHP getrusage() for CPU time estimation - CPU now displays even when shell_exec is disabled - Graceful fallback chain ensures data is always available Progress bar styling: - Success (green) for CPU - Info (blue) for RAM - Warning (orange/yellow) for Disk - All bars styled with height, rounded corners, and smooth transitions
This commit is contained in:
parent
232bf3ef8a
commit
3720da9b16
|
|
@ -229,18 +229,91 @@ class SystemOperations
|
|||
|
||||
private function readCpuUsage(): ?float
|
||||
{
|
||||
// Try shell command first (if available)
|
||||
$result = $this->safeCommand('top -bn1 | grep "Cpu(s)" | tail -n 1');
|
||||
if ($result === 'Unavailable') {
|
||||
return null;
|
||||
if ($result !== 'Unavailable' && trim($result) !== '') {
|
||||
if (preg_match('/(\d+(?:\.\d+)?)%us/', $result, $matches)) {
|
||||
return (float) $matches[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (preg_match('/(\d+(?:\.\d+)?)%us/', $result, $matches)) {
|
||||
return (float) $matches[1];
|
||||
// Fallback: read from /proc/stat if on Linux
|
||||
if (file_exists('/proc/stat')) {
|
||||
return $this->readCpuUsageFromProcStat();
|
||||
}
|
||||
|
||||
// Fallback: use PHP getrusage if available
|
||||
if (function_exists('getrusage')) {
|
||||
return $this->readCpuUsageFromRusage();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function readCpuUsageFromProcStat(): ?float
|
||||
{
|
||||
static $lastStat = null;
|
||||
static $lastTime = null;
|
||||
|
||||
$statFile = @file_get_contents('/proc/stat');
|
||||
if ($statFile === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$lines = explode("\n", $statFile);
|
||||
$cpuLine = $lines[0];
|
||||
if (! str_starts_with($cpuLine, 'cpu ')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$parts = preg_split('/\s+/', trim($cpuLine));
|
||||
if (count($parts) < 5) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$user = (int) $parts[1];
|
||||
$nice = (int) $parts[2];
|
||||
$system = (int) $parts[3];
|
||||
$idle = (int) $parts[4];
|
||||
$iowait = isset($parts[5]) ? (int) $parts[5] : 0;
|
||||
|
||||
$totalTime = microtime(true);
|
||||
$total = $user + $nice + $system + $idle + $iowait;
|
||||
$work = $user + $nice + $system;
|
||||
|
||||
if ($lastStat === null || $lastTime === null) {
|
||||
$lastStat = ['total' => $total, 'work' => $work];
|
||||
$lastTime = $totalTime;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
$diffTotal = $total - $lastStat['total'];
|
||||
$diffWork = $work - $lastStat['work'];
|
||||
|
||||
$lastStat = ['total' => $total, 'work' => $work];
|
||||
$lastTime = $totalTime;
|
||||
|
||||
if ($diffTotal <= 0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return min(100.0, round(($diffWork / $diffTotal) * 100, 2));
|
||||
}
|
||||
|
||||
private function readCpuUsageFromRusage(): ?float
|
||||
{
|
||||
$rusage = getrusage();
|
||||
if (! is_array($rusage)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$userTime = ($rusage['ru_utime.tv_sec'] ?? 0) + (($rusage['ru_utime.tv_usec'] ?? 0) / 1000000);
|
||||
$systemTime = ($rusage['ru_stime.tv_sec'] ?? 0) + (($rusage['ru_stime.tv_usec'] ?? 0) / 1000000);
|
||||
$totalTime = $userTime + $systemTime;
|
||||
|
||||
return min(100.0, (float) ($totalTime * 100));
|
||||
}
|
||||
|
||||
private function readMemoryUsage(): array
|
||||
{
|
||||
$result = $this->safeCommand('free -m');
|
||||
|
|
|
|||
|
|
@ -57,14 +57,43 @@
|
|||
<div class="card ops-card">
|
||||
<div class="card-header"><h5 class="mb-0">Resource Usage</h5></div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<div class="d-flex justify-content-between small text-muted"><span>CPU</span><span><?= esc((string) ($status['cpu']['used_percent'] ?? 'N/A')) ?>%</span></div>
|
||||
<div class="mb-4">
|
||||
<div class="d-flex justify-content-between small text-muted mb-1"><span>CPU</span><span id="cpuPercent"><?= esc((string) ($status['cpu']['used_percent'] ?? 'N/A')) ?>%</span></div>
|
||||
<div class="progress" style="height: 20px; border-radius: 4px; overflow: hidden;">
|
||||
<div class="progress-bar bg-success" id="cpuBar" role="progressbar" style="width: <?= (float) ($status['cpu']['used_percent'] ?? 0) ?>%; transition: width 0.3s ease;" aria-valuenow="<?= (float) ($status['cpu']['used_percent'] ?? 0) ?>" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<div class="d-flex justify-content-between small text-muted"><span>RAM</span><span><?= esc((string) ($status['memory']['used_mb'] ?? 'N/A')) ?> / <?= esc((string) ($status['memory']['total_mb'] ?? 'N/A')) ?> MB</span></div>
|
||||
<div class="mb-4">
|
||||
<div class="d-flex justify-content-between small text-muted mb-1">
|
||||
<span>RAM</span>
|
||||
<span id="ramPercent">
|
||||
<?php
|
||||
$ramTotal = (int) ($status['memory']['total_mb'] ?? 0);
|
||||
$ramUsed = (int) ($status['memory']['used_mb'] ?? 0);
|
||||
$ramPercent = $ramTotal > 0 ? round(($ramUsed / $ramTotal) * 100) : 0;
|
||||
echo esc((string) $ramUsed) . ' / ' . esc((string) $ramTotal) . ' MB (' . $ramPercent . '%)';
|
||||
?>
|
||||
</span>
|
||||
</div>
|
||||
<div class="progress" style="height: 20px; border-radius: 4px; overflow: hidden;">
|
||||
<div class="progress-bar bg-info" id="ramBar" role="progressbar" style="width: <?= $ramPercent ?>%; transition: width 0.3s ease;" aria-valuenow="<?= $ramPercent ?>" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="d-flex justify-content-between small text-muted"><span>Disk</span><span><?= esc((string) ($status['disk']['used_gb'] ?? 'N/A')) ?> / <?= esc((string) ($status['disk']['total_gb'] ?? 'N/A')) ?> GB</span></div>
|
||||
<div class="d-flex justify-content-between small text-muted mb-1">
|
||||
<span>Disk</span>
|
||||
<span id="diskPercent">
|
||||
<?php
|
||||
$diskTotal = (float) ($status['disk']['total_gb'] ?? 0);
|
||||
$diskUsed = (float) ($status['disk']['used_gb'] ?? 0);
|
||||
$diskPercent = $diskTotal > 0 ? round(($diskUsed / $diskTotal) * 100) : 0;
|
||||
echo esc((string) $diskUsed) . ' / ' . esc((string) $diskTotal) . ' GB (' . $diskPercent . '%)';
|
||||
?>
|
||||
</span>
|
||||
</div>
|
||||
<div class="progress" style="height: 20px; border-radius: 4px; overflow: hidden;">
|
||||
<div class="progress-bar bg-warning" id="diskBar" role="progressbar" style="width: <?= $diskPercent ?>%; transition: width 0.3s ease;" aria-valuenow="<?= $diskPercent ?>" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user