package db import ( "context" "errors" "fmt" "time" "github.com/sirupsen/logrus" "gorm.io/gorm/logger" ) type safeLogger struct { logger.Config } func newSafeLogger() logger.Interface { return &safeLogger{Config: logger.Config{ SlowThreshold: 200 * time.Millisecond, LogLevel: logger.Warn, IgnoreRecordNotFoundError: false, }} } func (l *safeLogger) LogMode(level logger.LogLevel) logger.Interface { newLogger := *l newLogger.LogLevel = level return &newLogger } func (l *safeLogger) Info(ctx context.Context, _ string, _ ...interface{}) { if l.LogLevel >= logger.Info { logrus.WithContext(ctx).WithField("component", "gorm").Info("数据库信息事件") } } func (l *safeLogger) Warn(ctx context.Context, _ string, _ ...interface{}) { if l.LogLevel >= logger.Warn { logrus.WithContext(ctx).WithField("component", "gorm").Warn("数据库警告事件") } } func (l *safeLogger) Error(ctx context.Context, _ string, _ ...interface{}) { if l.LogLevel >= logger.Error { logrus.WithContext(ctx).WithField("component", "gorm").Error("数据库错误事件") } } func (l *safeLogger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) { if l.LogLevel <= logger.Silent { return } elapsed := time.Since(begin) switch { case err != nil && l.LogLevel >= logger.Error && (!errors.Is(err, logger.ErrRecordNotFound) || !l.IgnoreRecordNotFoundError): _, rows := fc() l.traceEntry(ctx, elapsed, rows).WithFields(logrus.Fields{ "error_type": fmt.Sprintf("%T", err), "record_not_found": errors.Is(err, logger.ErrRecordNotFound), }).Error("数据库操作失败") case elapsed > l.SlowThreshold && l.SlowThreshold != 0 && l.LogLevel >= logger.Warn: _, rows := fc() l.traceEntry(ctx, elapsed, rows). WithField("slow_threshold", l.SlowThreshold.String()). Warn("数据库慢查询") case l.LogLevel >= logger.Info: _, rows := fc() l.traceEntry(ctx, elapsed, rows).Info("数据库操作完成") } } func (l *safeLogger) traceEntry(ctx context.Context, elapsed time.Duration, rows int64) *logrus.Entry { return logrus.WithContext(ctx).WithFields(logrus.Fields{ "component": "gorm", "elapsed_ms": float64(elapsed.Nanoseconds()) / 1e6, "rows_affected": rows, }) }