这一段时间在使用 gorm 的时候有一个疑惑,在 gorm
中查询可能会返回一个 error ,我希望在出错的时候记录具体的执行的 SQL 语句是什么,但是我看 gorm 返回的 error 中并没有提供相关的获取 SQL 的信息,反而在 Logger 中可以通过 Trace 的方式来记录 Error 信息以及执行的 SQL 。
我疑惑的点在于是否应该通过 error 返回的时候携带具体执行的 SQL 语句更合适呢,这样在记录错误信息的时候也就能记录上相关出错的 SQL ,而通过 gorm 自身 Logger 的方法,就需要通过上下文关联才能定位到具体出错的 SQL 语句。
希望大家帮忙分析一下那个更合适
![]() |
1
Immortal 8 小时 16 分钟前
很多都是一层层 return err,等下 err 直接到 response 了
我反而有点疑惑你的思路...目前 Gorm 这样我反而觉得是最合理最方便的 |
2
aababc OP @Immortal #1 我的想法是在最上层的错误处理器里统一处理 error 并记录相关的错误信息而后返回 response ,但是我再使用 gorm 的时候,我希望在查询出错的时候能记录到 error 和执行的 SQL ,但是 gorm 返回的错误并没有携带 SQL 语句,如果要记录 gorm error 时执行的 SQL 就需要使用 gorm 自己的 Logger ,这样感觉就会把错误信息切分成两部分,我的错误处理器中记录一部分,如果要查询具体的 SQL 就需要去 gorm 的日志中查看
|
![]() |
3
Div1ne 7 小时 51 分钟前
你自己写一个 logger trace ,类似
func (l SQLLogger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) { sql, rows := fc() if err != nil { log.Errorf("[DB Error] %v | SQL: %s | Rows: %d", err, sql, rows) } } 然后创建 gorm 的时候,把这个传给 config: &gorm.Config{ Logger: SQLLogger{logger.Default.LogMode(logger.Info)}, } |
![]() |
4
Div1ne 7 小时 49 分钟前
gorm 本身是为了让关注点分离:sql 打印这些属于上下文,由 trace 负责。error 只负责管理错误。
|
6
rarpainting 7 小时 28 分钟前
如果你是打算特定位置特定格式来记录,可以在 if err!=nil 里用 dryrun
如果你是在事务里的话,gorm 的 Transaction 给的太灵活了,不会有官方手段的,项目内部规定一个 error 格式就好 总体来说你的问题虽然奇怪,但是解决方法还是足够的 |
![]() |
7
Immortal 7 小时 24 分钟前
@aababc #2
现代框架的方案一边都是在 Server 收到 Request 的时候,为每个 Request 创建一个 TraceID 在 Context 中,所有后续的 Log 都会打印出这个 TraceID 来追踪整个 Request 的处理情况.这样就不会出现你说的 DB 和逻辑日志分离了. 具体处理可以试试在 Gorm 的 DB 实例中注入这个 TraceID,类似 traceCtx := context.WithValue(context.Background(),traceKey,traceID) db := db.WithContext(traceCtx) 如果日志中没有可以像 3L 说的这样注入一个自定义的 TraceLogger 在打印的时候也打印出 TraceID. |
![]() |
8
wogogoing PRO 这应该是 Gorm 的设计理念。返回 error 是业务级别的,而 logtrace 则是日志级别的,并且支持自定义实现,这样让使用者可以更加的自由。
你可以看一下我在 go-sail 中对 trace 的自定义实现: https://github.com/keepchen/go-sail/blob/main/lib/db/logger.go 这样,可以开发者可以自行做很多事情,灵活度更高。 |
9
aababc OP @Immortal #7 咋说呢,我们现在的场景也有 traceID 上下文也能关联起来,现在使用的是 slog ,添加这个 traceID 也是挺恶心的,不单需要重新赋值 request ,还需要自己实现 slog 的 handler
|
![]() |
10
Immortal 6 小时 41 分钟前
@aababc #9
不用动 Request 吧,把处理后的 slog 和 db 可以直接放在入口的 ctx 里,实际逻辑和日志用自定义的 Ctx 去处理,就能统一注入 TraceID 了? |
11
veni2023 6 小时 8 分钟前
请求进来时 gorm 和 slog 都关联对应的请求 traceID ,不就可以了吗?这两应该都支持接入 OpenTelemetry
|
![]() |
12
iyaozhen 6 小时 0 分钟前
你的想法不能算错,但有些问题你没考虑到
1. sql 是不能随便显示的,如果混在 error 中,就可能打印在日志(这在大公司是不允许的),甚至返回给用户 2. 日志打印还是有技巧的,既不能多也不能少,你应该靠业务中的日志定位问题,而不是 sql 。类似打印 request 请求体、sql 原文,是不合规的 你的诉求 gorm 应该能实现,但我没这样需求,具体没弄过 |
13
Sendya 5 小时 48 分钟前
我这是通过 gorm plugin 和 gorm hooks 增加 gorm 的执行 before,after 的流程,在里面处理想要记录的信息,虽然我这边是记录上报给 opentelemetry, 你想记录日志也是同理的,这样还不用入侵你原始业务代码
https://github.com/omalloc/contrib/blob/main/kratos/orm/gorm_tracing_callbacks.go#L81 |