Spaces:
Running
Running
| """请求日志管理 API(admin):/admin/api/request-log | |
| - GET /admin/api/request-log 列表(摘要,含筛选) | |
| - GET /admin/api/request-log/{id} 详情(含完整 body/headers) | |
| - DELETE /admin/api/request-log/{id} 删除单条 | |
| - DELETE /admin/api/request-log 清空全部 | |
| - GET /admin/api/request-log/stats 统计 | |
| - GET /admin/api/request-log/settings 读取容量配置 | |
| - PUT /admin/api/request-log/settings 设置容量配置 | |
| - GET /admin/api/request-log/devices 设备列表(聚合统计) | |
| - GET /admin/api/request-log/devices/{device_id} 某设备最近请求(简化视图) | |
| """ | |
| from __future__ import annotations | |
| from typing import Optional | |
| from fastapi import APIRouter, Body, Depends, Query | |
| from ..errors import HttpError | |
| from ..services import request_log_store | |
| from ._common import ok_with_cors | |
| from .admin import _require_admin | |
| router = APIRouter(prefix="/admin/api/request-log", tags=["request-log"]) | |
| async def list_records( | |
| _admin: str = Depends(_require_admin), | |
| limit: int = Query(default=50, ge=1, le=500), | |
| offset: int = Query(default=0, ge=0), | |
| path: Optional[str] = Query(default=None), | |
| method: Optional[str] = Query(default=None), | |
| status: Optional[str] = Query(default=None), | |
| access_key: Optional[str] = Query(default=None), | |
| ok: Optional[int] = Query(default=None, ge=0, le=1), | |
| hours: Optional[int] = Query(default=None, ge=1, le=720), | |
| keyword: Optional[str] = Query(default=None), | |
| category: Optional[str] = Query(default="business"), | |
| device_id: Optional[str] = Query(default=None), | |
| ): | |
| result = request_log_store.list_records( | |
| limit=limit, offset=offset, | |
| path=path, method=method, status=status, | |
| access_key=access_key, | |
| ok=bool(ok) if ok is not None else None, | |
| hours=hours, keyword=keyword, category=category, | |
| device_id=device_id, | |
| ) | |
| return ok_with_cors(result) | |
| async def stats( | |
| _admin: str = Depends(_require_admin), | |
| hours: int = Query(default=24, ge=1, le=720), | |
| category: Optional[str] = Query(default="business"), | |
| ): | |
| return ok_with_cors(request_log_store.stats(hours=hours, category=category)) | |
| async def get_settings(_admin: str = Depends(_require_admin)): | |
| return ok_with_cors({"limit": request_log_store.get_limit()}) | |
| async def put_settings( | |
| body: dict = Body(default={}), | |
| _admin: str = Depends(_require_admin), | |
| ): | |
| limit = body.get("limit") | |
| if limit is None: | |
| raise HttpError("limit is required", status=400, code="bad_request") | |
| new_limit = request_log_store.set_limit(int(limit)) | |
| return ok_with_cors({"limit": new_limit}) | |
| async def list_devices( | |
| _admin: str = Depends(_require_admin), | |
| hours: Optional[int] = Query(default=None, ge=1, le=720), | |
| limit: int = Query(default=100, ge=1, le=500), | |
| offset: int = Query(default=0, ge=0), | |
| keyword: Optional[str] = Query(default=None), | |
| ): | |
| """按 device_id 聚合的设备列表(含统计与最近活跃信息)。""" | |
| return ok_with_cors( | |
| request_log_store.list_devices( | |
| hours=hours, limit=limit, offset=offset, keyword=keyword, | |
| ) | |
| ) | |
| async def device_records( | |
| device_id: str, | |
| _admin: str = Depends(_require_admin), | |
| limit: int = Query(default=50, ge=1, le=200), | |
| offset: int = Query(default=0, ge=0), | |
| hours: Optional[int] = Query(default=None, ge=1, le=720), | |
| keyword: Optional[str] = Query(default=None), | |
| scope: Optional[str] = Query(default=None), | |
| ): | |
| """某设备的最近请求记录(简化视图:含从请求体提取的文本摘要)。 | |
| keyword: 关键词,在 request_body / response_body 上 LIKE 搜索。 | |
| scope: 'req' 仅请求、'resp' 仅响应、'both' 或空 两者都搜。 | |
| """ | |
| return ok_with_cors( | |
| request_log_store.list_device_records( | |
| device_id=device_id, limit=limit, offset=offset, hours=hours, | |
| keyword=keyword, scope=scope, | |
| ) | |
| ) | |
| async def clear_device_records( | |
| device_id: str, | |
| _admin: str = Depends(_require_admin), | |
| ): | |
| """清空某设备的全部请求记录。""" | |
| count = request_log_store.clear_device_records(device_id) | |
| return ok_with_cors({"cleared": count, "device_id": device_id}) | |
| async def get_record( | |
| rid: int, | |
| _admin: str = Depends(_require_admin), | |
| ): | |
| rec = request_log_store.get_record(rid) | |
| if not rec: | |
| raise HttpError(f"request log not found: {rid}", status=404, code="not_found") | |
| return ok_with_cors({"record": rec}) | |
| async def delete_record( | |
| rid: int, | |
| _admin: str = Depends(_require_admin), | |
| ): | |
| ok = request_log_store.delete_record(rid) | |
| if not ok: | |
| raise HttpError(f"request log not found: {rid}", status=404, code="not_found") | |
| return ok_with_cors({"deleted": True, "id": rid}) | |
| async def clear_all(_admin: str = Depends(_require_admin)): | |
| count = request_log_store.clear_all() | |
| return ok_with_cors({"cleared": count}) | |