mailwolt/app/Livewire/Ui/Security/AuditLogsTable.php

84 lines
2.4 KiB
PHP

<?php
namespace App\Livewire\Ui\Security;
use Illuminate\Support\Str;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Attributes\Url;
use Livewire\Component;
#[Layout('layouts.dvx')]
#[Title('Audit-Logs · Mailwolt')]
class AuditLogsTable extends Component
{
#[Url(as: 'q', keep: true)]
public string $search = '';
#[Url(as: 'lvl', keep: true)]
public string $level = '';
public int $limit = 200;
public function loadMore(): void
{
$this->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'));
}
}