# 日志系统使用指南 **日期**: 2026-01-28 **版本**: 1.0.0 ## 概述 项目使用 **loguru** 库实现轻量级日志系统,支持: - 日志持久化(按日期和大小轮转) - 分级输出(INFO、ERROR) - 开发/生产环境不同配置 - 便捷的日志查看工具 ## 日志配置 ### 日志级别 通过环境变量 `LOG_LEVEL` 配置日志级别: ```bash # .env LOG_LEVEL=INFO # DEBUG, INFO, WARNING, ERROR, CRITICAL ``` **推荐配置**: - 开发环境:`INFO` 或 `DEBUG` - 测试环境:`INFO` - 生产环境:`WARNING` 或 `ERROR` ### 日志输出 日志会输出到以下位置: #### 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`: ```bash 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:直接查看日志文件 ```bash 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:查看容器日志 ```bash # 查看实时日志 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 ``` ## 日志使用示例 ### 在代码中使用日志 ```python 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 天),也可以手动清理: ```bash cd server # 删除 30 天前的日志 find logs/ -name "*.log" -mtime +30 -delete find logs/ -name "*.zip" -mtime +30 -delete # 删除所有日志(谨慎使用) rm -rf logs/* ``` ### 日志备份 ```bash cd server # 备份日志到指定目录 tar -czf logs_backup_$(date +%Y%m%d).tar.gz logs/ # 上传到云存储(示例) # aws s3 cp logs_backup_*.tar.gz s3://my-bucket/logs/ ``` ### 日志分析 使用 `grep`、`awk`、`sed` 等工具分析日志: ```bash # 统计错误数量 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 ``` ## 生产环境配置 ### 推荐配置 ```bash # .env (生产环境) ENVIRONMENT=production LOG_LEVEL=WARNING DATABASE_ECHO=False # 关闭 SQLAlchemy 日志 ``` ### 性能优化 1. **关闭 SQLAlchemy 日志** ```python # app/core/config.py DATABASE_ECHO: bool = False # 生产环境 ``` 2. **提高日志级别** ```bash LOG_LEVEL=WARNING # 或 ERROR ``` 3. **减少日志输出** - 仅记录关键业务日志 - 避免在循环中记录日志 - 使用结构化日志而非字符串拼接 ### 监控告警 可以配合以下工具实现日志监控和告警: 1. **简单方案**:使用 cron 定时检查错误日志 ```bash # 每小时检查错误日志,如果有新错误则发送通知 0 * * * * [ -s /path/to/logs/error_$(date +\%Y-\%m-\%d).log ] && echo "发现错误日志" | mail -s "错误告警" admin@example.com ``` 2. **企业方案**:集成 ELK Stack 或 Loki + Grafana - 参考 [日志系统升级方案](./logging-system-upgrade.md)(未来实施) ## 故障排查 ### 问题 1:日志文件不存在 **原因**:日志目录未创建或权限不足 **解决方案**: ```bash cd server mkdir -p logs chmod 755 logs ``` ### 问题 2:日志文件过大 **原因**:日志级别设置为 DEBUG,或 SQLAlchemy 日志未关闭 **解决方案**: ```bash # 修改 .env LOG_LEVEL=INFO DATABASE_ECHO=False # 重启服务 docker-compose restart app ``` ### 问题 3:容器重启后日志丢失 **原因**:日志目录未挂载到宿主机 **解决方案**: ```yaml # docker-compose.yml volumes: - ./logs:/app/logs # 确保此行存在 ``` ### 问题 4:日志中文乱码 **原因**:编码问题 **解决方案**: - 日志文件已配置 `encoding="utf-8"` - 查看时使用支持 UTF-8 的工具(如 `less -R`) ## 最佳实践 ### 1. 日志级别使用 - **DEBUG**:详细的调试信息(仅开发环境) - **INFO**:关键业务流程(用户登录、订单创建等) - **WARNING**:警告信息(余额不足、配额即将用尽等) - **ERROR**:错误信息(数据库连接失败、第三方服务异常等) - **CRITICAL**:严重错误(系统崩溃、数据丢失等) ### 2. 日志内容 ✅ **好的日志**: ```python logger.info( "用户登录成功", user_id=user.user_id, username=user.username, ip=request.client.host, user_agent=request.headers.get("user-agent") ) ``` ❌ **不好的日志**: ```python logger.info("用户登录") # 缺少上下文信息 logger.info(f"用户 {user.user_id} 登录成功") # 字符串拼接,不利于结构化分析 ``` ### 3. 敏感信息 ❌ **禁止记录敏感信息**: - 密码、token、密钥 - 身份证号、银行卡号 - 完整的手机号(可记录脱敏后的) ✅ **脱敏示例**: ```python # 手机号脱敏 phone_masked = phone[:3] + "****" + phone[-4:] logger.info("发送验证码", phone=phone_masked) ``` ### 4. 性能考虑 - 避免在高频循环中记录日志 - 使用结构化日志而非字符串拼接 - 生产环境使用 WARNING 或 ERROR 级别 ## 相关文档 - [日志系统实施记录](../changelogs/2026-01-28-logging-system-implementation.md) - [后端架构文档](../../requirements/backend/01-architecture-overview.md) - [Docker 部署指南](./DEPLOYMENT.md) ## 未来扩展 当项目规模扩大时,可以考虑升级到企业级日志系统: 1. **ELK Stack**(Elasticsearch + Logstash + Kibana) - 集中式日志管理 - 强大的搜索和分析能力 - 可视化仪表板 2. **Loki + Grafana**(更轻量) - Grafana Labs 出品 - 资源占用更少 - 与 Prometheus 集成良好 3. **云服务** - 阿里云日志服务(SLS) - 腾讯云日志服务(CLS) - AWS CloudWatch Logs 详细方案参考:[日志系统升级方案](./logging-system-upgrade.md)(待编写)