You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

8.6 KiB

日志系统使用指南

日期: 2026-01-28
版本: 1.0.0

概述

项目使用 loguru 库实现轻量级日志系统,支持:

  • 日志持久化(按日期和大小轮转)
  • 分级输出(INFO、ERROR)
  • 开发/生产环境不同配置
  • 便捷的日志查看工具

日志配置

日志级别

通过环境变量 LOG_LEVEL 配置日志级别:

# .env
LOG_LEVEL=INFO  # DEBUG, INFO, WARNING, ERROR, CRITICAL

推荐配置

  • 开发环境:INFODEBUG
  • 测试环境:INFO
  • 生产环境:WARNINGERROR

日志输出

日志会输出到以下位置:

1. 控制台输出

  • 开发环境:彩色输出,显示详细信息
  • 生产环境:简化输出,减少性能影响

2. 文件输出

所有日志文件位于 server/logs/ 目录:

文件名 说明 轮转策略 保留时间
app_YYYY-MM-DD.log 所有日志(按日期) 每天午夜 30 天
error_YYYY-MM-DD.log 仅错误日志 每天午夜 30 天
app_size_YYYY-MM-DD.log 所有日志(按大小) 100 MB 30 天

特性

  • 自动压缩旧日志(zip 格式)
  • 异步写入,不阻塞主线程
  • 错误日志包含完整堆栈跟踪和变量值

日志查看

方法 1:使用日志查看脚本(推荐)

项目提供了便捷的日志查看脚本 server/scripts/view_logs.sh

cd server

# 查看帮助
./scripts/view_logs.sh -h

# 列出所有日志文件
./scripts/view_logs.sh -l

# 查看最新 50 行日志(默认)
./scripts/view_logs.sh

# 查看最新 100 行日志
./scripts/view_logs.sh -t 100

# 实时跟踪日志
./scripts/view_logs.sh -f

# 查看错误日志
./scripts/view_logs.sh -e

# 搜索日志内容
./scripts/view_logs.sh -s "用户登录"

# 查看指定日期的日志
./scripts/view_logs.sh -d 2026-01-28

# 查看容器日志
./scripts/view_logs.sh -c

方法 2:直接查看日志文件

cd server

# 查看最新日志
tail -f logs/app_$(date +%Y-%m-%d).log

# 查看错误日志
tail -f logs/error_$(date +%Y-%m-%d).log

# 搜索日志
grep "关键词" logs/app_*.log

# 查看压缩的日志
unzip -p logs/app_2026-01-27.log.zip | less

方法 3:查看容器日志

# 查看实时日志
docker logs -f jointo-server-app

# 查看最新 100 行
docker logs jointo-server-app --tail 100

# 查看特定时间段的日志
docker logs jointo-server-app --since 2026-01-28T10:00:00

# 查看 Celery Worker 日志
docker logs -f jointo-server-celery-ai
docker logs -f jointo-server-celery-export
docker logs -f jointo-server-celery-beat

日志使用示例

在代码中使用日志

from loguru import logger

# INFO 级别
logger.info("用户登录成功", user_id=user.user_id, ip=request.client.host)

# WARNING 级别
logger.warning("积分余额不足", user_id=user.user_id, balance=user.balance)

# ERROR 级别
logger.error("数据库连接失败", error=str(e))

# 带异常堆栈
try:
    # 业务逻辑
    pass
except Exception as e:
    logger.exception("处理请求时发生异常")  # 自动记录堆栈跟踪

# 结构化日志
logger.info(
    "API 请求",
    method=request.method,
    path=request.url.path,
    status_code=response.status_code,
    duration_ms=duration
)

日志格式

控制台输出(开发环境)

2026-01-28 10:30:45.123 | INFO     | app.api.v1.auth:login:45 | 用户登录成功

文件输出

2026-01-28 10:30:45.123 | INFO     | app.api.v1.auth:login:45 | 用户登录成功

错误日志(包含堆栈跟踪)

2026-01-28 10:30:45.123 | ERROR    | app.services.user_service:create_user:78 | 创建用户失败
Traceback (most recent call last):
  File "app/services/user_service.py", line 78, in create_user
    await self.repository.create(user)
  ...
ValueError: 用户名已存在

日志管理

日志清理

日志会自动清理(保留 30 天),也可以手动清理:

cd server

# 删除 30 天前的日志
find logs/ -name "*.log" -mtime +30 -delete
find logs/ -name "*.zip" -mtime +30 -delete

# 删除所有日志(谨慎使用)
rm -rf logs/*

日志备份

cd server

# 备份日志到指定目录
tar -czf logs_backup_$(date +%Y%m%d).tar.gz logs/

# 上传到云存储(示例)
# aws s3 cp logs_backup_*.tar.gz s3://my-bucket/logs/

日志分析

使用 grepawksed 等工具分析日志:

# 统计错误数量
grep "ERROR" logs/app_*.log | wc -l

# 统计 API 请求数量
grep "completed with status" logs/app_*.log | wc -l

# 统计最慢的 API 请求
grep "completed with status" logs/app_*.log | \
  awk '{print $(NF-1)}' | \
  sort -rn | \
  head -10

# 统计错误类型分布
grep "ERROR" logs/app_*.log | \
  awk -F'|' '{print $NF}' | \
  sort | uniq -c | sort -rn

生产环境配置

推荐配置

# .env (生产环境)
ENVIRONMENT=production
LOG_LEVEL=WARNING
DATABASE_ECHO=False  # 关闭 SQLAlchemy 日志

性能优化

  1. 关闭 SQLAlchemy 日志

    # app/core/config.py
    DATABASE_ECHO: bool = False  # 生产环境
    
  2. 提高日志级别

    LOG_LEVEL=WARNING  # 或 ERROR
    
  3. 减少日志输出

    • 仅记录关键业务日志
    • 避免在循环中记录日志
    • 使用结构化日志而非字符串拼接

监控告警

可以配合以下工具实现日志监控和告警:

  1. 简单方案:使用 cron 定时检查错误日志

    # 每小时检查错误日志,如果有新错误则发送通知
    0 * * * * [ -s /path/to/logs/error_$(date +\%Y-\%m-\%d).log ] && echo "发现错误日志" | mail -s "错误告警" admin@example.com
    
  2. 企业方案:集成 ELK Stack 或 Loki + Grafana

故障排查

问题 1:日志文件不存在

原因:日志目录未创建或权限不足

解决方案

cd server
mkdir -p logs
chmod 755 logs

问题 2:日志文件过大

原因:日志级别设置为 DEBUG,或 SQLAlchemy 日志未关闭

解决方案

# 修改 .env
LOG_LEVEL=INFO
DATABASE_ECHO=False

# 重启服务
docker-compose restart app

问题 3:容器重启后日志丢失

原因:日志目录未挂载到宿主机

解决方案

# docker-compose.yml
volumes:
  - ./logs:/app/logs  # 确保此行存在

问题 4:日志中文乱码

原因:编码问题

解决方案

  • 日志文件已配置 encoding="utf-8"
  • 查看时使用支持 UTF-8 的工具(如 less -R

最佳实践

1. 日志级别使用

  • DEBUG:详细的调试信息(仅开发环境)
  • INFO:关键业务流程(用户登录、订单创建等)
  • WARNING:警告信息(余额不足、配额即将用尽等)
  • ERROR:错误信息(数据库连接失败、第三方服务异常等)
  • CRITICAL:严重错误(系统崩溃、数据丢失等)

2. 日志内容

好的日志

logger.info(
    "用户登录成功",
    user_id=user.user_id,
    username=user.username,
    ip=request.client.host,
    user_agent=request.headers.get("user-agent")
)

不好的日志

logger.info("用户登录")  # 缺少上下文信息
logger.info(f"用户 {user.user_id} 登录成功")  # 字符串拼接,不利于结构化分析

3. 敏感信息

禁止记录敏感信息

  • 密码、token、密钥
  • 身份证号、银行卡号
  • 完整的手机号(可记录脱敏后的)

脱敏示例

# 手机号脱敏
phone_masked = phone[:3] + "****" + phone[-4:]
logger.info("发送验证码", phone=phone_masked)

4. 性能考虑

  • 避免在高频循环中记录日志
  • 使用结构化日志而非字符串拼接
  • 生产环境使用 WARNING 或 ERROR 级别

相关文档

未来扩展

当项目规模扩大时,可以考虑升级到企业级日志系统:

  1. ELK Stack(Elasticsearch + Logstash + Kibana)

    • 集中式日志管理
    • 强大的搜索和分析能力
    • 可视化仪表板
  2. Loki + Grafana(更轻量)

    • Grafana Labs 出品
    • 资源占用更少
    • 与 Prometheus 集成良好
  3. 云服务

    • 阿里云日志服务(SLS)
    • 腾讯云日志服务(CLS)
    • AWS CloudWatch Logs

详细方案参考:日志系统升级方案(待编写)