|
|
from datetime import datetime, timedelta |
|
|
from typing import Any, Dict, List, Optional |
|
|
|
|
|
from sqlalchemy import delete, func, select |
|
|
|
|
|
from app.config.config import settings |
|
|
from app.database import services as db_services |
|
|
from app.database.connection import database |
|
|
from app.database.models import ErrorLog |
|
|
from app.log.logger import get_error_log_logger |
|
|
|
|
|
logger = get_error_log_logger() |
|
|
|
|
|
|
|
|
async def delete_old_error_logs(): |
|
|
""" |
|
|
Deletes error logs older than a specified number of days, |
|
|
based on the AUTO_DELETE_ERROR_LOGS_ENABLED and AUTO_DELETE_ERROR_LOGS_DAYS settings. |
|
|
""" |
|
|
if not settings.AUTO_DELETE_ERROR_LOGS_ENABLED: |
|
|
logger.info("Auto-deletion of error logs is disabled. Skipping.") |
|
|
return |
|
|
|
|
|
days_to_keep = settings.AUTO_DELETE_ERROR_LOGS_DAYS |
|
|
if not isinstance(days_to_keep, int) or days_to_keep <= 0: |
|
|
logger.error( |
|
|
f"Invalid AUTO_DELETE_ERROR_LOGS_DAYS value: {days_to_keep}. Must be a positive integer. Skipping deletion." |
|
|
) |
|
|
return |
|
|
|
|
|
cutoff_date = datetime.now() - timedelta(days=days_to_keep) |
|
|
|
|
|
logger.info( |
|
|
f"Attempting to delete error logs older than {days_to_keep} days (before {cutoff_date.strftime('%Y-%m-%d %H:%M:%S %Z')})." |
|
|
) |
|
|
|
|
|
try: |
|
|
if not database.is_connected: |
|
|
await database.connect() |
|
|
logger.info("Database connection established for deleting error logs.") |
|
|
|
|
|
|
|
|
count_query = select(func.count(ErrorLog.id)).where( |
|
|
ErrorLog.request_time < cutoff_date |
|
|
) |
|
|
num_logs_to_delete = await database.fetch_val(count_query) |
|
|
|
|
|
if num_logs_to_delete == 0: |
|
|
logger.info( |
|
|
"No error logs found older than the specified period. No deletion needed." |
|
|
) |
|
|
return |
|
|
|
|
|
logger.info(f"Found {num_logs_to_delete} error logs to delete.") |
|
|
|
|
|
|
|
|
query = delete(ErrorLog).where(ErrorLog.request_time < cutoff_date) |
|
|
await database.execute(query) |
|
|
logger.info( |
|
|
f"Successfully deleted {num_logs_to_delete} error logs older than {days_to_keep} days." |
|
|
) |
|
|
|
|
|
except Exception as e: |
|
|
logger.error( |
|
|
f"Error during automatic deletion of error logs: {e}", exc_info=True |
|
|
) |
|
|
|
|
|
|
|
|
async def process_get_error_logs( |
|
|
limit: int, |
|
|
offset: int, |
|
|
key_search: Optional[str], |
|
|
error_search: Optional[str], |
|
|
error_code_search: Optional[str], |
|
|
start_date: Optional[datetime], |
|
|
end_date: Optional[datetime], |
|
|
sort_by: str, |
|
|
sort_order: str, |
|
|
) -> Dict[str, Any]: |
|
|
""" |
|
|
处理错误日志的检索,支持分页和过滤。 |
|
|
""" |
|
|
try: |
|
|
logs_data = await db_services.get_error_logs( |
|
|
limit=limit, |
|
|
offset=offset, |
|
|
key_search=key_search, |
|
|
error_search=error_search, |
|
|
error_code_search=error_code_search, |
|
|
start_date=start_date, |
|
|
end_date=end_date, |
|
|
sort_by=sort_by, |
|
|
sort_order=sort_order, |
|
|
) |
|
|
total_count = await db_services.get_error_logs_count( |
|
|
key_search=key_search, |
|
|
error_search=error_search, |
|
|
error_code_search=error_code_search, |
|
|
start_date=start_date, |
|
|
end_date=end_date, |
|
|
) |
|
|
return {"logs": logs_data, "total": total_count} |
|
|
except Exception as e: |
|
|
logger.error(f"Service error in process_get_error_logs: {e}", exc_info=True) |
|
|
raise |
|
|
|
|
|
|
|
|
async def process_get_error_log_details(log_id: int) -> Optional[Dict[str, Any]]: |
|
|
""" |
|
|
处理特定错误日志详细信息的检索。 |
|
|
如果未找到,则返回 None。 |
|
|
""" |
|
|
try: |
|
|
log_details = await db_services.get_error_log_details(log_id=log_id) |
|
|
return log_details |
|
|
except Exception as e: |
|
|
logger.error( |
|
|
f"Service error in process_get_error_log_details for ID {log_id}: {e}", |
|
|
exc_info=True, |
|
|
) |
|
|
raise |
|
|
|
|
|
|
|
|
async def process_find_error_log_by_info( |
|
|
gemini_key: str, |
|
|
timestamp: datetime, |
|
|
status_code: Optional[int] = None, |
|
|
window_seconds: int = 100, |
|
|
) -> Optional[Dict[str, Any]]: |
|
|
""" |
|
|
根据 key/状态码/时间窗口 查询最匹配的一条错误日志,未找到则返回 None。 |
|
|
""" |
|
|
try: |
|
|
return await db_services.find_error_log_by_info( |
|
|
gemini_key=gemini_key, |
|
|
timestamp=timestamp, |
|
|
status_code=status_code, |
|
|
window_seconds=window_seconds, |
|
|
) |
|
|
except Exception as e: |
|
|
logger.error( |
|
|
f"Service error in process_find_error_log_by_info: {e}", |
|
|
exc_info=True, |
|
|
) |
|
|
raise |
|
|
|
|
|
|
|
|
async def process_delete_error_logs_by_ids(log_ids: List[int]) -> int: |
|
|
""" |
|
|
按 ID 批量删除错误日志。 |
|
|
返回尝试删除的日志数量。 |
|
|
""" |
|
|
if not log_ids: |
|
|
return 0 |
|
|
try: |
|
|
deleted_count = await db_services.delete_error_logs_by_ids(log_ids) |
|
|
return deleted_count |
|
|
except Exception as e: |
|
|
logger.error( |
|
|
f"Service error in process_delete_error_logs_by_ids for IDs {log_ids}: {e}", |
|
|
exc_info=True, |
|
|
) |
|
|
raise |
|
|
|
|
|
|
|
|
async def process_delete_error_log_by_id(log_id: int) -> bool: |
|
|
""" |
|
|
按 ID 删除单个错误日志。 |
|
|
如果删除成功(或找到日志并尝试删除),则返回 True,否则返回 False。 |
|
|
""" |
|
|
try: |
|
|
success = await db_services.delete_error_log_by_id(log_id) |
|
|
return success |
|
|
except Exception as e: |
|
|
logger.error( |
|
|
f"Service error in process_delete_error_log_by_id for ID {log_id}: {e}", |
|
|
exc_info=True, |
|
|
) |
|
|
raise |
|
|
|
|
|
|
|
|
async def process_delete_all_error_logs() -> int: |
|
|
""" |
|
|
处理删除所有错误日志的请求。 |
|
|
返回删除的日志数量。 |
|
|
""" |
|
|
try: |
|
|
if not database.is_connected: |
|
|
await database.connect() |
|
|
logger.info("Database connection established for deleting all error logs.") |
|
|
|
|
|
deleted_count = await db_services.delete_all_error_logs() |
|
|
logger.info( |
|
|
f"Successfully processed request to delete all error logs. Count: {deleted_count}" |
|
|
) |
|
|
return deleted_count |
|
|
except Exception as e: |
|
|
logger.error( |
|
|
f"Service error in process_delete_all_error_logs: {e}", |
|
|
exc_info=True, |
|
|
) |
|
|
raise |
|
|
|