feat: add logger

This commit is contained in:
tao.chen
2026-08-12 12:43:31 +08:00
parent 3981c32781
commit 416ff4d06a
8 changed files with 381 additions and 6 deletions
+49 -6
View File
@@ -1,32 +1,40 @@
from __future__ import annotations
import time
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from typing import Any, AsyncIterator
from typing import Any
import httpx
from common.config import settings
from common.db import create_database_engine, create_session_factory
from common.logging import configure_logging
from common.service_app import create_service_app
from common.storage import (
AsyncStorageBackend,
PURPOSE_BUCKETS,
AsyncStorageBackend,
actual_bucket_name,
build_storage_config,
create_storage,
)
from fastapi import Request
from fastapi.responses import JSONResponse
from loguru import logger
from backend.admin import router as admin_router
from backend.auth import router as auth_router
from backend.platform import router as platform_router
from backend.jupyter import router as jupyter_router
from backend.platform import router as platform_router
from backend.rclone_rc_client import RcloneRCClient
from backend.resources import router as resources_router
from backend.runtime_client import RuntimeClient
from backend.rclone_rc_client import RcloneRCClient
from backend.schedule_runs import router as schedule_runs_router
from backend.schedules import router as schedules_router
from backend.scripts import router as scripts_router
from backend.storage_api import router as storage_api_router
configure_logging(settings.log_level)
@asynccontextmanager
async def lifespan(app: Any) -> AsyncIterator[None]:
@@ -39,7 +47,7 @@ async def lifespan(app: Any) -> AsyncIterator[None]:
# bucket name (e.g. "versions"), matching ``UploadSessions.bucket_name``
# and ``StorageObjects.bucket_name`` so call sites can do
# ``object_stores[upload.bucket_name].put(...)`` directly.
app.state.object_stores: dict[str, AsyncStorageBackend] = {
app.state.object_stores: dict[str, StorageBackend | AsyncStorageBackend] = { # noqa: F821
actual_bucket_name(purpose): create_storage(build_storage_config(purpose))
for purpose in PURPOSE_BUCKETS
}
@@ -78,3 +86,38 @@ app.include_router(platform_router)
# Reuse the proven storage endpoints without running another FastAPI service.
app.include_router(storage_api_router, prefix="/internal")
@app.middleware("http")
async def access_log(request: Request, call_next):
start = time.perf_counter()
try:
response = await call_next(request)
except Exception:
elapsed_ms = (time.perf_counter() - start) * 1000
logger.exception(
"request failed {method} {path} after {ms:.1f}ms",
method=request.method, path=request.url.path, ms=elapsed_ms,
)
raise
elapsed_ms = (time.perf_counter() - start) * 1000
logger.info(
"{method} {path} -> {status} in {ms:.1f}ms",
method=request.method, path=request.url.path,
status=response.status_code, ms=elapsed_ms,
)
return response
@app.exception_handler(Exception)
async def unhandled_exception_handler(request: Request, exc: Exception):
logger.error(
"unhandled exception on {method} {path} from {client}: {exc!r}",
method=request.method, path=request.url.path,
client=request.client.host if request.client else "-",
exc=exc,
)
return JSONResponse(
status_code=500,
content={"detail": "Internal server error"},
)