logPath = WRITEPATH . 'logs/'; $this->session = session(); } /** * Display list of all log files */ public function index() { $logFiles = $this->getLogFiles(); $data = [ 'title' => 'Log Files', 'logFiles' => $logFiles ]; return $this->loadLayout('logs/index', $data); // return view('logs/index', $data); } /** * Get all log files sorted by date (latest first) */ private function getLogFiles() { $files = []; if (!is_dir($this->logPath)) { return $files; } $iterator = new \DirectoryIterator($this->logPath); foreach ($iterator as $fileInfo) { if ($fileInfo->isFile() && $fileInfo->getExtension() === 'log') { $files[] = [ 'name' => $fileInfo->getFilename(), 'path' => $fileInfo->getPathname(), 'size' => $this->formatBytes($fileInfo->getSize()), 'modified' => $fileInfo->getMTime(), 'modified_date' => date('Y-m-d H:i:s', $fileInfo->getMTime()) ]; } } // Sort by modified time (latest first) usort($files, function($a, $b) { return $b['modified'] - $a['modified']; }); return $files; } /** * View specific log file content */ public function view($filename = null) { if (!$filename) { return redirect()->to('/logs')->with('error', 'No log file specified'); } // Security: prevent directory traversal $filename = basename($filename); $filePath = $this->logPath . $filename; if (!file_exists($filePath)) { return redirect()->to('/logs')->with('error', 'Log file not found'); } // ✅ extract date from filename: log-YYYY-MM-DD.log if (preg_match('/log-(\d{4}-\d{2}-\d{2})\.log/', $filename, $match)) { $currentDate = $match[1]; $prevDate = date('Y-m-d', strtotime('-1 day', strtotime($currentDate))); $nextDate = date('Y-m-d', strtotime('+1 day', strtotime($currentDate))); $prevFile = "log-$prevDate.log"; $nextFile = "log-$nextDate.log"; $prevExists = file_exists($this->logPath . $prevFile); $nextExists = file_exists($this->logPath . $nextFile); } // Read log file content $content = file_get_contents($filePath); $logEntries = $this->parseLogFile($content); $data = [ 'title' => 'View Log: ' . $filename, 'filename' => $filename, 'logEntries' => $logEntries, 'prevFile' => $prevExists ? $prevFile : null, 'nextFile' => $nextExists ? $nextFile : null, 'fileSize' => $this->formatBytes(filesize($filePath)), 'lastModified' => date('Y-m-d H:i:s', filemtime($filePath)) ]; // print_r( $data); die; return $this->loadLayout('logs/view', $data); // return view('logs/view', $data); } /** * Parse log file into structured array */ private function parseLogFile($content) { $entries = []; $lines = explode("\n", $content); $currentEntry = null; // Messages to filter out $skipPatterns = [ '/Session: Class initialized using/', '/Session class already loaded/', ]; foreach ($lines as $line) { // Match CI4 log format: LEVEL - date --> message if (preg_match('/^(\w+)\s*-\s*(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})\s*-->\s*(.*)$/', $line, $matches)) { // Save previous entry if exists (before checking skip) if ($currentEntry !== null) { $entries[] = $currentEntry; $currentEntry = null; } // Check if this message should be skipped $shouldSkip = false; foreach ($skipPatterns as $pattern) { if (preg_match($pattern, $matches[3])) { $shouldSkip = true; break; } } if ($shouldSkip) { continue; } // Start new entry $currentEntry = [ 'level' => $matches[1], 'date' => $matches[2], 'message' => $matches[3] ]; } elseif ($currentEntry !== null && trim($line) !== '') { // Continuation of previous message $currentEntry['message'] .= "\n" . $line; } } // Add last entry if ($currentEntry !== null) { $entries[] = $currentEntry; } return array_reverse($entries); // Latest first } /** * Download log file */ public function download($filename = null) { if (!$filename) { return redirect()->to('/logs')->with('error', 'No log file specified'); } $filename = basename($filename); $filePath = $this->logPath . $filename; if (!file_exists($filePath)) { return redirect()->to('/logs')->with('error', 'Log file not found'); } return $this->response->download($filePath, null); } /** * Delete log file */ public function delete($filename = null) { if (!$filename) { return redirect()->to('/logs')->with('error', 'No log file specified'); } $filename = basename($filename); $filePath = $this->logPath . $filename; if (!file_exists($filePath)) { return redirect()->to('/logs')->with('error', 'Log file not found'); } if (unlink($filePath)) { return redirect()->to('/logs')->with('success', 'Log file deleted successfully'); } else { return redirect()->to('/logs')->with('error', 'Failed to delete log file'); } } /** * Format bytes to human readable format */ private function formatBytes($bytes, $precision = 2) { $units = ['B', 'KB', 'MB', 'GB', 'TB']; $bytes = max($bytes, 0); $pow = floor(($bytes ? log($bytes) : 0) / log(1024)); $pow = min($pow, count($units) - 1); $bytes /= pow(1024, $pow); return round($bytes, $precision) . ' ' . $units[$pow]; } /** * Clear all log files */ public function clearAll() { $logFiles = $this->getLogFiles(); $deleted = 0; foreach ($logFiles as $file) { if (unlink($file['path'])) { $deleted++; } } return redirect()->to('/logs')->with('success', $deleted . ' log file(s) deleted successfully'); } }