189 lines
6.9 KiB
PHP
189 lines
6.9 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Livewire\Admin;
|
|
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\Session;
|
|
use Livewire\Component;
|
|
|
|
class Log extends Component
|
|
{
|
|
public $logContent = '';
|
|
public $message = '';
|
|
public $diskUsage = '';
|
|
public $diskUsageClass = '';
|
|
public $availableRam;
|
|
public $availableRamClass;
|
|
public $queueWorkers = [];
|
|
public $queueWorkersCount = 0;
|
|
public $reverbConnected = false;
|
|
|
|
|
|
public function mount()
|
|
{
|
|
// Security check: user must be authenticated
|
|
if (!Auth::check()) {
|
|
abort(403, 'Unauthorized');
|
|
}
|
|
|
|
// Security check: activeProfileType must be 'App\Models\Admin'
|
|
if (getActiveProfileType() !== 'Admin') {
|
|
abort(403, 'Unauthorized');
|
|
}
|
|
|
|
// Security check: user must own the active profile
|
|
$activeProfile = getActiveProfile();
|
|
if (!$activeProfile) {
|
|
abort(403, 'Unauthorized');
|
|
}
|
|
|
|
// CRITICAL SECURITY: Validate user has ownership/access to this profile
|
|
\App\Helpers\ProfileAuthorizationHelper::authorize($activeProfile);
|
|
|
|
// Load log content - support both daily (laravel-YYYY-MM-DD.log) and single (laravel.log) drivers
|
|
$logPath = storage_path('logs/laravel-' . date('Y-m-d') . '.log');
|
|
if (!file_exists($logPath)) {
|
|
$logPath = storage_path('logs/laravel.log');
|
|
}
|
|
if (file_exists($logPath)) {
|
|
$logLines = (int) timebank_config('admin_settings.log_lines', 100);
|
|
$this->logContent = shell_exec("tail -n {$logLines} " . escapeshellarg($logPath));
|
|
// Use tail output to check for warnings/errors (avoid file() which loads entire file into memory)
|
|
$recentLines = explode("\n", $this->logContent ?? '');
|
|
|
|
$messages = [];
|
|
if (collect($recentLines)->contains(fn ($line) => stripos($line, 'WARNING') !== false)) {
|
|
$messages[] = '<span class="font-bold text-orange-500">Warning</span> detected in the recent log output';
|
|
}
|
|
if (collect($recentLines)->contains(fn ($line) => stripos($line, 'ERROR') !== false)) {
|
|
$messages[] = '<span class="font-bold text-red-500">Error</span> detected in the recent log output';
|
|
}
|
|
if (collect($recentLines)->contains(fn ($line) => stripos($line, 'CRITICAL') !== false)) {
|
|
$messages[] = '<span class="font-bold text-red-500">Critical</span> issue detected in the recent log output';
|
|
}
|
|
if (collect($recentLines)->contains(fn ($line) => stripos($line, 'ALERT') !== false)) {
|
|
$messages[] = '<span class="font-bold text-red-500">Alert</span> detected in the recent log output - IMMEDIATE ACTION REQUIRED';
|
|
}
|
|
$this->message = implode('<br>', $messages);
|
|
}
|
|
|
|
// Get disk usage
|
|
$free = disk_free_space("/");
|
|
$total = disk_total_space("/");
|
|
$used = $total - $free;
|
|
$percent = $total > 0 ? round(($used / $total) * 100, 1) : 0;
|
|
|
|
|
|
// Determine disk usage color class
|
|
if ($percent > 90) {
|
|
$this->diskUsageClass = 'text-red-500';
|
|
} elseif ($percent > 75) {
|
|
$this->diskUsageClass = 'text-orange-500';
|
|
} else {
|
|
$this->diskUsageClass = 'text-green-500';
|
|
}
|
|
|
|
$this->diskUsage = sprintf(
|
|
'%s used of %s (%.1f%%)',
|
|
$this->formatBytes($used),
|
|
$this->formatBytes($total),
|
|
$percent
|
|
);
|
|
|
|
|
|
|
|
// Get RAM memory information
|
|
$meminfo = file_get_contents('/proc/meminfo');
|
|
preg_match('/MemTotal:\s+(\d+)/', $meminfo, $matchesTotal);
|
|
preg_match('/MemAvailable:\s+(\d+)/', $meminfo, $matchesAvailable);
|
|
|
|
$totalKb = $matchesTotal[1] ?? 0;
|
|
$availableKb = $matchesAvailable[1] ?? 0;
|
|
$usedKb = $totalKb - $availableKb;
|
|
|
|
$percentRam = $totalKb > 0 ? round(($usedKb / $totalKb) * 100, 1) : 0;
|
|
|
|
$this->availableRam = sprintf(
|
|
'%s used of %s (%.1f%%)',
|
|
$this->formatBytes($usedKb * 1024),
|
|
$this->formatBytes($totalKb * 1024),
|
|
$percentRam
|
|
);
|
|
|
|
if ($percentRam > 90) {
|
|
$this->availableRamClass = 'text-red-500';
|
|
} elseif ($percentRam > 75) {
|
|
$this->availableRamClass = 'text-orange-500';
|
|
} else {
|
|
$this->availableRamClass = 'text-green-500';
|
|
}
|
|
|
|
|
|
// Check running queue workers
|
|
$queueWorkers = [];
|
|
exec("ps aux | grep 'artisan queue:work' | grep -v grep", $output);
|
|
foreach ($output as $line) {
|
|
// Parse $line for more details
|
|
$queueWorkers[] = $line;
|
|
}
|
|
$this->queueWorkers = $queueWorkers;
|
|
$this->queueWorkersCount = count($queueWorkers);
|
|
|
|
// Check Reverb server connection (example: check if port is open)
|
|
$reverbPort = env('REVERB_PORT', 6001);
|
|
|
|
// Check Reverb server connection
|
|
$reverbConnected = false;
|
|
$connection = @fsockopen('127.0.0.1', $reverbPort, $errno, $errstr, 1);
|
|
if ($connection) {
|
|
$reverbConnected = true;
|
|
fclose($connection);
|
|
}
|
|
|
|
$this->reverbConnected = $reverbConnected;
|
|
|
|
|
|
}
|
|
|
|
// Helper to format bytes
|
|
public function formatBytes($bytes, $precision = 2)
|
|
{
|
|
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
$bytes = max($bytes, 0);
|
|
$pow = $bytes > 0 ? floor(log($bytes) / log(1024)) : 0;
|
|
$pow = min($pow, count($units) - 1);
|
|
$bytes /= (1 << (10 * $pow));
|
|
return round($bytes, $precision) . ' ' . $units[$pow];
|
|
}
|
|
|
|
public function downloadLog()
|
|
{
|
|
$logPath = storage_path('logs/laravel-' . date('Y-m-d') . '.log');
|
|
if (!file_exists($logPath)) {
|
|
$logPath = storage_path('logs/laravel.log');
|
|
}
|
|
if (file_exists($logPath)) {
|
|
return response()->download($logPath, 'laravel-' . date('Y-m-d') . '.log');
|
|
}
|
|
|
|
session()->flash('error', 'Log file not found');
|
|
}
|
|
|
|
public function render()
|
|
{
|
|
$layout = Auth::check() ? 'app-layout' : 'guest-layout';
|
|
return view('livewire.admin.log', [
|
|
'layout' => $layout,
|
|
'logContent' => $this->logContent,
|
|
'message' => $this->message,
|
|
'diskUsage' => $this->diskUsage,
|
|
'diskUsageClass' => $this->diskUsageClass,
|
|
'availableRam' => $this->availableRam,
|
|
'availableRamClass' => $this->availableRamClass,
|
|
'queueWorkers' => $this->queueWorkers,
|
|
'queueWorkersCount' => $this->queueWorkersCount,
|
|
'reverbConnected' => $this->reverbConnected,
|
|
]);
|
|
}
|
|
}
|