Add live logs to admin dashboard with level filtering and error middleware

This commit is contained in:
root
2026-03-31 15:54:21 -05:00
parent 40322e8861
commit a0d9f1f9d9
4 changed files with 153 additions and 6 deletions

View File

@@ -1,6 +1,8 @@
import logging
import io
from datetime import datetime, timezone, timedelta
from fastapi import APIRouter, Depends, HTTPException
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession
@@ -15,6 +17,39 @@ router = APIRouter(prefix="/admin", tags=["admin"])
ADMIN_EMAILS = ["chris.ryan@deepcutsai.com"]
# In-memory log buffer for admin viewing
LOG_BUFFER_SIZE = 500
_log_buffer: list[dict] = []
class AdminLogHandler(logging.Handler):
"""Captures log records into an in-memory buffer for the admin UI."""
def emit(self, record):
entry = {
"timestamp": datetime.fromtimestamp(record.created, tz=timezone.utc).isoformat(),
"level": record.levelname,
"logger": record.name,
"message": self.format(record),
}
_log_buffer.append(entry)
if len(_log_buffer) > LOG_BUFFER_SIZE:
_log_buffer.pop(0)
# Attach handler to root logger and uvicorn
_handler = AdminLogHandler()
_handler.setLevel(logging.INFO)
_handler.setFormatter(logging.Formatter("%(message)s"))
logging.getLogger().addHandler(_handler)
logging.getLogger("uvicorn.access").addHandler(_handler)
logging.getLogger("uvicorn.error").addHandler(_handler)
logging.getLogger("app").addHandler(_handler)
# Create app logger for explicit logging
app_logger = logging.getLogger("app")
app_logger.setLevel(logging.INFO)
@router.get("/stats")
async def get_stats(
@@ -98,3 +133,19 @@ async def get_stats(
},
"user_breakdown": user_breakdown,
}
@router.get("/logs")
async def get_logs(
user: User = Depends(get_current_user),
level: str = Query("ALL", description="Filter by level: ALL, ERROR, WARNING, INFO"),
limit: int = Query(100, description="Number of log entries"),
):
if user.email not in ADMIN_EMAILS:
raise HTTPException(status_code=403, detail="Admin only")
logs = _log_buffer[-limit:]
if level != "ALL":
logs = [l for l in logs if l["level"] == level.upper()]
return {"logs": list(reversed(logs)), "total": len(_log_buffer)}