API日志记录功能使用指南.md 7.0 KB

API接口日志记录功能使用指南

功能概述

本功能实现了对所有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://125.122.32.114: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 - Token
  • steamLoginSecure - Steam登录令牌
  • machine_code - 机器码

使用方法

方式1: 自动记录(中间件自动处理)

中间件会自动记录:

  • 入参密文(原始请求体)
  • 出参密文(加密响应数据)

无需额外代码,只需确保中间件已添加到应用中。

方式2: 手动记录明文(在业务代码中)

在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

方式3: 完整记录(包含所有数据)

使用 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天
    ...
)

示例API路由

已创建示例接口,演示如何使用日志功能:

  • POST /api/v1/auth/login - 用户登录
  • GET /api/v1/announcements - 获取公告列表
  • POST /api/v1/heartbeat - 心跳检测

与现有系统的集成

1. 数据库日志记录

原有的 APILoggingASGIMiddleware 仍然会将日志写入 api_logs 表,记录请求和响应的密文(截断后)。

2. 控制台日志

控制台会同时输出简化的日志信息:

[API请求] POST http://125.122.32.114:9000/api/v1/auth/login - 请求数据(密文): eyJ...
[API响应] POST http://125.122.32.114:9000/api/v1/auth/login - 响应数据(密文): eyJ... - 执行时间: 105ms

3. 文件日志

增强的日志会同时写入:

  • logs/api/api_YYYY-MM-DD.log - 完整的入参出参日志
  • logs/client_YYYYMMDD.log - 原有控制台日志

故障排除

问题1: 看不到入参明文

原因:业务代码中没有调用 log_decrypted_request 函数。

解决方案:

# 在API处理函数中添加
decrypted_request = get_decrypted_request()
if decrypted_request:
    log_decrypted_request(decrypted_request)

问题2: 日志文件没有生成

原因:日志目录权限问题或日志器配置错误。

解决方案:

  1. 确保 logs/api 目录存在且有写入权限
  2. 检查 app/utils/api_logger.py 中的日志路径配置

问题3: 敏感字段没有脱敏

原因:字段名不在脱敏列表中。

解决方案:在 REDACTED_FIELDS 集合中添加字段名。

最佳实践

  1. 在每个API处理函数中记录明文:确保调用 log_decrypted_request 和 log_decrypted_response
  2. 不要记录完整的敏感数据:依赖自动脱敏机制
  3. 监控日志文件大小:避免单个日志文件过大
  4. 定期清理旧日志:日志保留策略已设置为30天

性能考虑

  1. 异步记录:日志记录不会阻塞API响应
  2. 数据截断:过长的数据会被自动截断
  3. 批量处理:日志写入采用批量方式,提高IO效率