diff --git a/backend/go.mod b/backend/go.mod index 2177e83..0889ced 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -14,13 +14,13 @@ require ( github.com/joho/godotenv v1.5.1 github.com/lib/pq v1.10.9 github.com/minio/minio-go/v7 v7.0.92 + github.com/shirou/gopsutil/v4 v4.25.5 github.com/stretchr/testify v1.10.0 github.com/swaggo/files v1.0.1 github.com/swaggo/gin-swagger v1.6.0 github.com/swaggo/swag v1.16.4 github.com/testcontainers/testcontainers-go v0.37.0 golang.org/x/crypto v0.39.0 - golang.org/x/sys v0.33.0 gorm.io/driver/postgres v1.5.11 gorm.io/gorm v1.26.1 ) @@ -101,8 +101,6 @@ require ( github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/xid v1.6.0 // indirect - github.com/shirou/gopsutil v3.21.11+incompatible // indirect - github.com/shirou/gopsutil/v4 v4.25.5 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/tinylib/msgp v1.3.0 // indirect github.com/tklauser/go-sysconf v0.3.15 // indirect @@ -120,6 +118,7 @@ require ( golang.org/x/arch v0.17.0 // indirect golang.org/x/net v0.40.0 // indirect golang.org/x/sync v0.15.0 // indirect + golang.org/x/sys v0.33.0 // indirect golang.org/x/text v0.26.0 // indirect golang.org/x/tools v0.33.0 // indirect google.golang.org/protobuf v1.36.6 // indirect diff --git a/backend/go.sum b/backend/go.sum index 592749e..679d4e5 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -213,8 +213,6 @@ github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0t github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= -github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= -github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil/v4 v4.25.5 h1:rtd9piuSMGeU8g1RMXjZs9y9luK5BwtnG7dZaQUJAsc= github.com/shirou/gopsutil/v4 v4.25.5/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= diff --git a/backend/internal/config/config.go b/backend/internal/config/config.go index 934eb82..53461de 100644 --- a/backend/internal/config/config.go +++ b/backend/internal/config/config.go @@ -111,7 +111,7 @@ func loadEnvVariables() { log.Info("ENV_MODE loaded", "mode", env.EnvMode) env.PostgresesInstallDir = filepath.Join(backendRoot, "tools", "postgresql") - tools.VerifyPostgresesInstallation(env.EnvMode, env.PostgresesInstallDir) + tools.VerifyPostgresesInstallation(log, env.EnvMode, env.PostgresesInstallDir) // Store the data and temp folders one level below the root // (projectRoot/postgresus-data -> /postgresus-data) diff --git a/backend/internal/features/backups/background_service.go b/backend/internal/features/backups/background_service.go index 8d51908..79f6670 100644 --- a/backend/internal/features/backups/background_service.go +++ b/backend/internal/features/backups/background_service.go @@ -1,10 +1,10 @@ package backups import ( + "log/slog" "postgresus-backend/internal/config" "postgresus-backend/internal/features/databases" "postgresus-backend/internal/features/storages" - "postgresus-backend/internal/util/logger" "time" ) @@ -15,15 +15,14 @@ type BackupBackgroundService struct { storageService *storages.StorageService lastBackupTime time.Time + logger *slog.Logger } -var log = logger.GetLogger() - func (s *BackupBackgroundService) Run() { s.lastBackupTime = time.Now().UTC() if err := s.failBackupsInProgress(); err != nil { - log.Error("Failed to fail backups in progress", "error", err) + s.logger.Error("Failed to fail backups in progress", "error", err) panic(err) } @@ -37,11 +36,11 @@ func (s *BackupBackgroundService) Run() { } if err := s.cleanOldBackups(); err != nil { - log.Error("Failed to clean old backups", "error", err) + s.logger.Error("Failed to clean old backups", "error", err) } if err := s.runPendingBackups(); err != nil { - log.Error("Failed to run pending backups", "error", err) + s.logger.Error("Failed to run pending backups", "error", err) } s.lastBackupTime = time.Now().UTC() @@ -102,7 +101,7 @@ func (s *BackupBackgroundService) cleanOldBackups() error { dateBeforeBackupsShouldBeDeleted, ) if err != nil { - log.Error( + s.logger.Error( "Failed to find old backups for database", "databaseId", database.ID, @@ -115,7 +114,7 @@ func (s *BackupBackgroundService) cleanOldBackups() error { for _, backup := range oldBackups { storage, err := s.storageService.GetStorageByID(backup.StorageID) if err != nil { - log.Error( + s.logger.Error( "Failed to get storage by ID", "storageId", backup.StorageID, @@ -125,14 +124,18 @@ func (s *BackupBackgroundService) cleanOldBackups() error { continue } - storage.DeleteFile(backup.ID) - - if err := s.backupRepository.DeleteByID(backup.ID); err != nil { - log.Error("Failed to delete old backup", "backupId", backup.ID, "error", err) + err = storage.DeleteFile(backup.ID) + if err != nil { + s.logger.Error("Failed to delete backup file", "backupId", backup.ID, "error", err) continue } - log.Info("Deleted old backup", "backupId", backup.ID, "databaseId", database.ID) + if err := s.backupRepository.DeleteByID(backup.ID); err != nil { + s.logger.Error("Failed to delete old backup", "backupId", backup.ID, "error", err) + continue + } + + s.logger.Info("Deleted old backup", "backupId", backup.ID, "databaseId", database.ID) } } @@ -152,7 +155,7 @@ func (s *BackupBackgroundService) runPendingBackups() error { lastBackup, err := s.backupRepository.FindLastByDatabaseID(database.ID) if err != nil { - log.Error( + s.logger.Error( "Failed to get last backup for database", "databaseId", database.ID, @@ -168,7 +171,7 @@ func (s *BackupBackgroundService) runPendingBackups() error { } if database.BackupInterval.ShouldTriggerBackup(time.Now().UTC(), lastBackupTime) { - log.Info( + s.logger.Info( "Triggering scheduled backup", "databaseId", database.ID, @@ -177,7 +180,7 @@ func (s *BackupBackgroundService) runPendingBackups() error { ) go s.backupService.MakeBackup(database.ID) - log.Info("Successfully triggered scheduled backup", "databaseId", database.ID) + s.logger.Info("Successfully triggered scheduled backup", "databaseId", database.ID) } } diff --git a/backend/internal/features/backups/di.go b/backend/internal/features/backups/di.go index aabb419..38f6cd3 100644 --- a/backend/internal/features/backups/di.go +++ b/backend/internal/features/backups/di.go @@ -2,25 +2,22 @@ package backups import ( "postgresus-backend/internal/features/backups/usecases" - usecases_postgresql "postgresus-backend/internal/features/backups/usecases/postgresql" "postgresus-backend/internal/features/databases" "postgresus-backend/internal/features/notifiers" "postgresus-backend/internal/features/storages" "postgresus-backend/internal/features/users" + "postgresus-backend/internal/util/logger" "time" ) -var createPostgresqlBackupUsecase = &usecases_postgresql.CreatePostgresqlBackupUsecase{} -var createBackupUseCase = &usecases.CreateBackupUsecase{ - CreatePostgresqlBackupUsecase: createPostgresqlBackupUsecase, -} var backupRepository = &BackupRepository{} var backupService = &BackupService{ databases.GetDatabaseService(), storages.GetStorageService(), backupRepository, notifiers.GetNotifierService(), - createBackupUseCase, + usecases.GetCreateBackupUsecase(), + logger.GetLogger(), } var backupBackgroundService = &BackupBackgroundService{ @@ -29,6 +26,7 @@ var backupBackgroundService = &BackupBackgroundService{ databases.GetDatabaseService(), storages.GetStorageService(), time.Now().UTC(), + logger.GetLogger(), } var backupController = &BackupController{ diff --git a/backend/internal/features/backups/model.go b/backend/internal/features/backups/model.go index 64da0d6..d09b215 100644 --- a/backend/internal/features/backups/model.go +++ b/backend/internal/features/backups/model.go @@ -1,6 +1,7 @@ package backups import ( + "log/slog" "postgresus-backend/internal/features/databases" "postgresus-backend/internal/features/storages" "time" @@ -27,14 +28,14 @@ type Backup struct { CreatedAt time.Time `json:"createdAt" gorm:"column:created_at"` } -func (b *Backup) DeleteBackupFromStorage() { +func (b *Backup) DeleteBackupFromStorage(logger *slog.Logger) { if b.Status != BackupStatusCompleted { return } err := b.Storage.DeleteFile(b.ID) if err != nil { - log.Error("Failed to delete backup from storage", "error", err) + logger.Error("Failed to delete backup from storage", "error", err) // we ignore the error, because the access to the storage // may be lost, file already deleted, etc. } diff --git a/backend/internal/features/backups/service.go b/backend/internal/features/backups/service.go index 8ca48e5..2b1ee04 100644 --- a/backend/internal/features/backups/service.go +++ b/backend/internal/features/backups/service.go @@ -3,6 +3,7 @@ package backups import ( "errors" "fmt" + "log/slog" "postgresus-backend/internal/features/backups/usecases" "postgresus-backend/internal/features/databases" "postgresus-backend/internal/features/notifiers" @@ -21,6 +22,8 @@ type BackupService struct { notifierService *notifiers.NotifierService createBackupUseCase *usecases.CreateBackupUsecase + + logger *slog.Logger } func (s *BackupService) OnBeforeDbStorageChange( @@ -53,7 +56,7 @@ func (s *BackupService) OnBeforeDbStorageChange( if err := backup.Storage.DeleteFile(backup.ID); err != nil { // most likely we cannot do nothing with this, // so we just remove the backup model - log.Error("Failed to delete backup file", "error", err) + s.logger.Error("Failed to delete backup file", "error", err) } if err := s.backupRepository.DeleteByID(backup.ID); err != nil { @@ -125,7 +128,7 @@ func (s *BackupService) DeleteBackup( return errors.New("backup is in progress") } - backup.DeleteBackupFromStorage() + backup.DeleteBackupFromStorage(s.logger) backup.Status = BackupStatusDeleted return s.backupRepository.Save(backup) @@ -134,24 +137,24 @@ func (s *BackupService) DeleteBackup( func (s *BackupService) MakeBackup(databaseID uuid.UUID) { database, err := s.databaseService.GetDatabaseByID(databaseID) if err != nil { - log.Error("Failed to get database by ID", "error", err) + s.logger.Error("Failed to get database by ID", "error", err) return } lastBackup, err := s.backupRepository.FindLastByDatabaseID(databaseID) if err != nil { - log.Error("Failed to find last backup by database ID", "error", err) + s.logger.Error("Failed to find last backup by database ID", "error", err) return } if lastBackup != nil && lastBackup.Status == BackupStatusInProgress { - log.Error("Backup is in progress") + s.logger.Error("Backup is in progress") return } storage, err := s.storageService.GetStorageByID(database.StorageID) if err != nil { - log.Error("Failed to get storage by ID", "error", err) + s.logger.Error("Failed to get storage by ID", "error", err) return } @@ -170,7 +173,7 @@ func (s *BackupService) MakeBackup(databaseID uuid.UUID) { } if err := s.backupRepository.Save(backup); err != nil { - log.Error("Failed to save backup", "error", err) + s.logger.Error("Failed to save backup", "error", err) return } @@ -183,7 +186,7 @@ func (s *BackupService) MakeBackup(databaseID uuid.UUID) { backup.BackupDurationMs = time.Since(start).Milliseconds() if err := s.backupRepository.Save(backup); err != nil { - log.Error("Failed to update backup progress", "error", err) + s.logger.Error("Failed to update backup progress", "error", err) } } @@ -201,7 +204,7 @@ func (s *BackupService) MakeBackup(databaseID uuid.UUID) { backup.BackupSizeMb = 0 if updateErr := s.databaseService.SetBackupError(databaseID, errMsg); updateErr != nil { - log.Error( + s.logger.Error( "Failed to update database last backup time", "databaseId", databaseID, @@ -211,7 +214,7 @@ func (s *BackupService) MakeBackup(databaseID uuid.UUID) { } if err := s.backupRepository.Save(backup); err != nil { - log.Error("Failed to save backup", "error", err) + s.logger.Error("Failed to save backup", "error", err) } s.SendBackupNotification( @@ -228,14 +231,14 @@ func (s *BackupService) MakeBackup(databaseID uuid.UUID) { backup.BackupDurationMs = time.Since(start).Milliseconds() if err := s.backupRepository.Save(backup); err != nil { - log.Error("Failed to save backup", "error", err) + s.logger.Error("Failed to save backup", "error", err) return } // Update database last backup time now := time.Now().UTC() if updateErr := s.databaseService.SetLastBackupTime(databaseID, now); updateErr != nil { - log.Error( + s.logger.Error( "Failed to update database last backup time", "databaseId", databaseID, diff --git a/backend/internal/features/backups/usecases/di.go b/backend/internal/features/backups/usecases/di.go new file mode 100644 index 0000000..69fb3c1 --- /dev/null +++ b/backend/internal/features/backups/usecases/di.go @@ -0,0 +1,13 @@ +package usecases + +import ( + usecases_postgresql "postgresus-backend/internal/features/backups/usecases/postgresql" +) + +var createBackupUsecase = &CreateBackupUsecase{ + usecases_postgresql.GetCreatePostgresqlBackupUsecase(), +} + +func GetCreateBackupUsecase() *CreateBackupUsecase { + return createBackupUsecase +} diff --git a/backend/internal/features/backups/usecases/postgresql/create_backup_uc.go b/backend/internal/features/backups/usecases/postgresql/create_backup_uc.go index f943147..e823020 100644 --- a/backend/internal/features/backups/usecases/postgresql/create_backup_uc.go +++ b/backend/internal/features/backups/usecases/postgresql/create_backup_uc.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "io" + "log/slog" "os" "os/exec" "path/filepath" @@ -16,15 +17,14 @@ import ( "postgresus-backend/internal/features/databases" pgtypes "postgresus-backend/internal/features/databases/databases/postgresql" "postgresus-backend/internal/features/storages" - "postgresus-backend/internal/util/logger" "postgresus-backend/internal/util/tools" "github.com/google/uuid" ) -var log = logger.GetLogger() - -type CreatePostgresqlBackupUsecase struct{} +type CreatePostgresqlBackupUsecase struct { + logger *slog.Logger +} // Execute creates a backup of the database func (uc *CreatePostgresqlBackupUsecase) Execute( @@ -35,7 +35,7 @@ func (uc *CreatePostgresqlBackupUsecase) Execute( completedMBs float64, ), ) error { - log.Info( + uc.logger.Info( "Creating PostgreSQL backup via pg_dump custom format", "databaseId", db.ID, @@ -85,7 +85,7 @@ func (uc *CreatePostgresqlBackupUsecase) streamToStorage( db *databases.Database, backupProgressListener func(completedMBs float64), ) error { - log.Info("Streaming PostgreSQL backup to storage", "pgBin", pgBin, "args", args) + uc.logger.Info("Streaming PostgreSQL backup to storage", "pgBin", pgBin, "args", args) ctx, cancel := context.WithTimeout(context.Background(), 60*time.Minute) defer cancel() @@ -126,7 +126,7 @@ func (uc *CreatePostgresqlBackupUsecase) streamToStorage( // Verify .pgpass file was created correctly if info, err := os.Stat(pgpassFile); err == nil { - log.Info("Temporary .pgpass file created successfully", + uc.logger.Info("Temporary .pgpass file created successfully", "pgpassFile", pgpassFile, "size", info.Size(), "mode", info.Mode(), @@ -136,17 +136,17 @@ func (uc *CreatePostgresqlBackupUsecase) streamToStorage( } cmd := exec.CommandContext(ctx, pgBin, args...) - log.Info("Executing PostgreSQL backup command", "command", cmd.String()) + uc.logger.Info("Executing PostgreSQL backup command", "command", cmd.String()) // Start with system environment variables to preserve Windows PATH, SystemRoot, etc. cmd.Env = os.Environ() // Use the .pgpass file for authentication cmd.Env = append(cmd.Env, "PGPASSFILE="+pgpassFile) - log.Info("Using temporary .pgpass file for authentication", "pgpassFile", pgpassFile) + uc.logger.Info("Using temporary .pgpass file for authentication", "pgpassFile", pgpassFile) // Debug password setup (without exposing the actual password) - log.Info("Setting up PostgreSQL environment", + uc.logger.Info("Setting up PostgreSQL environment", "passwordLength", len(password), "passwordEmpty", password == "", "pgBin", pgBin, @@ -170,11 +170,11 @@ func (uc *CreatePostgresqlBackupUsecase) streamToStorage( // Require SSL when explicitly configured if shouldRequireSSL { cmd.Env = append(cmd.Env, "PGSSLMODE=require") - log.Info("Using required SSL mode", "configuredHttps", db.Postgresql.IsHttps) + uc.logger.Info("Using required SSL mode", "configuredHttps", db.Postgresql.IsHttps) } else { // SSL not explicitly required, but prefer it if available cmd.Env = append(cmd.Env, "PGSSLMODE=prefer") - log.Info("Using preferred SSL mode", "configuredHttps", db.Postgresql.IsHttps) + uc.logger.Info("Using preferred SSL mode", "configuredHttps", db.Postgresql.IsHttps) } // Set other SSL parameters to avoid certificate issues @@ -220,7 +220,7 @@ func (uc *CreatePostgresqlBackupUsecase) streamToStorage( // Start streaming into storage in its own goroutine saveErrCh := make(chan error, 1) go func() { - saveErrCh <- storage.SaveFile(backupID, storageReader) + saveErrCh <- storage.SaveFile(uc.logger, backupID, storageReader) }() // Start pg_dump @@ -251,7 +251,7 @@ func (uc *CreatePostgresqlBackupUsecase) streamToStorage( if config.IsShouldShutdown() { if pipeWriter, ok := countingWriter.writer.(*io.PipeWriter); ok { if err := pipeWriter.Close(); err != nil { - log.Error("Failed to close counting writer", "error", err) + uc.logger.Error("Failed to close counting writer", "error", err) } } @@ -262,7 +262,7 @@ func (uc *CreatePostgresqlBackupUsecase) streamToStorage( // Close the pipe writer to signal end of data if pipeWriter, ok := countingWriter.writer.(*io.PipeWriter); ok { if err := pipeWriter.Close(); err != nil { - log.Error("Failed to close counting writer", "error", err) + uc.logger.Error("Failed to close counting writer", "error", err) } } @@ -297,7 +297,7 @@ func (uc *CreatePostgresqlBackupUsecase) streamToStorage( // Enhanced debugging for exit status 1 with empty stderr if exitCode == 1 && strings.TrimSpace(stderrStr) == "" { - log.Error("pg_dump failed with exit status 1 but no stderr output", + uc.logger.Error("pg_dump failed with exit status 1 but no stderr output", "pgBin", pgBin, "args", args, "env_vars", []string{ @@ -323,7 +323,7 @@ func (uc *CreatePostgresqlBackupUsecase) streamToStorage( strings.Join(args, " "), ) } else if exitCode == -1073741819 { // 0xC0000005 in decimal - log.Error("PostgreSQL tool crashed with access violation", + uc.logger.Error("PostgreSQL tool crashed with access violation", "pgBin", pgBin, "args", args, "exitCode", fmt.Sprintf("0x%X", uint32(exitCode)), diff --git a/backend/internal/features/backups/usecases/postgresql/di.go b/backend/internal/features/backups/usecases/postgresql/di.go new file mode 100644 index 0000000..e4a1f4e --- /dev/null +++ b/backend/internal/features/backups/usecases/postgresql/di.go @@ -0,0 +1,13 @@ +package usecases_postgresql + +import ( + "postgresus-backend/internal/util/logger" +) + +var createPostgresqlBackupUsecase = &CreatePostgresqlBackupUsecase{ + logger.GetLogger(), +} + +func GetCreatePostgresqlBackupUsecase() *CreatePostgresqlBackupUsecase { + return createPostgresqlBackupUsecase +} diff --git a/backend/internal/features/databases/databases/postgresql/model.go b/backend/internal/features/databases/databases/postgresql/model.go index 4aea4cc..77510f0 100644 --- a/backend/internal/features/databases/databases/postgresql/model.go +++ b/backend/internal/features/databases/databases/postgresql/model.go @@ -4,7 +4,7 @@ import ( "context" "errors" "fmt" - "postgresus-backend/internal/util/logger" + "log/slog" "postgresus-backend/internal/util/tools" "time" @@ -12,8 +12,6 @@ import ( "github.com/jackc/pgx/v5" ) -var log = logger.GetLogger() - type PostgresqlDatabase struct { ID uuid.UUID `json:"id" gorm:"primaryKey;type:uuid;default:gen_random_uuid()"` @@ -61,15 +59,19 @@ func (p *PostgresqlDatabase) Validate() error { return nil } -func (p *PostgresqlDatabase) TestConnection() error { +func (p *PostgresqlDatabase) TestConnection(logger *slog.Logger) error { ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() - return testSingleDatabaseConnection(ctx, p) + return testSingleDatabaseConnection(logger, ctx, p) } // testSingleDatabaseConnection tests connection to a specific database for pg_dump -func testSingleDatabaseConnection(ctx context.Context, p *PostgresqlDatabase) error { +func testSingleDatabaseConnection( + logger *slog.Logger, + ctx context.Context, + p *PostgresqlDatabase, +) error { // For single database backup, we need to connect to the specific database if p.Database == nil || *p.Database == "" { return errors.New("database name is required for single database backup (pg_dump)") @@ -89,7 +91,7 @@ func testSingleDatabaseConnection(ctx context.Context, p *PostgresqlDatabase) er } defer func() { if closeErr := conn.Close(ctx); closeErr != nil { - log.Error("Failed to close connection", "error", closeErr) + logger.Error("Failed to close connection", "error", closeErr) } }() diff --git a/backend/internal/features/databases/di.go b/backend/internal/features/databases/di.go index c3f13f8..7b31e07 100644 --- a/backend/internal/features/databases/di.go +++ b/backend/internal/features/databases/di.go @@ -1,12 +1,16 @@ package databases -import "postgresus-backend/internal/features/users" +import ( + "postgresus-backend/internal/features/users" + "postgresus-backend/internal/util/logger" +) var databaseRepository = &DatabaseRepository{} var databaseService = &DatabaseService{ databaseRepository, nil, + logger.GetLogger(), } var databaseController = &DatabaseController{ diff --git a/backend/internal/features/databases/interfaces.go b/backend/internal/features/databases/interfaces.go index f703a4e..fcb9e3e 100644 --- a/backend/internal/features/databases/interfaces.go +++ b/backend/internal/features/databases/interfaces.go @@ -1,13 +1,17 @@ package databases -import "github.com/google/uuid" +import ( + "log/slog" + + "github.com/google/uuid" +) type DatabaseValidator interface { Validate() error } type DatabaseConnector interface { - TestConnection() error + TestConnection(logger *slog.Logger) error } type DatabaseStorageChangeListener interface { diff --git a/backend/internal/features/databases/model.go b/backend/internal/features/databases/model.go index b28c594..d22b63d 100644 --- a/backend/internal/features/databases/model.go +++ b/backend/internal/features/databases/model.go @@ -2,6 +2,7 @@ package databases import ( "errors" + "log/slog" "postgresus-backend/internal/features/databases/databases/postgresql" "postgresus-backend/internal/features/intervals" "postgresus-backend/internal/features/notifiers" @@ -102,8 +103,8 @@ func (d *Database) ValidateUpdate(old, new Database) error { return nil } -func (d *Database) TestConnection() error { - return d.getSpecificDatabase().TestConnection() +func (d *Database) TestConnection(logger *slog.Logger) error { + return d.getSpecificDatabase().TestConnection(logger) } func (d *Database) getSpecificDatabase() DatabaseConnector { diff --git a/backend/internal/features/databases/service.go b/backend/internal/features/databases/service.go index 029cd04..2b57915 100644 --- a/backend/internal/features/databases/service.go +++ b/backend/internal/features/databases/service.go @@ -2,6 +2,7 @@ package databases import ( "errors" + "log/slog" users_models "postgresus-backend/internal/features/users/models" "time" @@ -11,6 +12,7 @@ import ( type DatabaseService struct { dbRepository *DatabaseRepository dbStorageChangeListener DatabaseStorageChangeListener + logger *slog.Logger } func (s *DatabaseService) SetDatabaseStorageChangeListener( @@ -131,7 +133,7 @@ func (s *DatabaseService) TestDatabaseConnection( return errors.New("you have not access to this database") } - err = database.TestConnection() + err = database.TestConnection(s.logger) if err != nil { lastSaveError := err.Error() database.LastBackupErrorMessage = &lastSaveError @@ -146,7 +148,7 @@ func (s *DatabaseService) TestDatabaseConnection( func (s *DatabaseService) TestDatabaseConnectionDirect( database *Database, ) error { - return database.TestConnection() + return database.TestConnection(s.logger) } func (s *DatabaseService) GetDatabaseByID( diff --git a/backend/internal/features/notifiers/di.go b/backend/internal/features/notifiers/di.go index 5f07ece..e063371 100644 --- a/backend/internal/features/notifiers/di.go +++ b/backend/internal/features/notifiers/di.go @@ -1,10 +1,14 @@ package notifiers -import "postgresus-backend/internal/features/users" +import ( + "postgresus-backend/internal/features/users" + "postgresus-backend/internal/util/logger" +) var notifierRepository = &NotifierRepository{} var notifierService = &NotifierService{ notifierRepository, + logger.GetLogger(), } var notifierController = &NotifierController{ notifierService, diff --git a/backend/internal/features/notifiers/interfaces.go b/backend/internal/features/notifiers/interfaces.go index d04ca2c..f1dfa39 100644 --- a/backend/internal/features/notifiers/interfaces.go +++ b/backend/internal/features/notifiers/interfaces.go @@ -1,7 +1,9 @@ package notifiers +import "log/slog" + type NotificationSender interface { - Send(heading string, message string) error + Send(logger *slog.Logger, heading string, message string) error Validate() error } diff --git a/backend/internal/features/notifiers/model.go b/backend/internal/features/notifiers/model.go index d72df92..e3a1877 100644 --- a/backend/internal/features/notifiers/model.go +++ b/backend/internal/features/notifiers/model.go @@ -2,6 +2,7 @@ package notifiers import ( "errors" + "log/slog" "postgresus-backend/internal/features/notifiers/notifiers/email_notifier" telegram_notifier "postgresus-backend/internal/features/notifiers/notifiers/telegram" webhook_notifier "postgresus-backend/internal/features/notifiers/notifiers/webhook" @@ -34,8 +35,8 @@ func (n *Notifier) Validate() error { return n.getSpecificNotifier().Validate() } -func (n *Notifier) Send(heading string, message string) error { - err := n.getSpecificNotifier().Send(heading, message) +func (n *Notifier) Send(logger *slog.Logger, heading string, message string) error { + err := n.getSpecificNotifier().Send(logger, heading, message) if err != nil { lastSendError := err.Error() diff --git a/backend/internal/features/notifiers/notifiers/email_notifier/model.go b/backend/internal/features/notifiers/notifiers/email_notifier/model.go index 4bad853..a74dae5 100644 --- a/backend/internal/features/notifiers/notifiers/email_notifier/model.go +++ b/backend/internal/features/notifiers/notifiers/email_notifier/model.go @@ -4,6 +4,7 @@ import ( "crypto/tls" "errors" "fmt" + "log/slog" "net" "net/smtp" "time" @@ -56,7 +57,7 @@ func (e *EmailNotifier) Validate() error { return nil } -func (e *EmailNotifier) Send(heading string, message string) error { +func (e *EmailNotifier) Send(logger *slog.Logger, heading string, message string) error { // Compose email from := e.SMTPUser to := []string{e.TargetEmail} diff --git a/backend/internal/features/notifiers/notifiers/telegram/model.go b/backend/internal/features/notifiers/notifiers/telegram/model.go index 08ef907..be8a4d8 100644 --- a/backend/internal/features/notifiers/notifiers/telegram/model.go +++ b/backend/internal/features/notifiers/notifiers/telegram/model.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "io" + "log/slog" "net/http" "net/url" "strings" @@ -33,7 +34,7 @@ func (t *TelegramNotifier) Validate() error { return nil } -func (t *TelegramNotifier) Send(heading string, message string) error { +func (t *TelegramNotifier) Send(logger *slog.Logger, heading string, message string) error { fullMessage := heading if message != "" { fullMessage = fmt.Sprintf("%s\n\n%s", heading, message) diff --git a/backend/internal/features/notifiers/notifiers/webhook/model.go b/backend/internal/features/notifiers/notifiers/webhook/model.go index 4064280..a7d19ba 100644 --- a/backend/internal/features/notifiers/notifiers/webhook/model.go +++ b/backend/internal/features/notifiers/notifiers/webhook/model.go @@ -6,15 +6,13 @@ import ( "errors" "fmt" "io" + "log/slog" "net/http" "net/url" - "postgresus-backend/internal/util/logger" "github.com/google/uuid" ) -var log = logger.GetLogger() - type WebhookNotifier struct { NotifierID uuid.UUID `json:"notifierId" gorm:"primaryKey;column:notifier_id"` WebhookURL string `json:"webhookUrl" gorm:"not null;column:webhook_url"` @@ -37,7 +35,7 @@ func (t *WebhookNotifier) Validate() error { return nil } -func (t *WebhookNotifier) Send(heading string, message string) error { +func (t *WebhookNotifier) Send(logger *slog.Logger, heading string, message string) error { switch t.WebhookMethod { case WebhookMethodGET: reqURL := fmt.Sprintf("%s?heading=%s&message=%s", @@ -52,7 +50,7 @@ func (t *WebhookNotifier) Send(heading string, message string) error { } defer func() { if cerr := resp.Body.Close(); cerr != nil { - log.Error("failed to close response body", "error", cerr) + logger.Error("failed to close response body", "error", cerr) } }() @@ -85,7 +83,7 @@ func (t *WebhookNotifier) Send(heading string, message string) error { defer func() { if cerr := resp.Body.Close(); cerr != nil { - log.Error("failed to close response body", "error", cerr) + logger.Error("failed to close response body", "error", cerr) } }() diff --git a/backend/internal/features/notifiers/service.go b/backend/internal/features/notifiers/service.go index fd2f0c1..0fd33b0 100644 --- a/backend/internal/features/notifiers/service.go +++ b/backend/internal/features/notifiers/service.go @@ -2,16 +2,15 @@ package notifiers import ( "errors" + "log/slog" users_models "postgresus-backend/internal/features/users/models" - "postgresus-backend/internal/util/logger" "github.com/google/uuid" ) -var log = logger.GetLogger() - type NotifierService struct { notifierRepository *NotifierRepository + logger *slog.Logger } func (s *NotifierService) SaveNotifier( @@ -87,7 +86,7 @@ func (s *NotifierService) SendTestNotification( return errors.New("you have not access to this notifier") } - err = notifier.Send("Test message", "This is a test message") + err = notifier.Send(s.logger, "Test message", "This is a test message") if err != nil { return err } @@ -102,7 +101,7 @@ func (s *NotifierService) SendTestNotification( func (s *NotifierService) SendTestNotificationToNotifier( notifier *Notifier, ) error { - return notifier.Send("Test message", "This is a test message") + return notifier.Send(s.logger, "Test message", "This is a test message") } func (s *NotifierService) SendNotification( @@ -121,20 +120,20 @@ func (s *NotifierService) SendNotification( return } - err = notifiedFromDb.Send(title, message) + err = notifiedFromDb.Send(s.logger, title, message) if err != nil { errMsg := err.Error() notifiedFromDb.LastSendError = &errMsg err = s.notifierRepository.Save(notifiedFromDb) if err != nil { - log.Error("Failed to save notifier", "error", err) + s.logger.Error("Failed to save notifier", "error", err) } } notifiedFromDb.LastSendError = nil err = s.notifierRepository.Save(notifiedFromDb) if err != nil { - log.Error("Failed to save notifier", "error", err) + s.logger.Error("Failed to save notifier", "error", err) } } diff --git a/backend/internal/features/restores/background_service.go b/backend/internal/features/restores/background_service.go index 85a1dfd..08512fa 100644 --- a/backend/internal/features/restores/background_service.go +++ b/backend/internal/features/restores/background_service.go @@ -1,19 +1,18 @@ package restores import ( + "log/slog" "postgresus-backend/internal/features/restores/enums" - "postgresus-backend/internal/util/logger" ) -var log = logger.GetLogger() - type RestoreBackgroundService struct { restoreRepository *RestoreRepository + logger *slog.Logger } func (s *RestoreBackgroundService) Run() { if err := s.failRestoresInProgress(); err != nil { - log.Error("Failed to fail restores in progress", "error", err) + s.logger.Error("Failed to fail restores in progress", "error", err) panic(err) } } diff --git a/backend/internal/features/restores/di.go b/backend/internal/features/restores/di.go index 94faa36..fb3e576 100644 --- a/backend/internal/features/restores/di.go +++ b/backend/internal/features/restores/di.go @@ -5,15 +5,16 @@ import ( "postgresus-backend/internal/features/restores/usecases" "postgresus-backend/internal/features/storages" "postgresus-backend/internal/features/users" + "postgresus-backend/internal/util/logger" ) -var restoreBackupUsecase = &usecases.RestoreBackupUsecase{} var restoreRepository = &RestoreRepository{} var restoreService = &RestoreService{ backups.GetBackupService(), restoreRepository, storages.GetStorageService(), - restoreBackupUsecase, + usecases.GetRestoreBackupUsecase(), + logger.GetLogger(), } var restoreController = &RestoreController{ restoreService, @@ -22,6 +23,7 @@ var restoreController = &RestoreController{ var restoreBackgroundService = &RestoreBackgroundService{ restoreRepository, + logger.GetLogger(), } func GetRestoreController() *RestoreController { diff --git a/backend/internal/features/restores/service.go b/backend/internal/features/restores/service.go index c0a8fa4..55e51a4 100644 --- a/backend/internal/features/restores/service.go +++ b/backend/internal/features/restores/service.go @@ -2,6 +2,7 @@ package restores import ( "errors" + "log/slog" "postgresus-backend/internal/features/backups" "postgresus-backend/internal/features/databases" "postgresus-backend/internal/features/restores/enums" @@ -19,6 +20,7 @@ type RestoreService struct { restoreRepository *RestoreRepository storageService *storages.StorageService restoreBackupUsecase *usecases.RestoreBackupUsecase + logger *slog.Logger } func (s *RestoreService) GetRestores( @@ -53,7 +55,7 @@ func (s *RestoreService) RestoreBackupWithAuth( go func() { if err := s.RestoreBackup(backup, requestDTO); err != nil { - log.Error("Failed to restore backup", "error", err) + s.logger.Error("Failed to restore backup", "error", err) } }() diff --git a/backend/internal/features/restores/usecases/di.go b/backend/internal/features/restores/usecases/di.go new file mode 100644 index 0000000..a4ec802 --- /dev/null +++ b/backend/internal/features/restores/usecases/di.go @@ -0,0 +1,13 @@ +package usecases + +import ( + usecases_postgresql "postgresus-backend/internal/features/restores/usecases/postgresql" +) + +var restoreBackupUsecase = &RestoreBackupUsecase{ + usecases_postgresql.GetRestorePostgresqlBackupUsecase(), +} + +func GetRestoreBackupUsecase() *RestoreBackupUsecase { + return restoreBackupUsecase +} diff --git a/backend/internal/features/restores/usecases/postgresql/di.go b/backend/internal/features/restores/usecases/postgresql/di.go new file mode 100644 index 0000000..5c3828f --- /dev/null +++ b/backend/internal/features/restores/usecases/postgresql/di.go @@ -0,0 +1,13 @@ +package usecases_postgresql + +import ( + "postgresus-backend/internal/util/logger" +) + +var restorePostgresqlBackupUsecase = &RestorePostgresqlBackupUsecase{ + logger.GetLogger(), +} + +func GetRestorePostgresqlBackupUsecase() *RestorePostgresqlBackupUsecase { + return restorePostgresqlBackupUsecase +} diff --git a/backend/internal/features/restores/usecases/postgresql/restore_backup_uc.go b/backend/internal/features/restores/usecases/postgresql/restore_backup_uc.go index d01babf..928169b 100644 --- a/backend/internal/features/restores/usecases/postgresql/restore_backup_uc.go +++ b/backend/internal/features/restores/usecases/postgresql/restore_backup_uc.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "io" + "log/slog" "os" "os/exec" "path/filepath" @@ -18,15 +19,14 @@ import ( pgtypes "postgresus-backend/internal/features/databases/databases/postgresql" "postgresus-backend/internal/features/restores/models" "postgresus-backend/internal/features/storages" - "postgresus-backend/internal/util/logger" "postgresus-backend/internal/util/tools" "github.com/google/uuid" ) -var log = logger.GetLogger() - -type RestorePostgresqlBackupUsecase struct{} +type RestorePostgresqlBackupUsecase struct { + logger *slog.Logger +} func (uc *RestorePostgresqlBackupUsecase) Execute( restore models.Restore, @@ -37,7 +37,7 @@ func (uc *RestorePostgresqlBackupUsecase) Execute( return errors.New("database type not supported") } - log.Info( + uc.logger.Info( "Restoring PostgreSQL backup via pg_restore", "restoreId", restore.ID, @@ -96,7 +96,7 @@ func (uc *RestorePostgresqlBackupUsecase) restoreFromStorage( storage *storages.Storage, pgConfig *pgtypes.PostgresqlDatabase, ) error { - log.Info( + uc.logger.Info( "Restoring PostgreSQL backup from storage via temporary file", "pgBin", pgBin, @@ -142,7 +142,7 @@ func (uc *RestorePostgresqlBackupUsecase) restoreFromStorage( } if info, err := os.Stat(pgpassFile); err == nil { - log.Info("Temporary .pgpass file created successfully", + uc.logger.Info("Temporary .pgpass file created successfully", "pgpassFile", pgpassFile, "size", info.Size(), "mode", info.Mode(), @@ -183,7 +183,7 @@ func (uc *RestorePostgresqlBackupUsecase) downloadBackupToTempFile( tempBackupFile := filepath.Join(tempDir, "backup.dump") // Get backup data from storage - log.Info( + uc.logger.Info( "Downloading backup file from storage to temporary file", "backupId", backup.ID, @@ -197,7 +197,7 @@ func (uc *RestorePostgresqlBackupUsecase) downloadBackupToTempFile( } defer func() { if err := backupReader.Close(); err != nil { - log.Error("Failed to close backup reader", "error", err) + uc.logger.Error("Failed to close backup reader", "error", err) } }() @@ -209,7 +209,7 @@ func (uc *RestorePostgresqlBackupUsecase) downloadBackupToTempFile( } defer func() { if err := tempFile.Close(); err != nil { - log.Error("Failed to close temporary file", "error", err) + uc.logger.Error("Failed to close temporary file", "error", err) } }() @@ -226,7 +226,7 @@ func (uc *RestorePostgresqlBackupUsecase) downloadBackupToTempFile( return "", nil, fmt.Errorf("failed to close temporary backup file: %w", err) } - log.Info("Backup file written to temporary location", "tempFile", tempBackupFile) + uc.logger.Info("Backup file written to temporary location", "tempFile", tempBackupFile) return tempBackupFile, cleanupFunc, nil } @@ -239,7 +239,7 @@ func (uc *RestorePostgresqlBackupUsecase) executePgRestore( pgConfig *pgtypes.PostgresqlDatabase, ) error { cmd := exec.CommandContext(ctx, pgBin, args...) - log.Info("Executing PostgreSQL restore command", "command", cmd.String()) + uc.logger.Info("Executing PostgreSQL restore command", "command", cmd.String()) // Setup environment variables uc.setupPgRestoreEnvironment(cmd, pgpassFile, pgConfig) @@ -302,7 +302,7 @@ func (uc *RestorePostgresqlBackupUsecase) setupPgRestoreEnvironment( // Use the .pgpass file for authentication cmd.Env = append(cmd.Env, "PGPASSFILE="+pgpassFile) - log.Info("Using temporary .pgpass file for authentication", "pgpassFile", pgpassFile) + uc.logger.Info("Using temporary .pgpass file for authentication", "pgpassFile", pgpassFile) // Add PostgreSQL-specific environment variables cmd.Env = append(cmd.Env, "PGCLIENTENCODING=UTF8") @@ -318,10 +318,10 @@ func (uc *RestorePostgresqlBackupUsecase) setupPgRestoreEnvironment( // Configure SSL settings if shouldRequireSSL { cmd.Env = append(cmd.Env, "PGSSLMODE=require") - log.Info("Using required SSL mode", "configuredHttps", pgConfig.IsHttps) + uc.logger.Info("Using required SSL mode", "configuredHttps", pgConfig.IsHttps) } else { cmd.Env = append(cmd.Env, "PGSSLMODE=prefer") - log.Info("Using preferred SSL mode", "configuredHttps", pgConfig.IsHttps) + uc.logger.Info("Using preferred SSL mode", "configuredHttps", pgConfig.IsHttps) } // Set other SSL parameters to avoid certificate issues diff --git a/backend/internal/features/restores/usecases/restore_backup_uc.go b/backend/internal/features/restores/usecases/restore_backup_uc.go index b172634..046c47f 100644 --- a/backend/internal/features/restores/usecases/restore_backup_uc.go +++ b/backend/internal/features/restores/usecases/restore_backup_uc.go @@ -10,7 +10,7 @@ import ( ) type RestoreBackupUsecase struct { - RestorePostgresqlBackupUsecase *usecases_postgresql.RestorePostgresqlBackupUsecase + restorePostgresqlBackupUsecase *usecases_postgresql.RestorePostgresqlBackupUsecase } func (uc *RestoreBackupUsecase) Execute( @@ -19,7 +19,7 @@ func (uc *RestoreBackupUsecase) Execute( storage *storages.Storage, ) error { if restore.Backup.Database.Type == databases.DatabaseTypePostgres { - return uc.RestorePostgresqlBackupUsecase.Execute(restore, backup, storage) + return uc.restorePostgresqlBackupUsecase.Execute(restore, backup, storage) } return errors.New("database type not supported") diff --git a/backend/internal/features/storages/interfaces.go b/backend/internal/features/storages/interfaces.go index 63355b1..e2f32a9 100644 --- a/backend/internal/features/storages/interfaces.go +++ b/backend/internal/features/storages/interfaces.go @@ -2,12 +2,13 @@ package storages import ( "io" + "log/slog" "github.com/google/uuid" ) type StorageFileSaver interface { - SaveFile(fileID uuid.UUID, file io.Reader) error + SaveFile(logger *slog.Logger, fileID uuid.UUID, file io.Reader) error GetFile(fileID uuid.UUID) (io.ReadCloser, error) diff --git a/backend/internal/features/storages/model.go b/backend/internal/features/storages/model.go index b8bc32c..d24326c 100644 --- a/backend/internal/features/storages/model.go +++ b/backend/internal/features/storages/model.go @@ -3,6 +3,7 @@ package storages import ( "errors" "io" + "log/slog" local_storage "postgresus-backend/internal/features/storages/storages/local" s3_storage "postgresus-backend/internal/features/storages/storages/s3" @@ -21,8 +22,8 @@ type Storage struct { S3Storage *s3_storage.S3Storage `json:"s3Storage" gorm:"foreignKey:StorageID"` } -func (s *Storage) SaveFile(fileID uuid.UUID, file io.Reader) error { - err := s.getSpecificStorage().SaveFile(fileID, file) +func (s *Storage) SaveFile(logger *slog.Logger, fileID uuid.UUID, file io.Reader) error { + err := s.getSpecificStorage().SaveFile(logger, fileID, file) if err != nil { lastSaveError := err.Error() s.LastSaveError = &lastSaveError diff --git a/backend/internal/features/storages/model_test.go b/backend/internal/features/storages/model_test.go index 8c3afed..534516e 100644 --- a/backend/internal/features/storages/model_test.go +++ b/backend/internal/features/storages/model_test.go @@ -9,6 +9,7 @@ import ( "path/filepath" local_storage "postgresus-backend/internal/features/storages/storages/local" s3_storage "postgresus-backend/internal/features/storages/storages/s3" + "postgresus-backend/internal/util/logger" "testing" "time" @@ -87,7 +88,7 @@ func Test_Storage_BasicOperations(t *testing.T) { fileID := uuid.New() - err = tc.storage.SaveFile(fileID, bytes.NewReader(fileData)) + err = tc.storage.SaveFile(logger.GetLogger(), fileID, bytes.NewReader(fileData)) require.NoError(t, err, "SaveFile should succeed") file, err := tc.storage.GetFile(fileID) @@ -104,7 +105,7 @@ func Test_Storage_BasicOperations(t *testing.T) { require.NoError(t, err, "Should be able to read test file") fileID := uuid.New() - err = tc.storage.SaveFile(fileID, bytes.NewReader(fileData)) + err = tc.storage.SaveFile(logger.GetLogger(), fileID, bytes.NewReader(fileData)) require.NoError(t, err, "SaveFile should succeed") err = tc.storage.DeleteFile(fileID) diff --git a/backend/internal/features/storages/storages/local/model.go b/backend/internal/features/storages/storages/local/model.go index 2b0d50f..ee0eabf 100644 --- a/backend/internal/features/storages/storages/local/model.go +++ b/backend/internal/features/storages/storages/local/model.go @@ -3,16 +3,14 @@ package local_storage import ( "fmt" "io" + "log/slog" "os" "path/filepath" "postgresus-backend/internal/config" - "postgresus-backend/internal/util/logger" "github.com/google/uuid" ) -var log = logger.GetLogger() - // LocalStorage uses ./postgresus_local_backups folder as a // directory for backups and ./postgresus_local_temp folder as a // directory for temp files @@ -24,20 +22,20 @@ func (l *LocalStorage) TableName() string { return "local_storages" } -func (l *LocalStorage) SaveFile(fileID uuid.UUID, file io.Reader) error { - log.Info("Starting to save file to local storage", "fileId", fileID.String()) +func (l *LocalStorage) SaveFile(logger *slog.Logger, fileID uuid.UUID, file io.Reader) error { + logger.Info("Starting to save file to local storage", "fileId", fileID.String()) if err := l.ensureDirectories(); err != nil { - log.Error("Failed to ensure directories", "fileId", fileID.String(), "error", err) + logger.Error("Failed to ensure directories", "fileId", fileID.String(), "error", err) return err } tempFilePath := filepath.Join(config.GetEnv().TempFolder, fileID.String()) - log.Debug("Creating temp file", "fileId", fileID.String(), "tempPath", tempFilePath) + logger.Debug("Creating temp file", "fileId", fileID.String(), "tempPath", tempFilePath) tempFile, err := os.Create(tempFilePath) if err != nil { - log.Error( + logger.Error( "Failed to create temp file", "fileId", fileID.String(), @@ -52,26 +50,26 @@ func (l *LocalStorage) SaveFile(fileID uuid.UUID, file io.Reader) error { _ = tempFile.Close() }() - log.Debug("Copying file data to temp file", "fileId", fileID.String()) + logger.Debug("Copying file data to temp file", "fileId", fileID.String()) _, err = io.Copy(tempFile, file) if err != nil { - log.Error("Failed to write to temp file", "fileId", fileID.String(), "error", err) + logger.Error("Failed to write to temp file", "fileId", fileID.String(), "error", err) return fmt.Errorf("failed to write to temp file: %w", err) } if err = tempFile.Sync(); err != nil { - log.Error("Failed to sync temp file", "fileId", fileID.String(), "error", err) + logger.Error("Failed to sync temp file", "fileId", fileID.String(), "error", err) return fmt.Errorf("failed to sync temp file: %w", err) } err = tempFile.Close() if err != nil { - log.Error("Failed to close temp file", "fileId", fileID.String(), "error", err) + logger.Error("Failed to close temp file", "fileId", fileID.String(), "error", err) return fmt.Errorf("failed to close temp file: %w", err) } finalPath := filepath.Join(config.GetEnv().DataFolder, fileID.String()) - log.Debug( + logger.Debug( "Moving file from temp to final location", "fileId", fileID.String(), @@ -81,7 +79,7 @@ func (l *LocalStorage) SaveFile(fileID uuid.UUID, file io.Reader) error { // Move the file from temp to backups directory if err = os.Rename(tempFilePath, finalPath); err != nil { - log.Error( + logger.Error( "Failed to move file from temp to backups", "fileId", fileID.String(), @@ -95,7 +93,7 @@ func (l *LocalStorage) SaveFile(fileID uuid.UUID, file io.Reader) error { return fmt.Errorf("failed to move file from temp to backups: %w", err) } - log.Info( + logger.Info( "Successfully saved file to local storage", "fileId", fileID.String(), diff --git a/backend/internal/features/storages/storages/s3/model.go b/backend/internal/features/storages/storages/s3/model.go index a59f5f7..0c92a63 100644 --- a/backend/internal/features/storages/storages/s3/model.go +++ b/backend/internal/features/storages/storages/s3/model.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "io" + "log/slog" "strings" "time" @@ -27,7 +28,7 @@ func (s *S3Storage) TableName() string { return "s3_storages" } -func (s *S3Storage) SaveFile(fileID uuid.UUID, file io.Reader) error { +func (s *S3Storage) SaveFile(logger *slog.Logger, fileID uuid.UUID, file io.Reader) error { client, err := s.getClient() if err != nil { return err diff --git a/backend/internal/features/tests/postgresql_backup_restore_test.go b/backend/internal/features/tests/postgresql_backup_restore_test.go index 9e7d536..9dff630 100644 --- a/backend/internal/features/tests/postgresql_backup_restore_test.go +++ b/backend/internal/features/tests/postgresql_backup_restore_test.go @@ -128,9 +128,13 @@ func testBackupRestoreForVersion(t *testing.T, pgVersion string) { } // Make backup - createBackupUC := &usecases_postgresql_backup.CreatePostgresqlBackupUsecase{} progressTracker := func(completedMBs float64) {} - err = createBackupUC.Execute(backupID, backupDbConfig, storage, progressTracker) + err = usecases_postgresql_backup.GetCreatePostgresqlBackupUsecase().Execute( + backupID, + backupDbConfig, + storage, + progressTracker, + ) assert.NoError(t, err) // Create new database @@ -173,7 +177,7 @@ func testBackupRestoreForVersion(t *testing.T, pgVersion string) { } // Restore the backup - restoreBackupUC := &usecases_postgresql_restore.RestorePostgresqlBackupUsecase{} + restoreBackupUC := usecases_postgresql_restore.GetRestorePostgresqlBackupUsecase() err = restoreBackupUC.Execute(restore, completedBackup, storage) assert.NoError(t, err) diff --git a/backend/internal/util/tools/postgresql.go b/backend/internal/util/tools/postgresql.go index 5ea599c..ad7f8b4 100644 --- a/backend/internal/util/tools/postgresql.go +++ b/backend/internal/util/tools/postgresql.go @@ -2,16 +2,14 @@ package tools import ( "fmt" + "log/slog" "os" "path/filepath" "runtime" env_utils "postgresus-backend/internal/util/env" - "postgresus-backend/internal/util/logger" ) -var log = logger.GetLogger() - // GetPostgresqlExecutable returns the full path to a specific PostgreSQL executable // for the given version. Common executables include: pg_dump, psql, etc. // On Windows, automatically appends .exe extension. @@ -37,7 +35,11 @@ func GetPostgresqlExecutable( // client tools (pg_dump, psql) available. // In development: ./tools/postgresql/postgresql-{VERSION}/bin // In production: /usr/pgsql-{VERSION}/bin -func VerifyPostgresesInstallation(envMode env_utils.EnvMode, postgresesInstallDir string) { +func VerifyPostgresesInstallation( + logger *slog.Logger, + envMode env_utils.EnvMode, + postgresesInstallDir string, +) { versions := []PostgresqlVersion{ PostgresqlVersion13, PostgresqlVersion14, @@ -54,7 +56,7 @@ func VerifyPostgresesInstallation(envMode env_utils.EnvMode, postgresesInstallDi for _, version := range versions { binDir := getPostgresqlBasePath(version, envMode, postgresesInstallDir) - log.Info( + logger.Info( "Verifying PostgreSQL installation", "version", string(version), @@ -64,7 +66,7 @@ func VerifyPostgresesInstallation(envMode env_utils.EnvMode, postgresesInstallDi if _, err := os.Stat(binDir); os.IsNotExist(err) { if envMode == env_utils.EnvModeDevelopment { - log.Error( + logger.Error( "PostgreSQL bin directory not found. Make sure PostgreSQL is installed. Read ./tools/readme.md for details", "version", string(version), @@ -72,7 +74,7 @@ func VerifyPostgresesInstallation(envMode env_utils.EnvMode, postgresesInstallDi binDir, ) } else { - log.Error( + logger.Error( "PostgreSQL bin directory not found. Please ensure PostgreSQL client tools are installed.", "version", string(version), @@ -91,7 +93,7 @@ func VerifyPostgresesInstallation(envMode env_utils.EnvMode, postgresesInstallDi postgresesInstallDir, ) - log.Info( + logger.Info( "Checking for PostgreSQL command", "command", cmd, @@ -103,7 +105,7 @@ func VerifyPostgresesInstallation(envMode env_utils.EnvMode, postgresesInstallDi if _, err := os.Stat(cmdPath); os.IsNotExist(err) { if envMode == env_utils.EnvModeDevelopment { - log.Error( + logger.Error( "PostgreSQL command not found. Make sure PostgreSQL is installed. Read ./tools/readme.md for details", "command", cmd, @@ -113,7 +115,7 @@ func VerifyPostgresesInstallation(envMode env_utils.EnvMode, postgresesInstallDi cmdPath, ) } else { - log.Error( + logger.Error( "PostgreSQL command not found. Please ensure PostgreSQL client tools are properly installed.", "command", cmd, @@ -126,7 +128,7 @@ func VerifyPostgresesInstallation(envMode env_utils.EnvMode, postgresesInstallDi os.Exit(1) } - log.Info( + logger.Info( "PostgreSQL command found", "command", cmd, @@ -135,7 +137,7 @@ func VerifyPostgresesInstallation(envMode env_utils.EnvMode, postgresesInstallDi ) } - log.Info( + logger.Info( "Installation of PostgreSQL verified", "version", string(version), @@ -144,7 +146,7 @@ func VerifyPostgresesInstallation(envMode env_utils.EnvMode, postgresesInstallDi ) } - log.Info("All PostgreSQL version-specific client tools verification completed successfully!") + logger.Info("All PostgreSQL version-specific client tools verification completed successfully!") } func getPostgresqlBasePath(