diff --git a/app/middleware/error_logger.py b/app/middleware/error_logger.py index 93a8f46..a8198a9 100644 --- a/app/middleware/error_logger.py +++ b/app/middleware/error_logger.py @@ -16,7 +16,7 @@ import json import time import traceback import uuid -from datetime import datetime, timezone +from datetime import datetime, timedelta, timezone from typing import Callable, Optional from fastapi import Request, Response @@ -38,6 +38,8 @@ logger = logging.getLogger(__name__) _REQUEST_LOG_QUEUE: asyncio.Queue = asyncio.Queue(maxsize=10_000) _FLUSH_INTERVAL_SECONDS: float = 2.0 # flush at most every 2 s _FLUSH_BATCH_SIZE: int = 500 # or when 500 entries are queued +_LOG_RETENTION_DAYS: int = 7 # delete request_logs older than this +_CLEANUP_INTERVAL_HOURS: int = 1 # run cleanup every N hours async def _flush_request_logs(entries: list) -> None: @@ -82,9 +84,31 @@ async def _request_log_flusher() -> None: await _flush_request_logs(entries) +async def _request_log_cleanup() -> None: + """Background coroutine: delete request_logs older than _LOG_RETENTION_DAYS.""" + while True: + await asyncio.sleep(_CLEANUP_INTERVAL_HOURS * 3600) + try: + cutoff = datetime.now(timezone.utc) - timedelta(days=_LOG_RETENTION_DAYS) + from app.core.database import AsyncSessionLocal + from sqlalchemy import text + async with AsyncSessionLocal() as db: + result = await db.execute( + text("DELETE FROM request_logs WHERE created_at < :cutoff"), + {"cutoff": cutoff}, + ) + deleted = result.rowcount + await db.commit() + if deleted: + logger.info(f"request_logs cleanup: deleted {deleted} rows older than {_LOG_RETENTION_DAYS}d") + except Exception as e: + logger.error(f"request_logs cleanup failed: {e}") + + def start_request_log_flusher() -> None: """Schedule the background flusher coroutine. Call once at app startup.""" asyncio.ensure_future(_request_log_flusher()) + asyncio.ensure_future(_request_log_cleanup()) logger.info("Request log flusher background task started")