-
-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Open
Labels
type:feature_requestfeature requestfeature request
Description
Describe the feature
希望 GORM 能够提供结构化日志接口,以便更好地与现代结构化日志库(如 slog、zap、zerolog 等)集成,而不需要解析格式化字符串。
目前 GORM 的日志接口只提供了 Printf(string, ...interface{}) 方法,这迫使用户必须解析格式化字符串来提取结构化字段,如执行时间、影响行数、SQL 语句和错误信息。这种方式既容易出错又效率低下。
建议的 API:
type StructuredLogger interface {
LogQuery(ctx context.Context, level Level, info QueryInfo)
}
type QueryInfo struct {
SQL string // SQL 语句
RowsAffected int64 // 影响行数
Elapsed time.Duration // 执行时长
Error error // 错误信息
SlowThreshold time.Duration // 慢查询阈值
Source string // 调用来源
}或者扩展现有的 Writer 接口:
type Writer interface {
Printf(string, ...interface{})
// 新增结构化日志方法
LogStructured(level Level, fields map[string]interface{})
}Motivation
1. 字符串解析容易出错
目前的方式需要解析各种格式字符串,例如:
"%s\n[info] ""%s\n[%.3fms] [rows:%v] %s""%s %s\n[%.3fms] [rows:%v] %s"
这种方式非常脆弱,依赖于 GORM 内部的格式化逻辑,而这些格式可能会变化。我们在生产环境中就遇到了因为 data 切片与预期不符导致的 panic:
// 我们不得不编写的脆弱代码
data = data[n:]
if f64, ok := data[0].(float64); ok { // panic: index out of range
// ...
}2. 更好地集成现代日志生态系统
现代 Go 应用程序使用的结构化日志库(slog、zap、zerolog)提供了:
- 类型安全的字段处理
- 更好的性能(无需字符串格式化)
- 应用程序中一致的日志结构
- 更好的日志聚合和搜索能力(在 ELK、Loki、CloudWatch 等系统中)
3. 性能优势
字符串格式化和后续解析会增加不必要的开销:
格式化字符串 → 解析字符串 → 转换为结构化字段
使用结构化日志:
直接使用结构化字段
4. 可维护性
GORM 日志格式的变化可能会破坏用户代码。结构化接口能提供稳定的契约。
真实案例
目前,为了与结构化日志集成,我们需要编写这样的代码:
func (w logWriter) Printf(msg string, data ...any) {
// 解析格式字符串
parts := strings.SplitN(msg, "\n", 2)
if len(parts) != 2 {
return // 无法解析,丢失日志
}
// 根据前缀猜测格式
if strings.HasPrefix(parts[1], "[info] ") {
// 手动提取字段...
}
// 更多脆弱的解析...
n := strings.Count(parts[0], "%s")
data = data[n:] // 危险!
elapsed := data[0].(float64) // 可能 panic!
rows := data[1]
sql := data[2:]
// ...
}如果有结构化日志支持,代码可以简化为:
func (l *StructuredLogger) LogQuery(ctx context.Context, level Level, info QueryInfo) {
l.logger.Info("数据库查询",
"耗时", info.Elapsed,
"影响行数", info.RowsAffected,
"SQL", info.SQL,
"错误", info.Error,
)
}优势对比:
| 方面 | 当前方式 | 结构化日志 |
|---|---|---|
| 可靠性 | 容易因格式变化而崩溃 | 稳定的接口契约 |
| 性能 | 需要格式化+解析 | 直接传递字段 |
| 可读性 | 大量字符串解析代码 | 简洁清晰 |
| 集成性 | 需要手动适配各种日志库 | 原生支持结构化输出 |
Related Issues
这将是一个向后兼容的功能增强,能够显著改善开发者在将 GORM 与现代日志基础设施集成时的体验。
补充说明:
这个功能对于企业级应用特别重要,因为:
- 生产环境需要可靠的日志记录,不能因为格式解析失败而丢失重要信息
- 需要将数据库日志与应用日志统一管理和分析
- 性能敏感的场景下,字符串格式化的开销不可忽视
希望 GORM 团队能够考虑这个功能请求,谢谢!
Metadata
Metadata
Assignees
Labels
type:feature_requestfeature requestfeature request