feat: enhance firewall log loading in Proxmox by implementing batch fetching, improved error handling, and support for multiple response formats

This commit is contained in:
2025-12-04 18:34:50 -05:00
parent 8731fa4470
commit f8fc966cfc

View File

@@ -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 = [];
}
}