如何在Golang中获取GORM查询(如插入)的执行时间
获取GORM查询执行时间的两种可行方案
方案一:自定义GORM Logger捕获执行时间
GORM的日志系统支持扩展,你可以实现gorm.Logger接口,在处理日志逻辑时直接拿到查询的执行耗时,再推送到外部监控系统。
示例代码:
import ( "context" "time" "gorm.io/gorm" "gorm.io/gorm/logger" ) type CustomLogger struct { logger.Interface } func (l CustomLogger) LogMode(level logger.LogLevel) logger.Interface { return CustomLogger{l.Interface.LogMode(level)} } func (l CustomLogger) Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) { // 保留原有日志输出逻辑 l.Interface.Trace(ctx, begin, fc, err) // 计算执行耗时 elapsed := time.Since(begin) sqlContent, rows := fc() // 此处将耗时、SQL语句、影响行数等信息发送到监控系统 // 例如:sendToMonitor(elapsed, sqlContent, rows, err) } // 初始化DB时替换默认Logger db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{ Logger: CustomLogger{logger.Default.LogMode(logger.Info)}, })
这个方案能覆盖所有GORM操作(查询、插入、更新、删除等),无需为单个操作单独编写逻辑,适合全局监控需求。
方案二:利用Hook+上下文记录单操作耗时
如果只需要针对特定操作(比如插入)统计耗时,可以结合GORM的Before/After Hook与上下文实现:
示例代码:
import ( "context" "time" "gorm.io/gorm" ) // 定义上下文key,用于存储操作开始时间 type startTimeKey struct{} // 执行插入前,通过WithContext传入开始时间 ctx := context.WithValue(context.Background(), startTimeKey{}, time.Now()) result := db.WithContext(ctx).Create(&User{Name: "test"}) // 为模型定义AfterCreate Hook func (u *User) AfterCreate(tx *gorm.DB) error { if beginTime, ok := tx.ctx.Value(startTimeKey{}).(time.Time); ok { elapsed := time.Since(beginTime) // 将耗时发送到监控系统 // sendToMonitor(elapsed, "INSERT", tx.Statement.SQL.String()) } return nil }
注意:该方案需要为每个需要统计的操作定义对应Hook(如AfterUpdate对应更新操作),适合针对性统计的场景。
补充说明
- 两种方案获取的耗时与GORM日志中输出的毫秒级数据完全一致
- 方案一适合全局统一统计所有SQL操作耗时,方案二更灵活,可聚焦特定操作
内容的提问来源于stack exchange,提问作者mehrdad
相关产品推荐
相关产品推荐

