feat: implement system log detail view with dynamic status badges and optimize log file retrieval performance
This commit is contained in:
parent
37960a9dc5
commit
2552ca9511
@ -10,14 +10,10 @@
|
||||
|
||||
class LogController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of log entries.
|
||||
*/
|
||||
public function index(Request $request): Response
|
||||
{
|
||||
$logFiles = $this->getLogFiles();
|
||||
|
||||
// Default to the latest log file if not specified or doesn't exist
|
||||
$selectedFile = $request->input('file');
|
||||
|
||||
if (! $selectedFile || ! in_array($selectedFile, $logFiles)) {
|
||||
@ -33,9 +29,6 @@ public function index(Request $request): Response
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all .log files from storage/logs.
|
||||
*/
|
||||
private function getLogFiles(): array
|
||||
{
|
||||
$path = storage_path('logs');
|
||||
@ -46,16 +39,14 @@ private function getLogFiles(): array
|
||||
$files = File::files($path);
|
||||
|
||||
return collect($files)
|
||||
->map(fn ($file) => $file->getFilename())
|
||||
->filter(fn ($filename) => str_ends_with($filename, '.log'))
|
||||
->sortDesc() // Latest dates first
|
||||
->map(fn($file) => $file->getFilename())
|
||||
->filter(fn($filename) => str_ends_with($filename, '.log'))
|
||||
->sortDesc()
|
||||
->take(10)
|
||||
->values()
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a log file into an array of entries.
|
||||
*/
|
||||
private function parseLogFile($filename): array
|
||||
{
|
||||
$path = storage_path("logs/{$filename}");
|
||||
@ -63,12 +54,8 @@ private function parseLogFile($filename): array
|
||||
return [];
|
||||
}
|
||||
|
||||
// Limit file reading to prevent memory issues with huge logs
|
||||
// For simplicity, we read the whole file here, but in production consider chunking.
|
||||
$content = File::get($path);
|
||||
|
||||
// Pattern: [timestamp] environment.LEVEL: Message
|
||||
// Handles multi-line messages (like stack traces) using lookahead
|
||||
$pattern = '/^\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\] (\w+)\.(\w+): ([\s\S]*?)(?=\n^\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\]|$)/m';
|
||||
|
||||
preg_match_all($pattern, $content, $matches, PREG_SET_ORDER);
|
||||
@ -84,7 +71,6 @@ private function parseLogFile($filename): array
|
||||
];
|
||||
}
|
||||
|
||||
// Return latest logs first
|
||||
return array_reverse($logs);
|
||||
}
|
||||
}
|
||||
|
||||
18
resources/js/lib/log-helpers.ts
Normal file
18
resources/js/lib/log-helpers.ts
Normal file
@ -0,0 +1,18 @@
|
||||
export const getLevelColor = (level: string) => {
|
||||
switch (level.toUpperCase()) {
|
||||
case 'EMERGENCY':
|
||||
case 'ALERT':
|
||||
case 'CRITICAL':
|
||||
case 'ERROR':
|
||||
return 'destructive';
|
||||
case 'WARNING':
|
||||
return 'outline';
|
||||
case 'NOTICE':
|
||||
case 'INFO':
|
||||
return 'secondary';
|
||||
case 'DEBUG':
|
||||
return 'outline';
|
||||
default:
|
||||
return 'default';
|
||||
}
|
||||
}
|
||||
@ -2,7 +2,8 @@ import { Head, router } from '@inertiajs/react';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { DataTable } from '@/components/data-table';
|
||||
import { useState } from 'react';
|
||||
import { getColumns, SystemLog } from './partials/columns';
|
||||
import { getColumns } from './partials/columns';
|
||||
import { SystemLog } from '@/types';
|
||||
import system from '@/routes/system';
|
||||
import {
|
||||
Select,
|
||||
@ -78,6 +79,7 @@ export default function SystemLogIndex({ logFiles, selectedFile, logs }: Props)
|
||||
]
|
||||
}
|
||||
]}
|
||||
showSelection={false}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@ -4,38 +4,13 @@ import { Badge } from '@/components/ui/badge';
|
||||
import { Eye } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
|
||||
export interface SystemLog {
|
||||
id: number;
|
||||
timestamp: string;
|
||||
env: string;
|
||||
level: string;
|
||||
message: string;
|
||||
}
|
||||
import { SystemLog } from '@/types';
|
||||
import { getLevelColor } from '@/lib/log-helpers';
|
||||
|
||||
interface ColumnProps {
|
||||
onView: (log: SystemLog) => void;
|
||||
}
|
||||
|
||||
const getLevelColor = (level: string) => {
|
||||
switch (level.toUpperCase()) {
|
||||
case 'EMERGENCY':
|
||||
case 'ALERT':
|
||||
case 'CRITICAL':
|
||||
case 'ERROR':
|
||||
return 'destructive';
|
||||
case 'WARNING':
|
||||
return 'outline'; // Fallback if no warning variant
|
||||
case 'NOTICE':
|
||||
case 'INFO':
|
||||
return 'secondary';
|
||||
case 'DEBUG':
|
||||
return 'outline';
|
||||
default:
|
||||
return 'default';
|
||||
}
|
||||
}
|
||||
|
||||
export const getColumns = ({ onView }: ColumnProps): ColumnDef<SystemLog>[] => [
|
||||
{
|
||||
accessorKey: "timestamp",
|
||||
|
||||
@ -5,7 +5,8 @@ import {
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { SystemLog } from "./columns"
|
||||
import { SystemLog } from "@/types"
|
||||
import { getLevelColor } from "@/lib/log-helpers"
|
||||
|
||||
interface Props {
|
||||
log: SystemLog | null;
|
||||
@ -21,7 +22,7 @@ export function LogDetailModal({ log, onClose }: Props) {
|
||||
<DialogHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<DialogTitle>Detail Log</DialogTitle>
|
||||
<Badge variant="outline">{log.level}</Badge>
|
||||
<Badge variant={getLevelColor(log.level)}>{log.level}</Badge>
|
||||
<span className="text-sm text-muted-foreground">{log.timestamp}</span>
|
||||
</div>
|
||||
</DialogHeader>
|
||||
|
||||
@ -8,4 +8,5 @@ export type * from './payroll';
|
||||
export type * from './purchase';
|
||||
export type * from './general-setting';
|
||||
export type * from './activity';
|
||||
export type * from './system-log';
|
||||
|
||||
|
||||
7
resources/js/types/system-log.ts
Normal file
7
resources/js/types/system-log.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export interface SystemLog {
|
||||
id: number;
|
||||
timestamp: string;
|
||||
env: string;
|
||||
level: string;
|
||||
message: string;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user