portalMonitor->vmMetrics($vmwareId); try { $storage = $this->portalMonitor->vmStorage($vmwareId); } catch (\RuntimeException) { $storage = []; } $provisionedDiskBytes = collect($storage['disks'] ?? [])->sum( fn ($disk) => is_array($disk) ? (int) ($disk['capacity_bytes'] ?? 0) : 0 ); $diskSummary = is_array($storage['summary'] ?? null) ? $storage['summary'] : []; return [ 'cpu_usage_percent' => $stats['cpu_usage_percent'] ?? null, 'cpu_cores' => $cpuCores, 'cpu_mhz' => $stats['cpu_mhz'] ?? null, 'cpu_ready_ms' => $stats['cpu_ready_ms'] ?? null, 'mem_usage_percent' => $stats['guest_memory_usage_percent'] ?? null, 'mem_usage_mb' => $stats['memory_active_mb'] ?? null, 'mem_consumed_mb' => $stats['memory_consumed_mb'] ?? null, 'mem_total_mb' => $memoryTotalMb, 'disk_read_bps' => $stats['disk_read_bps'] ?? null, 'disk_write_bps' => $stats['disk_write_bps'] ?? null, 'disk_latency_ms' => $stats['disk_latency_ms'] ?? null, 'disk_total_bytes' => $diskSummary['total_bytes'] ?? ($provisionedDiskBytes ?: null), 'disk_used_bytes' => $diskSummary['used_bytes'] ?? null, 'disk_usage_percent' => $diskSummary['usage_percent'] ?? null, 'network_rx_bps' => $stats['network_rx_bps'] ?? null, 'network_tx_bps' => $stats['network_tx_bps'] ?? null, 'timestamp' => $stats['timestamp'] ?? null, 'stale' => (bool) ($stats['stale'] ?? false), ]; } private const HISTORY_FIELDS = [ 'cpu' => 'cpu_usage_percent', 'mem' => 'guest_memory_usage_percent', 'disk_read_bps' => 'disk_read_bps', 'disk_write_bps' => 'disk_write_bps', 'net_rx_bps' => 'network_rx_bps', 'net_tx_bps' => 'network_tx_bps', ]; public function history(string $vmwareId, \DateTimeInterface $from, \DateTimeInterface $to, int $maxPoints = 240): array { $rows = $this->portalMonitor->vmHistory($vmwareId, $from, $to); $span = max(1, $to->getTimestamp() - $from->getTimestamp()); $bucket = max(1, (int) ceil($span / $maxPoints)); return collect($rows) ->filter(fn ($row) => is_array($row) && isset($row['timestamp'])) ->groupBy(fn ($row) => intdiv(strtotime($row['timestamp']), $bucket)) ->map(function ($group, $key) use ($bucket) { $point = ['t' => gmdate('c', $key * $bucket + intdiv($bucket, 2))]; foreach (self::HISTORY_FIELDS as $name => $source) { $values = $group->pluck($source)->filter(fn ($v) => $v !== null); $point[$name] = $values->isEmpty() ? null : round($values->avg(), 2); } return $point; }) ->sortKeys() ->values() ->all(); } }