"use client" import { useEffect, useState, useMemo } from "react" import { useRouter } from "next/navigation" import { api } from "@/lib/api" import { Header } from "@/components/Header" import { Card, CardContent } from "@/components/ui/card" import { Button } from "@/components/ui/button" import { RefreshCw, Filter, X } from "lucide-react" type LogEntry = { text: string date?: Date unit?: string level?: "err" | "warning" | "info" | "debug" } export default function Logs() { const router = useRouter() const [allLogs, setAllLogs] = useState([]) const [loading, setLoading] = useState(true) const [limit, setLimit] = useState(500) // Filter states const [timeRange, setTimeRange] = useState("all") // all, 24h, 7d, 30d const [priority, setPriority] = useState("all") // all, err (error and higher) const [unit, setUnit] = useState("") // Unit/Service filter const [searchText, setSearchText] = useState("") // Free text search const [units, setUnits] = useState([]) // Available units for dropdown useEffect(() => { // Check authentication const token = localStorage.getItem("access_token") if (!token) { router.push("/login") return } // Load logs loadLogs() }, [router]) useEffect(() => { // Reload when limit changes loadLogs() }, [limit]) const loadLogs = async () => { setLoading(true) try { const data = await api.getSystemLogs(limit) const logsList = data?.logs || [] setAllLogs(logsList) // Extract unique units for dropdown const uniqueUnits = new Set() logsList.forEach((log: string) => { const match = log.match(/\s(\S+)\[(\d+)\]:|systemd(\[[\d.]+\])?:|(\S+):/) if (match) { const unitName = match[1] || match[3] || match[4] || "" if (unitName && unitName !== "kernel") { uniqueUnits.add(unitName) } } }) setUnits(Array.from(uniqueUnits).sort()) } catch (error) { console.error("Failed to load logs:", error) setAllLogs([]) } finally { setLoading(false) } } // Parse log entry to extract metadata const parseLogEntry = (logText: string): LogEntry => { const entry: LogEntry = { text: logText } // Try to parse date from log (format: "MMM DD HH:MM:SS") const dateMatch = logText.match(/^(\w+\s+\d+\s+\d{2}:\d{2}:\d{2})/) if (dateMatch) { try { const now = new Date() const dateStr = `${dateMatch[1]} ${now.getFullYear()}` const parsed = new Date(dateStr) if (!isNaN(parsed.getTime())) { entry.date = parsed } } catch (e) { // Date parsing failed, continue } } // Extract unit/service name const unitMatch = logText.match(/\s(\S+?)\[(\d+)\]:|systemd(\[[\d.]+\])?:|(\S+):/) if (unitMatch) { entry.unit = unitMatch[1] || unitMatch[3] || unitMatch[4] || "" } // Detect priority level if (logText.match(/ERROR|err|Err|ERR|error/i)) { entry.level = "err" } else if (logText.match(/WARN|warn|WARNING/i)) { entry.level = "warning" } else if (logText.match(/INFO|info|Notice|NOTICE/i)) { entry.level = "info" } else { entry.level = "debug" } return entry } // Filter logs based on selected criteria const filteredLogs = useMemo(() => { return allLogs.filter((logText) => { const entry = parseLogEntry(logText) // Time filter if (timeRange !== "all" && entry.date) { let cutoffDate = new Date() switch (timeRange) { case "24h": cutoffDate.setHours(cutoffDate.getHours() - 24) break case "7d": cutoffDate.setDate(cutoffDate.getDate() - 7) break case "30d": cutoffDate.setDate(cutoffDate.getDate() - 30) break } if (entry.date < cutoffDate) return false } // Priority filter if (priority === "err") { if (entry.level !== "err") return false } // Unit filter if (unit && entry.unit) { if (!entry.unit.toLowerCase().includes(unit.toLowerCase())) return false } // Text search filter if (searchText) { if (!logText.toLowerCase().includes(searchText.toLowerCase())) return false } return true }) }, [allLogs, timeRange, priority, unit, searchText]) const hasActiveFilters = timeRange !== "all" || priority !== "all" || unit || searchText return (

System Logs

Showing {filteredLogs.length} of {allLogs.length} entries

{/* Filter Section */}
{/* Time Range Filter */}
{/* Priority Filter */}
{/* Unit Filter */}
{/* Free Text Search */}
setSearchText(e.target.value)} className="w-full px-3 py-2 rounded-md border border-border bg-background text-sm" />
{/* Active Filters Display */} {hasActiveFilters && (
Aktive Filter: {timeRange !== "all" && ( {timeRange === "24h" ? "Letzte 24h" : timeRange === "7d" ? "Letzte 7 Tage" : "Letzte 30 Tage"} )} {priority === "err" && ( Nur Fehler )} {unit && ( {unit} )} {searchText && ( "{searchText}" )}
)}
{/* Logs Display */}
{filteredLogs.length === 0 ? (
{loading ? "Loading logs..." : "No logs found matching filters"}
) : ( filteredLogs.map((log: string, idx: number) => { const entry = parseLogEntry(log) const bgColor = entry.level === "err" ? "bg-red-500/5 hover:bg-red-500/10" : entry.level === "warning" ? "bg-yellow-500/5 hover:bg-yellow-500/10" : "hover:bg-muted/50" return (
{log}
) }) )}
) }