Files
orc-order-v2/web/backend/routers/logs.py
T
houhuan dedc3b4183 feat: complete web application — FastAPI backend + Vue 3 SPA frontend
- Full FastAPI backend with JWT auth, file management, processing pipeline,
  memory CRUD, barcode mappings, config management, cloud sync
- Vue 3 + Element Plus frontend with dashboard, task history, HTTP logs,
  memory editor, barcode editor, config editor, sync page
- HTTP request logging middleware with SQLite persistence
- Task history tracking with progress and retry support
- File metadata recording for upload/download operations
- WebAuth section in config.ini for bcrypt password storage
- Bug fix: logs.py count query returns tuple not dict

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-05 11:59:07 +08:00

104 lines
2.9 KiB
Python

"""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[0] 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,
}