feat: add HTTP log query API endpoints

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-05 11:33:23 +08:00
parent 5de8694eec
commit c49105a678
+103
View File
@@ -0,0 +1,103 @@
"""HTTP log query endpoints."""
import logging
import sqlite3
from pathlib import Path
from typing import Optional
from fastapi import APIRouter, Depends, Query
from ..auth.dependencies import get_current_user
from ..services.db_schema import query_http_logs, query_http_log_stats
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/logs", tags=["logs"])
_db_path = Path(__file__).resolve().parent.parent.parent.parent / "data" / "web_data.db"
def _count_http_logs(
method: str = None,
path: str = None,
status_code: int = None,
start_time: str = None,
end_time: str = None,
) -> int:
"""Count total matching HTTP log rows for pagination."""
conn = sqlite3.connect(_db_path)
try:
clauses = []
params = []
if method:
clauses.append("method = ?")
params.append(method)
if path:
clauses.append("path LIKE ?")
params.append(f"%{path}%")
if status_code is not None:
clauses.append("status_code = ?")
params.append(status_code)
if start_time:
clauses.append("timestamp >= ?")
params.append(start_time)
if end_time:
clauses.append("timestamp <= ?")
params.append(end_time)
where = (" WHERE " + " AND ".join(clauses)) if clauses else ""
row = conn.execute(
f"SELECT COUNT(*) as cnt FROM http_logs{where}", params
).fetchone()
return row["cnt"] if row else 0
finally:
conn.close()
@router.get("")
async def list_logs(
page: int = Query(1, ge=1),
page_size: int = Query(50, ge=1, le=200),
method: Optional[str] = None,
status_code: Optional[int] = None,
path: Optional[str] = None,
start_date: Optional[str] = None,
end_date: Optional[str] = None,
current_user: dict = Depends(get_current_user),
):
"""List HTTP logs with filters and pagination."""
offset = (page - 1) * page_size
items = query_http_logs(
method=method,
path=path,
status_code=status_code,
start_time=start_date,
end_time=end_date,
limit=page_size,
offset=offset,
)
total = _count_http_logs(
method=method,
path=path,
status_code=status_code,
start_time=start_date,
end_time=end_date,
)
return {"items": items, "total": total}
@router.get("/stats")
async def log_stats(
current_user: dict = Depends(get_current_user),
):
"""Get today's HTTP log statistics."""
raw = query_http_log_stats()
total = raw.get("total", 0)
errors = raw.get("errors", 0)
avg_duration = raw.get("avg_duration")
return {
"today_count": total,
"error_count": errors,
"avg_duration_ms": round(avg_duration, 2) if avg_duration else 0.0,
"error_rate": round(errors / total, 4) if total > 0 else 0.0,
}