I was having a lot of problems displaying log files in the admin area of my application. The Logfiles were being written to following each transaction, and a typical daily log file could be up to 10MB. The best available packages would crash and burn with this size of logfile.
In TALL stack style, the logfiles are displayed using Tailwind.
app/Http/Livewire/LogsViewer.php
Copy <? php
namespace App \ Http \ Livewire ;
use Illuminate \ Support \ Facades \ File ;
use Livewire \ Component ;
use SplFileInfo ;
class LogsViewer extends Component
{
public $file = 0 ;
public $page = 1 ;
public $total;
public $perPage = 500 ;
public $paginator;
protected $queryString = [ 'page' ];
public function render ()
{
$files = $this -> getLogfiles () ;
$log = collect ( file ( $files[ $this -> file] -> getPathname (), FILE_IGNORE_NEW_LINES )) ;
$this -> total = intval ( floor ( $log -> count () / $this -> perPage )) + 1 ;
$log = $log -> slice ( ( $this -> page - 1 ) * $this -> perPage , $this -> perPage ) -> values () ;
return view ( 'livewire.logs-viewer' ) -> withFiles ( $files ) -> withLog ( $log ) ;
}
protected function getLogFiles ()
{
$directory = storage_path ( 'logs' ) ;
return collect ( File :: allFiles ( $directory ))
-> sortByDesc ( function ( SplFileInfo $file) {
return $file -> getMTime () ;
} ) -> values () ;
}
public function goto ($page)
{
$this -> page = $page;
}
public function updatingFile ()
{
$this -> page = 1 ;
}
}
Of note here is the detection of the [stackdump] sections, moving these to a nested block and hiding that block using Alpine. Clicking the [stackdump]
in the log expands the nested section and reveals the stack dump.
resources/views/livewire/logs-viewer.blade.php
Copy < div >
< x - slot name = "header" >
< h2 class= "text-xl font-semibold leading-tight text-gray-800" >
Log Files
</ h2 >
</ x - slot >
< div class= "px-4 py-2 mx-4 my-8 bg-white shadow-xl sm:rounded-lg" >
< div class= "flex justify-around" >
< select wire:model = "file" class= "px-4 py-2 font-mono text-sm bg-red-200 rounded" >
@foreach ($files as $file)
< option value = "{{ $loop -> index }}" > {{ $file -> getFilename () }} </ option >
@endforeach
</ select >
</ div >
@include ( 'layouts.logs-paginator' )
@if ($log -> count () > 0 )
< ul class= 'font-mono text-xs' >
@for ($i = 0 ; $i < $log -> count () ; $i ++ )
@if(Illuminate\Support\Str::startsWith($log[$i],'[stacktrace]') || Illuminate\Support\Str::startsWith($log[$i],'#'))
< li x - data = "{expanded:false}" x - on :click = "expanded = !expanded" > [stacktrace]
< ul class= "ml-8" x - show = "expanded" x - cloak >
@while ($i < $log -> count () )
< li wire:key = "{{$page}}-line-{{ $i }}" > {{ $log[$i] }} </ li >
@break ( Illuminate \ Support \ Str :: startsWith ( $log[$i ++ ] , '"}' ) )
@endwhile
</ ul >
</ li >
@endif
@break ($i >= $log -> count () )
< li wire:key = "{{ $page }}-line-{{ $i }}" class= "font-mono text-xs leading-5
{{ Illuminate\Support\Str::contains($log[$i], '.CRITICAL:') ? 'text-red-800':''}}
{{ Illuminate\Support\Str::contains($log[$i], '.ERROR:') ? 'text-orange-600':'' }}
{{ Illuminate\Support\Str::contains($log[$i], '.INFO:') ? 'text-blue-900':'' }}
{{ Illuminate\Support\Str::contains($log[$i], '.WARNING:') ? 'text-indigo-700':'' }}
" > {{ $log[$i] }}
</ li >
@endfor
</ ul >
@endif
</ div >
</ div >
resources/views/layouts/logs-paginator.blade.php
Copy < div class= "flex float-right" >
<button id="first" wire:click="goto(1)" class="w-10 outline-none px-2 border rounded-l-lg m-0 {{ $page==1 ? 'bg-gray-600 text-white font-bold' :'' }}" >1</button>
@if ($page - 4 > 1 )
< button id = "dots1" class= "w-10 px-2 m-0 -ml-px border outline-none" >& hellip; </ button >
@endif
@if ($page - 3 > 1 )
<button id="minus3" class="w-10 px-2 m-0 -ml-px border outline-none" wire:click="goto({{ $page-3 }})">{{ $page-3 }}</button>
@endif
@if ($page - 2 > 1 )
<button id="minus2" class="w-10 px-2 m-0 -ml-px border outline-none" wire:click="goto({{ $page-2 }})">{{ $page-2 }}</button>
@endif
@if ($page - 1 > 1 )
<button id="minus1" class="w-10 px-2 m-0 -ml-px border outline-none" wire:click="goto({{ $page-1 }})">{{ $page-1 }}</button>
@endif
@if ($page != 1 && $page != $total )
<button id="current" class="w-10 px-2 m-0 -ml-px font-bold text-white bg-gray-600 border outline-none">{{ $page }}</button>
@endif
@if ($page + 1 < $total )
<button id="plus1" class="w-10 px-2 m-0 -ml-px border outline-none" wire:click="goto({{ $page+1 }})">{{ $page+1 }}</button>
@endif
@if ($page + 2 < $total )
<button id="plus2" class="w-10 px-2 m-0 -ml-px border outline-none" wire:click="goto({{ $page+2 }})">{{ $page+2 }}</button>
@endif
@if ($page + 3 < $total )
<button id="plus3" class="w-10 px-2 m-0 -ml-px border outline-none" wire:click="goto({{ $page+3 }})">{{ $page+3 }}</button>
@endif
@if ($page + 4 < $total )
< button id = "dots2" class= "w-10 px-2 m-0 -ml-px border outline-none" >& hellip; </ button ></ button >
@endif
@if ($total > 1 )
<button id="last" class="rounded-r-lg w-10 outline-none px-2 border -ml-px m-0 {{ $page == $total ? 'text-white bg-gray-600 font-bold':'' }}" wire:click="goto({{ $total }})">{{ $total }}</button>
@endif
</ div >