nhance/app/Controllers/LogController.php
2026-02-20 15:26:00 +05:30

146 lines
5.0 KiB
PHP

<?php
namespace App\Controllers;
use App\Controllers\BaseController;
class LogController extends BaseController
{
private $logPath;
public function __construct()
{
$this->logPath = WRITEPATH . 'logs/';
}
public function index()
{
$data = [
'title' => 'Log Files',
'logFiles' => $this->getLogFiles()
];
return view('logs/index', $data);
}
public function view($filename = null)
{
if (!$filename) return redirect()->to('/logs');
$filename = basename($filename);
$filePath = $this->logPath . $filename;
if (!file_exists($filePath)) return redirect()->to('/logs');
$db = \Config\Database::connect();
// 1. Fetch TPA List for the first row of tabs
$tpaConfigs = $db->table('tpa_log_config')->get()->getResultArray();
// 2. Dynamically get Action buttons from table columns
$allColumns = $db->getFieldNames('tpa_log_config');
$dynamicKeys = [];
foreach ($allColumns as $column) {
if ($column !== 'tpa_name') {
// Formatting: 'claim_push_key' -> 'Claim Push'
$label = str_replace(['_key', '_'], ['', ' '], $column);
$dynamicKeys[$column] = ucwords($label);
}
}
$selectedTpa = $this->request->getGet('tpa');
$selectedKey = $this->request->getGet('key');
$searchTerm = $this->request->getGet('search');
// Parse logs with current filters
$logEntries = $this->parseLogFileOptimized($filePath, $tpaConfigs, $selectedTpa, $selectedKey, $searchTerm);
// Date Pagination
$prevFile = $nextFile = null;
if (preg_match('/log-(\d{4}-\d{2}-\d{2})\.log/', $filename, $match)) {
$currentDate = $match[1];
$prevD = date('Y-m-d', strtotime('-1 day', strtotime($currentDate)));
$nextD = date('Y-m-d', strtotime('+1 day', strtotime($currentDate)));
if (file_exists($this->logPath . "log-$prevD.log")) $prevFile = "log-$prevD.log";
if (file_exists($this->logPath . "log-$nextD.log")) $nextFile = "log-$nextD.log";
}
$data = [
'title' => 'TPA Logs: ' . $filename,
'filename' => $filename,
'logEntries' => $logEntries,
'tpaConfigs' => $tpaConfigs,
'dynamicKeys' => $dynamicKeys, // Dynamic Buttons
'selectedTpa' => $selectedTpa,
'selectedKey' => $selectedKey,
'searchTerm' => $searchTerm,
'prevFile' => $prevFile,
'nextFile' => $nextFile
];
return view('logs/view', $data);
}
private function parseLogFileOptimized($path, $configs, $tpaName, $keyType, $searchTerm)
{
$entries = [];
$handle = fopen($path, 'r');
if (!$handle) return [];
$filters = [];
if ($tpaName) {
$filters[] = $tpaName;
if ($keyType) {
foreach ($configs as $conf) {
if ($conf['tpa_name'] === $tpaName && isset($conf[$keyType])) {
$filters[] = $conf[$keyType];
}
}
}
}
if ($searchTerm) $filters[] = $searchTerm;
$currentEntry = null;
while (($line = fgets($handle)) !== false) {
if (preg_match('/^(\w+)\s*-\s*(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})\s*-->\s*(.*)$/', $line, $matches)) {
if ($currentEntry && $this->matchesFilters($currentEntry['message'], $filters)) {
$entries[] = $currentEntry;
}
$currentEntry = ['level' => $matches[1], 'date' => $matches[2], 'message' => $matches[3]];
} elseif ($currentEntry !== null && trim($line) !== '') {
$currentEntry['message'] .= "\n" . $line;
}
}
if ($currentEntry && $this->matchesFilters($currentEntry['message'], $filters)) $entries[] = $currentEntry;
fclose($handle);
return array_reverse($entries);
}
private function matchesFilters($message, $filters)
{
if (empty($filters)) return false;
foreach ($filters as $f) {
if (stripos($message, $f) === false) return false;
}
return true;
}
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(),
'size' => round($fileInfo->getSize() / 1024, 2) . ' KB',
'modified_date' => date('Y-m-d H:i:s', $fileInfo->getMTime()),
'ts' => $fileInfo->getMTime()
];
}
}
usort($files, fn($a, $b) => $b['ts'] - $a['ts']);
return $files;
}
}