mirror of
https://github.com/HDInnovations/UNIT3D-Community-Edition.git
synced 2026-01-31 00:09:39 -06:00
146 lines
4.6 KiB
PHP
146 lines
4.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* NOTICE OF LICENSE.
|
|
*
|
|
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
|
* The details is bundled with this project in the file LICENSE.txt.
|
|
*
|
|
* @project UNIT3D Community Edition
|
|
*
|
|
* @author HDVinnie <hdinnovations@protonmail.com>
|
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
|
*/
|
|
|
|
namespace App\Http\Livewire;
|
|
|
|
use App\Traits\CastLivewireProperties;
|
|
use Illuminate\Pagination\LengthAwarePaginator;
|
|
use Illuminate\Support\Facades\File;
|
|
use Livewire\Attributes\Computed;
|
|
use Livewire\Attributes\Url;
|
|
use Livewire\Component;
|
|
use Livewire\WithPagination;
|
|
use SplFileInfo;
|
|
|
|
/**
|
|
* @property \Illuminate\Support\Collection $logFiles
|
|
* @property LengthAwarePaginator $entries
|
|
*/
|
|
class LaravelLogViewer extends Component
|
|
{
|
|
use CastLivewireProperties;
|
|
use WithPagination;
|
|
|
|
/**
|
|
* @var int[]|string[]
|
|
*/
|
|
public array $logs = [0];
|
|
|
|
public int $page = 1;
|
|
|
|
#[Url(history: true)]
|
|
public int $perPage = 5;
|
|
|
|
final public function updating(string $field, mixed &$value): void
|
|
{
|
|
$this->castLivewireProperties($field, $value);
|
|
}
|
|
|
|
final public function loadMore(): void
|
|
{
|
|
$this->perPage += 5;
|
|
}
|
|
|
|
#[Computed]
|
|
final public function logFiles()
|
|
{
|
|
$directory = storage_path('logs');
|
|
|
|
return collect(File::allFiles($directory))
|
|
->sortByDesc(fn (SplFileInfo $file) => $file->getMTime())->values();
|
|
}
|
|
|
|
/**
|
|
* @return \Illuminate\Pagination\LengthAwarePaginator<\Illuminate\Support\Collection<string|int, mixed>>
|
|
*/
|
|
#[Computed]
|
|
final public function entries(): LengthAwarePaginator
|
|
{
|
|
$files = $this->logFiles;
|
|
$logString = '';
|
|
|
|
foreach ($this->logs as $log) {
|
|
if ($files[$log] ?? []) {
|
|
$logString .= file_get_contents($files[$log]->getPathname());
|
|
}
|
|
}
|
|
|
|
$entryPattern = '/^\[(?<date>.*)\]\s(?<env>\w+)\.(?<level>\w+)\:\s/m';
|
|
$contextPattern = '/^(?<message>[^\{]*)?(?:\{"exception"\:"\[object\]\s\((?<exception>[^\s\(]+))?.*\s(?:in|at)\s(?<in>.*)\:(?<line>\d+)\)?/ms';
|
|
|
|
$entries = collect();
|
|
|
|
if (preg_match_all($entryPattern, $logString, $entryMatches, PREG_SET_ORDER) !== false) {
|
|
$stacktraces = preg_split($entryPattern, $logString);
|
|
// Delete the empty first entry
|
|
array_shift($stacktraces);
|
|
$numEntries = \count($entryMatches);
|
|
|
|
for ($i = 0; $i < $numEntries; $i++) {
|
|
// The context is the portion before the first stack trace
|
|
$context = preg_split('/^\[stacktrace\]|Stack trace\:/ms', (string) $stacktraces[$i])[0];
|
|
// The `context` consists of a message, an exception, a filename, and a linecount
|
|
preg_match($contextPattern, $context, $contextMatches);
|
|
|
|
$entries->push([
|
|
'date' => $entryMatches[$i]['date'],
|
|
'env' => $entryMatches[$i]['env'],
|
|
'level' => $entryMatches[$i]['level'],
|
|
'message' => $contextMatches['message'] ?? '',
|
|
'exception' => $contextMatches['exception'] ?? '',
|
|
'in' => $contextMatches['in'] ?? '',
|
|
'line' => $contextMatches['line'] ?? '',
|
|
'stacktrace' => $stacktraces[$i],
|
|
]);
|
|
}
|
|
}
|
|
|
|
$groupedEntries = $entries->groupBy(fn ($entry) => $entry['message'].'-'.$entry['exception'].'-'.$entry['in'].'-'.$entry['line']);
|
|
$currentEntries = $groupedEntries->forPage($this->page, $this->perPage);
|
|
|
|
return new LengthAwarePaginator($currentEntries, $groupedEntries->count(), $this->perPage, $this->page);
|
|
}
|
|
|
|
final public function clearLatestLog(): void
|
|
{
|
|
$latestLogFile = $this->logFiles->first();
|
|
|
|
if ($latestLogFile) {
|
|
File::put($latestLogFile->getPathname(), '');
|
|
}
|
|
}
|
|
|
|
final public function deleteAllLogs(): void
|
|
{
|
|
$directory = storage_path('logs');
|
|
$files = File::allFiles($directory);
|
|
|
|
foreach ($files as $file) {
|
|
File::delete($file->getPathname());
|
|
}
|
|
}
|
|
|
|
final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Contracts\Foundation\Application
|
|
{
|
|
return view('livewire.laravel-log-viewer', [
|
|
'files' => $this->logFiles,
|
|
'entries' => $this->entries,
|
|
])
|
|
->extends('layout.default')
|
|
->section('content');
|
|
}
|
|
}
|