feat: add detailed logging to all API routes and global access log middleware
Each API module now logs: - evaluations: trigger (scenario path, task_id), status polls, list - runs: list (count), detail (run_id, metrics, sample counts) - scenarios: list (total, valid, error counts) - pipeline: submit (docs_path, models, max_docs), status polls, list - llm_profiles: CRUD ops (name, model, id), probe/test (model, ok, latency), apply (patched fields) - score: already had per-request logging Global middleware (webapp.access logger): - Every API request: METHOD path -> status (latency_ms) at INFO - Static file requests demoted to DEBUG to reduce noise Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -8,6 +8,7 @@ the server starts even when the evaluation dependencies are not yet installed.
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import FastAPI, Request
|
||||
@@ -20,6 +21,7 @@ from webapp.api import evaluations, llm_profiles, pipeline, runs, scenarios, sco
|
||||
|
||||
STATIC_DIR = Path(__file__).resolve().parent / "static"
|
||||
logger = logging.getLogger("webapp.server")
|
||||
access_logger = logging.getLogger("webapp.access")
|
||||
|
||||
# OpenAPI tag metadata — controls the grouping and descriptions in /docs.
|
||||
OPENAPI_TAGS = [
|
||||
@@ -107,6 +109,24 @@ def create_app() -> FastAPI:
|
||||
app.include_router(pipeline.router)
|
||||
app.include_router(score.router)
|
||||
|
||||
@app.middleware("http")
|
||||
async def access_log_middleware(request: Request, call_next):
|
||||
"""Log every API request with method, path, status code and latency.
|
||||
|
||||
Static file requests are logged at DEBUG level to keep the console clean.
|
||||
"""
|
||||
t0 = time.monotonic()
|
||||
response = await call_next(request)
|
||||
latency_ms = int((time.monotonic() - t0) * 1000)
|
||||
path = request.url.path
|
||||
is_static = path.startswith("/static/") or path in ("/", "/favicon.ico")
|
||||
msg = "%s %s → %d (%dms)", request.method, path, response.status_code, latency_ms
|
||||
if is_static:
|
||||
access_logger.debug(*msg)
|
||||
else:
|
||||
access_logger.info(*msg)
|
||||
return response
|
||||
|
||||
@app.exception_handler(RequestValidationError)
|
||||
async def validation_exception_handler(request: Request, exc: RequestValidationError) -> JSONResponse:
|
||||
"""Log full validation error detail to help diagnose 422 responses."""
|
||||
|
||||
Reference in New Issue
Block a user