本功能实现了对所有API接口的完整日志记录,包括:
日志文件按天滚动,每天生成一个日志文件,保存在 logs/api/ 目录下。
backend-client/
├── app/
│ ├── middleware/
│ │ ├── logging.py # 增强的API日志中间件(已更新)
│ │ └── enhanced_logging.py # 独立的增强日志中间件(可选使用)
│ ├── utils/
│ │ ├── api_context.py # 请求上下文管理
│ │ ├── api_logger.py # API日志记录器
│ │ └── __init__.py # 导出工具函数
│ ├── api/
│ │ └── v1/
│ │ └── router.py # 示例API路由
│ └── main.py # 应用入口(已添加中间件)
└── logs/
└── api/
└── api_2026-02-02.log # 按天滚动的日志文件
每条日志记录包含以下字段:
{
"timestamp": "2026-02-02 18:30:45.123", // 时间戳(精确到毫秒)
"endpoint": "http://localhost:9000/api/v1/auth/login", // 接口路径
"method": "POST", // HTTP方法
"user_id": 1, // 用户ID(可为null)
"client_ip": "192.168.1.100", // 客户端IP
"processing_time_ms": 105, // 处理时间(毫秒)
"status_code": 200, // HTTP状态码
"error": null, // 错误信息(可为null)
"request": {
"encrypted": "base64编码的加密请求数据...",
"decrypted": {
"username": "test",
"password": "****", // 已脱敏
"machine_code": "****" // 已脱敏
}
},
"response": {
"encrypted": "base64编码的加密响应数据...",
"decrypted": {
"code": 200,
"msg": "登录成功",
"data": {...}
}
}
}
以下字段会被自动脱敏:
password, card_code - 密码和卡密shared_secret, identity_secret - Steam密钥aes_key, encrypted_aes_key - AES密钥signature - 签名access_token, refresh_token, session_token - TokensteamLoginSecure - Steam登录令牌machine_code - 机器码中间件会自动记录:
无需额外代码,只需确保中间件已添加到应用中。
在API处理函数中,使用提供的工具函数记录明文数据:
from fastapi import APIRouter
from app.utils.api_context import (
get_decrypted_request, # 获取解密后的请求数据
log_decrypted_request, # 记录入参明文
log_decrypted_response, # 记录出参明文
)
router = APIRouter()
@router.post("/auth/login")
async def login(request_data: LoginRequest):
"""
用户登录接口示例
"""
# 方法1: 获取解密后的请求数据
decrypted_request = get_decrypted_request()
if decrypted_request:
# 记录入参明文
log_decrypted_request(decrypted_request)
else:
# 如果没有解密数据,直接记录请求体
log_decrypted_request(request_data.model_dump())
# 业务处理...
# 构建响应数据
response_data = {"code": 200, "msg": "成功", "data": {...}}
# 记录出参明文
log_decrypted_response(response_data)
return response_data
使用 log_complete 函数记录完整的API调用信息:
from app.utils.api_context import log_complete
@router.post("/auth/login")
async def login(request_data: LoginRequest):
# 业务处理...
response_data = {"code": 200, "msg": "成功"}
# 完整记录(包含明文和密文)
log_complete(
decrypted_request=request_data.model_dump(),
decrypted_response=response_data,
processing_time_ms=105,
status_code=200
)
return response_data
在 app/utils/api_logger.py 中可以配置:
# 日志目录
API_LOG_DIR = Path("logs/api")
# 敏感字段脱敏
REDACTED_FIELDS = {
"password",
"card_code",
# ... 其他字段
}
# 数据截断长度
MAX_DATA_LENGTH = 10000
日志文件按天自动轮转,保留最近30天的日志:
loguru_logger.add(
str(self._log_path),
rotation="00:00", # 每天午夜轮转
retention="30 days", # 保留30天
...
)
已创建示例接口,演示如何使用日志功能:
POST /api/v1/auth/login - 用户登录GET /api/v1/announcements - 获取公告列表POST /api/v1/heartbeat - 心跳检测原有的 APILoggingASGIMiddleware 仍然会将日志写入 api_logs 表,记录请求和响应的密文(截断后)。
控制台会同时输出简化的日志信息:
[API请求] POST http://localhost:9000/api/v1/auth/login - 请求数据(密文): eyJ...
[API响应] POST http://localhost:9000/api/v1/auth/login - 响应数据(密文): eyJ... - 执行时间: 105ms
增强的日志会同时写入:
logs/api/api_YYYY-MM-DD.log - 完整的入参出参日志logs/client_YYYYMMDD.log - 原有控制台日志原因:业务代码中没有调用 log_decrypted_request 函数。
解决方案:
# 在API处理函数中添加
decrypted_request = get_decrypted_request()
if decrypted_request:
log_decrypted_request(decrypted_request)
原因:日志目录权限问题或日志器配置错误。
解决方案:
logs/api 目录存在且有写入权限app/utils/api_logger.py 中的日志路径配置原因:字段名不在脱敏列表中。
解决方案:在 REDACTED_FIELDS 集合中添加字段名。
log_decrypted_request 和 log_decrypted_response