package database import ( "context" "errors" "time" "github.com/rs/zerolog" "gorm.io/gorm" "gorm.io/gorm/logger" ) type GormLogger struct { logger zerolog.Logger slowThreshold time.Duration logLevel logger.LogLevel } func (l *GormLogger) LogMode(level logger.LogLevel) logger.Interface { newLogger := *l newLogger.logLevel = level return &newLogger } func (l *GormLogger) Info(ctx context.Context, msg string, data ...interface{}) { if l.logLevel >= logger.Info { l.logger.Info().Msgf(msg, data...) } } func (l *GormLogger) Warn(ctx context.Context, msg string, data ...interface{}) { if l.logLevel >= logger.Warn { l.logger.Warn().Msgf(msg, data...) } } func (l *GormLogger) Error(ctx context.Context, msg string, data ...interface{}) { if l.logLevel >= logger.Error { l.logger.Error().Msgf(msg, data...) } } func (l *GormLogger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) { if l.logLevel <= logger.Silent { return } elapsed := time.Since(begin) sql, rows := fc() switch { // cache miss / record not found - expected, don't log as error case err != nil && errors.Is(err, gorm.ErrRecordNotFound): if l.logLevel >= logger.Info { l.logger.Debug(). Str("sql", sql). Int64("rows", rows). Dur("elapsed", elapsed). Msg("QueryCacheMiss") } // error query case err != nil && l.logLevel >= logger.Error: l.logger.Error(). Err(err). Str("sql", sql). Int64("rows", rows). Dur("elapsed", elapsed). Msg("QueryError") // slow query case elapsed > l.slowThreshold && l.logLevel >= logger.Warn: l.logger.Warn(). Str("sql", sql). Int64("rows", rows). Dur("elapsed", elapsed). Msg("SlowQuery") // normal query case l.logLevel >= logger.Info: l.logger.Debug(). Str("sql", sql). Int64("rows", rows). Dur("elapsed", elapsed). Msg("Query") } } func NewGormLogger(serviceLogger zerolog.Logger, threshold time.Duration) *GormLogger { return &GormLogger{ logger: serviceLogger.With().Str("module", "gorm").Logger(), slowThreshold: threshold, logLevel: logger.Warn, // default } }