99 lines
2.8 KiB
PHP
99 lines
2.8 KiB
PHP
<?php
|
|
/**
|
|
* @package Bicycle
|
|
* @author Egor Isaev
|
|
* @description FileLogReader.php
|
|
* @copyright (c) 24/06/2026
|
|
*/
|
|
|
|
namespace System\Classes;
|
|
|
|
/**
|
|
* Чтение логов из файлов {channel}-{Y-m-d}.log в каталоге Log::directory().
|
|
* Парсит строки формата "[Y-m-d H:i:s] LEVEL: message".
|
|
*/
|
|
class FileLogReader implements LogReader
|
|
{
|
|
/** @var int Максимум записей в выдаче */
|
|
public int $limit = 1000;
|
|
|
|
/** Регулярка строки лога: дата-время, уровень, сообщение */
|
|
private const LINE = '/^\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\] (\w+): (.*)$/';
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public function read(array $filters = []): array
|
|
{
|
|
$date = $filters['date'] ?? date('Y-m-d');
|
|
$channel = $filters['channel'] ?? 'action';
|
|
$level = strtolower((string)($filters['level'] ?? ''));
|
|
$q = (string)($filters['q'] ?? '');
|
|
|
|
$channels = $channel === 'all' ? ['action', 'error'] : [$channel];
|
|
$entries = [];
|
|
|
|
foreach ($channels as $ch) {
|
|
$file = Log::directory() . '/' . $ch . '-' . $date . '.log';
|
|
if (!is_file($file)) {
|
|
continue;
|
|
}
|
|
|
|
foreach (file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) {
|
|
if (!preg_match(self::LINE, $line, $m)) {
|
|
continue;
|
|
}
|
|
|
|
$entry = [
|
|
'datetime' => $m[1],
|
|
'level' => strtolower($m[2]),
|
|
'message' => $m[3],
|
|
'channel' => $ch,
|
|
];
|
|
|
|
if ($level !== '' && $entry['level'] !== $level) {
|
|
continue;
|
|
}
|
|
if ($q !== '' && stripos($line, $q) === false) {
|
|
continue;
|
|
}
|
|
|
|
$entries[] = $entry;
|
|
}
|
|
}
|
|
|
|
// Новые сверху (datetime сравним лексикографически).
|
|
usort($entries, static fn($a, $b) => strcmp($b['datetime'], $a['datetime']));
|
|
|
|
return array_slice($entries, 0, $this->limit);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public function dates(): array
|
|
{
|
|
$dir = Log::directory();
|
|
if (!is_dir($dir)) {
|
|
return [];
|
|
}
|
|
|
|
$files = array_merge(
|
|
glob($dir . '/action-*.log') ?: [],
|
|
glob($dir . '/error-*.log') ?: []
|
|
);
|
|
|
|
$dates = [];
|
|
foreach ($files as $file) {
|
|
if (preg_match('/-(\d{4}-\d{2}-\d{2})\.log$/', $file, $m)) {
|
|
$dates[$m[1]] = true;
|
|
}
|
|
}
|
|
|
|
$dates = array_keys($dates);
|
|
rsort($dates); // новые даты сверху
|
|
|
|
return $dates;
|
|
}
|
|
}
|