limit += 200; } private function parseLogs(): array { $logFile = storage_path('logs/laravel.log'); if (!is_readable($logFile)) return []; $fp = @fopen($logFile, 'r'); if (!$fp) return []; $size = filesize($logFile); $chunk = 250_000; fseek($fp, max(0, $size - $chunk)); $raw = fread($fp, $chunk); fclose($fp); if (!$raw) return []; $lines = explode("\n", $raw); $lines = array_slice($lines, -2000); $entries = []; $current = null; foreach ($lines as $line) { if (preg_match('/^\[(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2})[^\]]*\] \w+\.(\w+): (.+)/', $line, $m)) { if ($current !== null) $entries[] = $current; $current = [ 'time' => str_replace('T', ' ', $m[1]), 'level' => strtolower($m[2]), 'message' => trim($m[3]), ]; } elseif ($current !== null) { $current['message'] .= "\n" . trim($line); } } if ($current !== null) $entries[] = $current; $entries = array_reverse($entries); $filtered = []; foreach ($entries as $e) { if ($this->level && $e['level'] !== $this->level) continue; if ($this->search !== '' && !str_contains(strtolower($e['message']), strtolower($this->search))) continue; $e['message'] = Str::limit(preg_replace('/\s+/', ' ', $e['message']), 300); $filtered[] = $e; if (count($filtered) >= $this->limit) break; } return $filtered; } public function render() { $logs = $this->parseLogs(); $levels = ['', 'info', 'debug', 'warning', 'error', 'critical']; return view('livewire.ui.security.audit-logs-table', compact('logs', 'levels')); } }