9.2 KiB
9.2 KiB
系统日志记录指南
日志级别记录策略
✅ 需要记录到系统日志的级别
1. error(错误)级别 - 必须记录
- 数据库操作失败 - 创建、更新、删除数据失败
- 文件操作失败 - 保存、删除文件失败
- 系统服务异常 - 缓存、队列、分片表等基础设施错误
- 关键业务逻辑错误 - 订单创建失败、支付失败等影响业务流程的错误
- 外部服务调用失败 - 第三方API调用失败
2. warning(警告)级别 - 应该记录
- 非关键操作失败但可继续 - 如分片删除失败、分片读取失败(不影响主流程)
- 资源清理失败 - 临时文件清理失败、缓存清理失败等
- 性能警告 - 操作耗时过长、资源使用率高等
- 配置问题 - 配置缺失或无效,但系统仍可运行
❌ 不需要记录到系统日志的级别
3. info(信息)级别 - 不记录到数据库
- 正常业务流程 - 订单创建成功、支付成功等
- 操作统计 - 用户登录、数据导出等
- 系统状态 - 服务启动、配置加载等
- 说明:这些信息只在文件日志中记录,不写入数据库,避免产生大量日志
4. debug(调试)级别 - 不记录到数据库
- 调试信息 - 变量值、函数调用栈等
- 详细执行流程 - 仅在开发环境需要
- 说明:只在开发环境的文件日志中记录,生产环境通常不记录
原则总结
需要记录到系统日志的错误:
- 数据库操作失败 - 创建、更新、删除数据失败
- 文件操作失败 - 保存、删除文件失败
- 系统服务异常 - 缓存、队列、分片表等基础设施错误
- 关键业务逻辑错误 - 订单创建失败、支付失败等影响业务流程的错误
- 外部服务调用失败 - 第三方API调用失败
需要记录到系统日志的警告:
- 非关键操作失败 - 不影响主流程但需要关注的问题
- 资源清理失败 - 临时文件、缓存清理失败等
- 性能警告 - 需要监控的性能问题
不需要记录到系统日志的错误:
- 参数验证错误 - 如"订单ID不能为空"、"user_id不能为空"
- 业务逻辑的正常错误 - 如"订单不存在"、"用户不存在"、"记录不存在"
- 查询不存在的记录 - 这些是正常的业务场景,不是系统错误
需要记录的错误清单
1. order_service.go
✅ 需要记录
fmt.Errorf("获取锁失败: %v", err)- 系统服务异常fmt.Errorf("生成唯一订单号失败,请重试")- 关键业务逻辑错误fmt.Errorf("创建订单失败: %v", err)- 数据库操作失败fmt.Errorf("创建订单详情失败: %v", err)- 数据库操作失败fmt.Errorf("删除订单详情失败: %v", err)- 数据库操作失败
❌ 不需要记录
fmt.Errorf("订单ID不能为空")- 参数验证错误fmt.Errorf("订单不存在")- 业务逻辑的正常错误(多次出现)
2. attachment_service.go
✅ 需要记录
fmt.Errorf("保存分片失败: %w", err)- 文件操作失败fmt.Errorf("创建目标目录失败: %w", err)- 文件操作失败fmt.Errorf("创建目标文件失败: %w", err)- 文件操作失败fmt.Errorf("写入分片 %d 失败: %w", i, err)- 文件操作失败fmt.Errorf("关闭目标文件失败: %w", err)- 文件操作失败fmt.Errorf("创建附件记录失败: %w", err)- 数据库操作失败fmt.Errorf("保存文件失败: %w", err)- 文件操作失败fmt.Errorf("更新附件显示名称失败: %v", err)- 数据库操作失败fmt.Errorf("删除文件失败: %w", err)- 文件操作失败fmt.Errorf("删除附件记录失败: %w", err)- 数据库操作失败
❌ 不需要记录
fmt.Errorf("分片索引无效")- 参数验证错误fmt.Errorf("分片 %d 不存在", i)- 业务逻辑的正常错误fmt.Errorf("附件不存在: %v", err)- 业务逻辑的正常错误(多次出现)fmt.Errorf("查询附件失败: %v", err)- 查询错误,但可能是正常的"不存在"情况
3. user_service.go
✅ 需要记录
fmt.Errorf("更新用户余额失败: %v", err)- 数据库操作失败fmt.Errorf("创建余额变动记录失败: %v", err)- 数据库操作失败
❌ 不需要记录
fmt.Errorf("用户不存在: %v", err)- 业务逻辑的正常错误fmt.Errorf("余额不足,当前余额: %.2f", user.Balance)- 业务逻辑的正常错误fmt.Errorf("无效的变动类型: %s", logType)- 参数验证错误
4. user_balance_log_service.go
✅ 需要记录
fmt.Errorf("创建余额变动记录失败: %v", err)- 数据库操作失败
❌ 不需要记录
fmt.Errorf("user_id 不能为空,GORM Sharding 需要 ShardingKey")- 参数验证错误(多次出现)fmt.Errorf("用户不存在: %v", err)- 业务逻辑的正常错误
5. export_service.go
✅ 需要记录
fmt.Errorf("写入CSV表头失败: %w", err)- 文件操作失败fmt.Errorf("写入CSV数据失败: %w", err)- 文件操作失败fmt.Errorf("CSV写入失败: %w", err)- 文件操作失败fmt.Errorf("保存文件失败: %w", err)- 文件操作失败
❌ 不需要记录
fmt.Errorf("Excel导出功能暂未实现,请使用CSV格式")- 功能未实现,不是错误
6. export_record_service.go
✅ 需要记录
fmt.Errorf("删除导出记录失败: %v", err)- 数据库操作失败fmt.Errorf("批量删除导出记录失败: %v", err)- 数据库操作失败
❌ 不需要记录
fmt.Errorf("导出记录不存在: %v", err)- 业务逻辑的正常错误(多次出现)fmt.Errorf("查询导出记录失败: %v", err)- 查询错误
7. 各种 service 的 GetByID 方法
❌ 不需要记录(统一处理)
以下错误都是查询不存在的记录,属于正常业务场景:
fmt.Errorf("系统日志不存在: %v", err)fmt.Errorf("操作日志不存在: %v", err)fmt.Errorf("登录日志不存在: %v", err)fmt.Errorf("部门不存在: %v", err)fmt.Errorf("权限不存在: %v", err)fmt.Errorf("角色不存在: %v", err)fmt.Errorf("黑名单不存在: %v", err)fmt.Errorf("字典不存在: %v", err)fmt.Errorf("管理员不存在: %v", err)
8. 基础设施相关
✅ 需要记录
providers/database_service_provider.go:fmt.Errorf("获取 GORM DB 实例失败: %v", err)- 系统服务异常providers/database_service_provider.go:fmt.Errorf("注册 GORM Sharding 插件失败: %v", err)- 系统服务异常utils/gorm_sharding.go:fmt.Errorf("ORM 未初始化")- 系统服务异常utils/gorm_sharding.go:fmt.Errorf("无法通过反射获取原生 GORM DB 实例...")- 系统服务异常utils/sharding_helper.go:fmt.Errorf("查询分表失败: %v", err)- 系统服务异常(多次出现)services/sharding_service.go:fmt.Errorf("创建分表 %s 失败: %v", tableName, err)- 系统服务异常console/commands/create_order_sharding_tables.go:fmt.Errorf("创建分表 %s 失败: %v", tableName, err)- 系统服务异常(多次出现)console/commands/queue_clear.go: 所有 Redis 相关错误 - 系统服务异常console/commands/queue_stats.go: 所有 Redis 相关错误 - 系统服务异常
❌ 不需要记录
console/commands/create_order_sharding_tables.go:fmt.Errorf("月份格式错误...")- 参数验证错误
9. 控制器相关
❌ 不需要记录
order_controller.go: 时间格式验证错误 - 参数验证错误
10. 其他服务
✅ 需要记录
google_authenticator_service.go: 所有错误 - 外部服务调用失败
❌ 不需要记录
admin_service.go:fmt.Errorf("查询管理员失败: %v", err)- 查询错误,可能是正常的"不存在"
实现建议
方式1:使用 errorlog.RecordHTTP(推荐)
import "goravel/app/utils/errorlog"
// 在 HTTP 请求处理中
if err != nil {
errorlog.RecordHTTP(ctx, "order", "创建订单失败", map[string]any{
"error": err.Error(),
"user_id": userID,
"amount": amount,
}, "创建订单失败: %v", err)
return nil, nil, fmt.Errorf("创建订单失败: %v", err)
}
方式2:使用 response.ErrorWithLog
import "goravel/app/http/response"
// 在控制器中
if err != nil {
return response.ErrorWithLog(ctx, http.StatusInternalServerError, "create_failed", "order", "创建订单失败", err)
}
方式3:使用 systemLogService.RecordHTTP
import "goravel/app/services"
systemLogService := services.NewSystemLogService()
_ = systemLogService.RecordHTTP(ctx, "error", "order", "创建订单失败", map[string]any{
"error": err.Error(),
"user_id": userID,
})
注意事项
- 避免重复记录:如果已经在 controller 层记录了日志,service 层就不需要再记录
- 记录上下文信息:尽量记录相关的业务数据(如订单ID、用户ID等),方便排查问题
- 日志级别:大部分错误使用 "error" 级别,警告使用 "warning" 级别
- 性能考虑:系统日志记录是异步的,但也要避免在高频操作中记录过多日志