"""操作审计日志服务 — 轻量级,各 endpoint 直接调用。""" from typing import Optional from sqlalchemy.ext.asyncio import AsyncSession from fastapi import Request from app.models.operation_log import OperationLog async def log_operation( db: AsyncSession, *, action: str, resource_type: Optional[str] = None, resource_id: Optional[int] = None, detail: Optional[str] = None, user_id: Optional[int] = None, username: Optional[str] = None, request: Optional[Request] = None, ) -> None: """记录操作日志(fire-and-forget,不抛异常)。""" try: ip_address = None user_agent = None if request: forwarded = request.headers.get("x-forwarded-for") ip_address = forwarded.split(",")[0].strip() if forwarded else ( request.client.host if request.client else None ) user_agent = request.headers.get("user-agent", "")[:255] log = OperationLog( user_id=user_id, username=username, action=action, resource_type=resource_type, resource_id=resource_id, detail=detail, ip_address=ip_address, user_agent=user_agent, ) db.add(log) await db.flush() except Exception: # 审计日志不应影响业务流程 pass