from fastapi import APIRouter, Depends, HTTPException, Query, Request from fastapi.responses import HTMLResponse from fastapi.templating import Jinja2Templates from typing import List, Optional import os import json router = APIRouter(prefix="/logs", tags=["System Logs"]) templates = Jinja2Templates(directory="templates") LOG_FILE_PATH = "logs/system.json.log" @router.get("/view", response_class=HTMLResponse) async def view_logs_page(request: Request): """ Log Analysis Dashboard Page (UI) """ return templates.TemplateResponse("log_viewer.html", {"request": request}) @router.get("/api") async def get_logs_api( limit: int = 100, level: Optional[str] = None, keyword: Optional[str] = None ): """ API to fetch parsed logs from system.json.log """ if not os.path.exists(LOG_FILE_PATH): return {"logs": []} logs = [] # Read file in reverse is tricky with JSON lines, so read all and filter (for now) # Optimization: Read file backwards or use `tail`. # Since it's local file system, reading lines is okay for < 10MB. try: with open(LOG_FILE_PATH, 'r', encoding='utf-8') as f: lines = f.readlines() # Parse and Filter for line in reversed(lines): # Show newest first try: if not line.strip(): continue log_entry = json.loads(line) # Filter by Level if level and log_entry.get("level") != level.upper(): continue # Filter by Keyword if keyword: # Search in message or other fields search_blobs = str(log_entry.values()).lower() if keyword.lower() not in search_blobs: continue logs.append(log_entry) if len(logs) >= limit: break except json.JSONDecodeError: continue return {"logs": logs} except Exception as e: raise HTTPException(status_code=500, detail=str(e))