package database import ( "context" "errors" "fmt" "time" "git.iwork-ai.com/xdc/iqudo-top1/internal/config" "go.uber.org/zap" "gorm.io/driver/mysql" "gorm.io/gorm" gormlogger "gorm.io/gorm/logger" ) func Open(cfg config.DatabaseConfig, log *zap.Logger) (*gorm.DB, error) { db, err := gorm.Open(mysql.Open(cfg.DSN()), &gorm.Config{ Logger: newGORMLogger(log.Named("gorm"), gormlogger.Warn), }) if err != nil { return nil, fmt.Errorf("open mysql: %w", err) } sqlDB, err := db.DB() if err != nil { return nil, fmt.Errorf("get sql database: %w", err) } sqlDB.SetMaxIdleConns(cfg.MaxIdleConnections) sqlDB.SetMaxOpenConns(cfg.MaxOpenConnections) sqlDB.SetConnMaxLifetime(cfg.ConnectionMaxLifetime) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := sqlDB.PingContext(ctx); err != nil { return nil, fmt.Errorf("ping mysql: %w", err) } return db, nil } type zapGORMLogger struct { log *zap.Logger level gormlogger.LogLevel } func newGORMLogger(log *zap.Logger, level gormlogger.LogLevel) gormlogger.Interface { return &zapGORMLogger{log: log, level: level} } func (l *zapGORMLogger) LogMode(level gormlogger.LogLevel) gormlogger.Interface { clone := *l clone.level = level return &clone } func (l *zapGORMLogger) Info(_ context.Context, msg string, data ...interface{}) { if l.level >= gormlogger.Info { l.log.Sugar().Infof(msg, data...) } } func (l *zapGORMLogger) Warn(_ context.Context, msg string, data ...interface{}) { if l.level >= gormlogger.Warn { l.log.Sugar().Warnf(msg, data...) } } func (l *zapGORMLogger) Error(_ context.Context, msg string, data ...interface{}) { if l.level >= gormlogger.Error { l.log.Sugar().Errorf(msg, data...) } } func (l *zapGORMLogger) Trace(_ context.Context, begin time.Time, fc func() (string, int64), err error) { if l.level == gormlogger.Silent { return } sql, rows := fc() fields := []zap.Field{zap.Duration("duration", time.Since(begin)), zap.Int64("rows", rows), zap.String("sql", sql)} if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) && l.level >= gormlogger.Error { l.log.Error("query failed", append(fields, zap.Error(err))...) return } if l.level >= gormlogger.Info { l.log.Debug("query", fields...) } }