mirror of
https://github.com/snailyp/gemini-balance.git
synced 2026-09-05 23:56:37 +08:00
feat(error_logs): 添加错误日志搜索和日期过滤功能
- 在后端 (`services.py`, `log_routes.py`) 实现按 Gemini 密钥(模糊匹配)、错误类型/内容(模糊匹配)和日期范围(开始/结束日期)过滤错误日志的逻辑。
- 添加新函数 `get_error_logs_count` 以高效获取符合过滤条件的总日志数,用于分页。
- 更新 `/api/logs/errors` API 端点以接受 `key_search`, `error_search`, `start_date`, `end_date` 查询参数。端点现在返回包含过滤后日志和总数的对象。
- 增强前端 (`error_logs.html`, `error_logs.js`, `error_logs.css`):
- 添加用于密钥搜索、错误/日志搜索和日期范围选择的输入字段。
- 实现 JavaScript 逻辑以捕获搜索参数,使用过滤器触发 API 调用,并在新搜索时重置到第一页。
- 更新表格渲染以显示顺序行号而非数据库 ID。
- 在表格视图中遮罩 Gemini 密钥(显示前/后 4 个字符)以提高可读性,同时仍在详细信息模态框中显示完整密钥。
- 优化新搜索控件、表格外观(内边距、边框、悬停效果、斑马条纹)和按钮样式的 CSS,以提供更清晰的用户界面。
- 通过使用 `logger.exception` 包含堆栈跟踪来改进后端服务中的错误日志记录。
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
"""
|
||||
日志路由模块
|
||||
"""
|
||||
from typing import Any, Dict, List
|
||||
from typing import Any, Dict, List, Optional
|
||||
from datetime import date
|
||||
from pydantic import BaseModel
|
||||
from fastapi import APIRouter, HTTPException, Request, Query
|
||||
from fastapi.responses import RedirectResponse
|
||||
|
||||
from app.core.security import verify_auth_token
|
||||
from app.log.logger import get_log_routes_logger
|
||||
from app.database.services import get_error_logs
|
||||
from app.database.services import get_error_logs, get_error_logs_count
|
||||
|
||||
# 创建路由
|
||||
router = APIRouter(prefix="/api/logs", tags=["logs"])
|
||||
@@ -15,11 +17,20 @@ router = APIRouter(prefix="/api/logs", tags=["logs"])
|
||||
logger = get_log_routes_logger()
|
||||
|
||||
|
||||
@router.get("/errors", response_model=List[Dict[str, Any]])
|
||||
# Define a response model that includes the total count for pagination
|
||||
class ErrorLogResponse(BaseModel):
|
||||
logs: List[Dict[str, Any]]
|
||||
total: int
|
||||
|
||||
@router.get("/errors", response_model=ErrorLogResponse)
|
||||
async def get_error_logs_api(
|
||||
request: Request,
|
||||
limit: int = Query(100, ge=1, le=1000),
|
||||
offset: int = Query(0, ge=0)
|
||||
limit: int = Query(20, ge=1, le=1000), # Default to 20 to match frontend
|
||||
offset: int = Query(0, ge=0),
|
||||
key_search: Optional[str] = Query(None, description="Search term for Gemini key (partial match)"),
|
||||
error_search: Optional[str] = Query(None, description="Search term for error type or log message"),
|
||||
start_date: Optional[date] = Query(None, description="Start date for filtering (YYYY-MM-DD)"),
|
||||
end_date: Optional[date] = Query(None, description="End date for filtering (YYYY-MM-DD)")
|
||||
):
|
||||
"""
|
||||
获取错误日志
|
||||
@@ -30,7 +41,7 @@ async def get_error_logs_api(
|
||||
offset: 偏移量
|
||||
|
||||
Returns:
|
||||
List[Dict[str, Any]]: 错误日志列表
|
||||
ErrorLogResponse: An object containing the list of logs and the total count.
|
||||
"""
|
||||
auth_token = request.cookies.get("auth_token")
|
||||
if not auth_token or not verify_auth_token(auth_token):
|
||||
@@ -38,8 +49,23 @@ async def get_error_logs_api(
|
||||
return RedirectResponse(url="/", status_code=302)
|
||||
|
||||
try:
|
||||
logs = await get_error_logs(limit, offset)
|
||||
return logs
|
||||
# Fetch logs with search parameters
|
||||
logs = await get_error_logs(
|
||||
limit=limit,
|
||||
offset=offset,
|
||||
key_search=key_search,
|
||||
error_search=error_search,
|
||||
start_date=start_date,
|
||||
end_date=end_date
|
||||
)
|
||||
# Fetch total count with the same search parameters
|
||||
total_count = await get_error_logs_count(
|
||||
key_search=key_search,
|
||||
error_search=error_search,
|
||||
start_date=start_date,
|
||||
end_date=end_date
|
||||
)
|
||||
return ErrorLogResponse(logs=logs, total=total_count)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get error logs: {str(e)}")
|
||||
logger.exception(f"Failed to get error logs: {str(e)}") # Use logger.exception for stack trace
|
||||
raise HTTPException(status_code=500, detail=f"Failed to get error logs: {str(e)}")
|
||||
|
||||
Reference in New Issue
Block a user