From f8fc966cfcf9f58cd719259b744a93567a23ffe5 Mon Sep 17 00:00:00 2001 From: "Joseph.Rawlings" Date: Thu, 4 Dec 2025 18:34:50 -0500 Subject: [PATCH] feat: enhance firewall log loading in Proxmox by implementing batch fetching, improved error handling, and support for multiple response formats --- .../Servers/Proxmox/Livewire/Firewall.php | 112 ++++++++++++++++-- 1 file changed, 101 insertions(+), 11 deletions(-) diff --git a/extensions/Servers/Proxmox/Livewire/Firewall.php b/extensions/Servers/Proxmox/Livewire/Firewall.php index bb7cc370c..95b862f33 100644 --- a/extensions/Servers/Proxmox/Livewire/Firewall.php +++ b/extensions/Servers/Proxmox/Livewire/Firewall.php @@ -1093,23 +1093,113 @@ class Firewall extends Component public function loadFirewallLogs(): void { + $this->logError = ''; + try { - $response = $this->firewallRequest( - '/nodes/' . $this->server->node->name . '/qemu/' . $this->server->vm_id . '/firewall/log', - 'get', - ['limit' => $this->logLimit] - ); + // Fetch logs in batches to handle large log sets + $allRawLogs = []; + $start = 0; + $batchSize = 500; + $maxLogs = $this->logLimit; + + do { + $response = $this->firewallRequest( + '/nodes/' . $this->server->node->name . '/qemu/' . $this->server->vm_id . '/firewall/log', + 'get', + [ + 'limit' => $batchSize, + 'start' => $start + ] + ); - if ($response->successful()) { - $rawLogs = $response->json()['data'] ?? []; - $this->firewallLogs = $this->parseFirewallLogs($rawLogs); - $this->logError = ''; - } else { - $this->logError = 'Failed to load firewall logs'; + if (!$response->successful()) { + $this->logError = 'Failed to fetch logs (HTTP ' . $response->status() . ')'; + Log::warning('Firewall log API request failed', [ + 'status' => $response->status(), + 'server_id' => $this->server->id, + 'vm_id' => $this->server->vm_id, + ]); + $this->firewallLogs = []; + return; + } + + // Proxmox firewall log endpoint can return JSON or text/plain + $body = $response->body(); + $batchRawLogs = []; + + // Check content type + $contentType = $response->header('Content-Type'); + $isJson = str_contains($contentType ?? '', 'json'); + + if ($isJson) { + try { + $jsonData = $response->json(); + + if (isset($jsonData['data'])) { + if (is_array($jsonData['data'])) { + foreach ($jsonData['data'] as $item) { + if (is_array($item) && isset($item['t'])) { + $batchRawLogs[] = $item['t']; + } elseif (is_string($item)) { + $batchRawLogs[] = $item; + } + } + } elseif (is_string($jsonData['data'])) { + $lines = preg_split('/\r\n|\r|\n/', $jsonData['data']); + $batchRawLogs = array_filter($lines, fn($line) => !empty(trim($line))); + } + } elseif (is_array($jsonData)) { + foreach ($jsonData as $item) { + if (is_array($item) && isset($item['t'])) { + $batchRawLogs[] = $item['t']; + } elseif (is_string($item)) { + $batchRawLogs[] = $item; + } + } + } + } catch (\Exception $e) { + Log::warning('Failed to parse JSON response', ['error' => $e->getMessage()]); + } + } + + // Fall back to text/plain format + if (empty($batchRawLogs) && !empty($body)) { + $lines = preg_split('/\r\n|\r|\n/', $body); + $batchRawLogs = array_filter($lines, fn($line) => !empty(trim($line))); + } + + $batchRawLogs = array_values($batchRawLogs); + $allRawLogs = array_merge($allRawLogs, $batchRawLogs); + $fetchedCount = count($batchRawLogs); + $start += $batchSize; + + // Break if we got fewer logs than requested or reached limit + if ($fetchedCount < $batchSize || count($allRawLogs) >= $maxLogs) { + break; + } + } while (true); + + // Limit to maxLogs + if (count($allRawLogs) > $maxLogs) { + $allRawLogs = array_slice($allRawLogs, 0, $maxLogs); } + + Log::info('Firewall logs fetched from Proxmox API', [ + 'raw_count' => count($allRawLogs), + 'first_3_logs' => array_slice($allRawLogs, 0, 3) + ]); + + $this->firewallLogs = $this->parseFirewallLogs($allRawLogs); + + Log::info('Firewall log parsing summary', [ + 'total_raw_logs' => count($allRawLogs), + 'successfully_parsed' => count($this->firewallLogs), + ]); + } catch (\Exception $e) { $this->logError = 'Failed to load logs: ' . $e->getMessage(); Log::error('Firewall logs error: ' . $e->getMessage()); + $this->firewallLogs = []; } }