From 902f9f5944feff9371b9c521c607deaac826fa9d Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 27 Dec 2020 16:16:40 -0800 Subject: [PATCH] Include more (and customizable) context with backup logs --- router/router_server_backup.go | 9 ++++-- server/backup.go | 5 +--- server/backup/backup.go | 22 +++++++++++++-- server/backup/backup_local.go | 15 +++++----- server/backup/backup_request.go | 16 ++++++----- server/backup/backup_s3.go | 49 ++++++++++++++------------------- 6 files changed, 65 insertions(+), 51 deletions(-) diff --git a/router/router_server_backup.go b/router/router_server_backup.go index aadb26a..8a44af9 100644 --- a/router/router_server_backup.go +++ b/router/router_server_backup.go @@ -1,7 +1,7 @@ package router import ( - "errors" + "emperror.dev/errors" "fmt" "github.com/gin-gonic/gin" "github.com/pterodactyl/wings/server" @@ -38,9 +38,14 @@ func postServerBackup(c *gin.Context) { return } + // Attach the server ID to the backup log output for easier parsing. + adapter.WithLogContext(map[string]interface{}{ + "server": s.Id(), + }) + go func(b backup.BackupInterface, serv *server.Server) { if err := serv.Backup(b); err != nil { - serv.Log().WithField("error", err).Error("failed to generate backup for server") + serv.Log().WithField("error", errors.WithStackIf(err)).Error("failed to generate backup for server") } }(adapter, s) diff --git a/server/backup.go b/server/backup.go index c9817c2..72b69d7 100644 --- a/server/backup.go +++ b/server/backup.go @@ -70,10 +70,7 @@ func (s *Server) Backup(b backup.BackupInterface) error { "error": notifyError, }).Warn("failed to notify panel of failed backup state") } else { - s.Log().WithFields(log.Fields{ - "backup": b.Identifier(), - "error": err, - }).Info("notified panel of failed backup state") + s.Log().WithFields(log.Fields{"backup": b.Identifier()}).Info("notified panel of failed backup state") } _ = s.Events().PublishJson(BackupCompletedEvent+":"+b.Identifier(), map[string]interface{}{ diff --git a/server/backup/backup.go b/server/backup/backup.go index b7c0c7b..29e7b5d 100644 --- a/server/backup/backup.go +++ b/server/backup/backup.go @@ -12,9 +12,11 @@ import ( "sync" ) +type AdapterType string + const ( - LocalBackupAdapter = "wings" - S3BackupAdapter = "s3" + LocalBackupAdapter AdapterType = "wings" + S3BackupAdapter AdapterType = "s3" ) type ArchiveDetails struct { @@ -41,6 +43,9 @@ type Backup struct { // An array of files to ignore when generating this backup. This should be // compatible with a standard .gitignore structure. Ignore string `json:"ignore"` + + adapter AdapterType + logContext map[string]interface{} } // noinspection GoNameStartsWithPackageName @@ -48,6 +53,9 @@ type BackupInterface interface { // Returns the UUID of this backup as tracked by the panel instance. Identifier() string + // Attaches additional context to the log output for this backup. + WithLogContext(map[string]interface{}) + // Generates a backup in whatever the configured source for the specific // implementation is. Generate(string, string) (*ArchiveDetails, error) @@ -160,3 +168,13 @@ func (b *Backup) Details() *ArchiveDetails { func (b *Backup) Ignored() string { return b.Ignore } + +// Returns a logger instance for this backup with the additional context fields +// assigned to the output. +func (b *Backup) log() *log.Entry { + l := log.WithField("backup", b.Identifier()).WithField("adapter", b.adapter) + for k, v := range b.logContext { + l = l.WithField(k, v) + } + return l +} diff --git a/server/backup/backup_local.go b/server/backup/backup_local.go index 871ebb2..6e07ff3 100644 --- a/server/backup/backup_local.go +++ b/server/backup/backup_local.go @@ -2,7 +2,6 @@ package backup import ( "errors" - "github.com/apex/log" "github.com/pterodactyl/wings/server/filesystem" "os" ) @@ -40,6 +39,11 @@ func (b *LocalBackup) Remove() error { return os.Remove(b.Path()) } +// Attaches additional context to the log output for this backup. +func (b *LocalBackup) WithLogContext(c map[string]interface{}) { + b.logContext = c +} + // Generates a backup of the selected files and pushes it to the defined location // for this instance. func (b *LocalBackup) Generate(basePath, ignore string) (*ArchiveDetails, error) { @@ -48,16 +52,11 @@ func (b *LocalBackup) Generate(basePath, ignore string) (*ArchiveDetails, error) Ignore: ignore, } - l := log.WithFields(log.Fields{ - "backup_id": b.Uuid, - "adapter": "local", - }) - - l.Info("creating backup for server...") + b.log().Info("creating backup for server...") if err := a.Create(b.Path()); err != nil { return nil, err } - l.Info("created backup successfully") + b.log().Info("created backup successfully") return b.Details(), nil } diff --git a/server/backup/backup_request.go b/server/backup/backup_request.go index a26641c..60ba4d7 100644 --- a/server/backup/backup_request.go +++ b/server/backup/backup_request.go @@ -6,9 +6,9 @@ import ( ) type Request struct { - Adapter string `json:"adapter"` - Uuid string `json:"uuid"` - Ignore string `json:"ignore"` + Adapter AdapterType `json:"adapter"` + Uuid string `json:"uuid"` + Ignore string `json:"ignore"` } // Generates a new local backup struct. @@ -19,8 +19,9 @@ func (r *Request) NewLocalBackup() (*LocalBackup, error) { return &LocalBackup{ Backup{ - Uuid: r.Uuid, - Ignore: r.Ignore, + Uuid: r.Uuid, + Ignore: r.Ignore, + adapter: LocalBackupAdapter, }, }, nil } @@ -33,8 +34,9 @@ func (r *Request) NewS3Backup() (*S3Backup, error) { return &S3Backup{ Backup: Backup{ - Uuid: r.Uuid, - Ignore: r.Ignore, + Uuid: r.Uuid, + Ignore: r.Ignore, + adapter: S3BackupAdapter, }, }, nil } diff --git a/server/backup/backup_s3.go b/server/backup/backup_s3.go index 9fd8c41..e5514b0 100644 --- a/server/backup/backup_s3.go +++ b/server/backup/backup_s3.go @@ -2,7 +2,6 @@ package backup import ( "fmt" - "github.com/apex/log" "github.com/pterodactyl/wings/api" "github.com/pterodactyl/wings/server/filesystem" "io" @@ -17,6 +16,16 @@ type S3Backup struct { var _ BackupInterface = (*S3Backup)(nil) +// Removes a backup from the system. +func (s *S3Backup) Remove() error { + return os.Remove(s.Path()) +} + +// Attaches additional context to the log output for this backup. +func (s *S3Backup) WithLogContext(c map[string]interface{}) { + s.logContext = c +} + // Generates a new backup on the disk, moves it into the S3 bucket via the provided // presigned URL, and then deletes the backup from the disk. func (s *S3Backup) Generate(basePath, ignore string) (*ArchiveDetails, error) { @@ -27,16 +36,11 @@ func (s *S3Backup) Generate(basePath, ignore string) (*ArchiveDetails, error) { Ignore: ignore, } - l := log.WithFields(log.Fields{ - "backup_id": s.Uuid, - "adapter": "s3", - }) - - l.Info("creating backup for server...") + s.log().Info("creating backup for server...") if err := a.Create(s.Path()); err != nil { return nil, err } - l.Info("created backup successfully") + s.log().Info("created backup successfully") rc, err := os.Open(s.Path()) if err != nil { @@ -51,11 +55,6 @@ func (s *S3Backup) Generate(basePath, ignore string) (*ArchiveDetails, error) { return s.Details(), nil } -// Removes a backup from the system. -func (s *S3Backup) Remove() error { - return os.Remove(s.Path()) -} - // Reader provides a wrapper around an existing io.Reader // but implements io.Closer in order to satisfy an io.ReadCloser. type Reader struct { @@ -70,26 +69,20 @@ func (Reader) Close() error { func (s *S3Backup) generateRemoteRequest(rc io.ReadCloser) error { defer rc.Close() - l := log.WithFields(log.Fields{ - "backup_id": s.Uuid, - "adapter": "s3", - }) - - l.Debug("attempting to get size of backup...") + s.log().Debug("attempting to get size of backup...") size, err := s.Backup.Size() if err != nil { return err } - l.WithField("size", size).Debug("got size of backup") + s.log().WithField("size", size).Debug("got size of backup") - l.Debug("attempting to get S3 upload urls from Panel...") + s.log().Debug("attempting to get S3 upload urls from Panel...") urls, err := api.New().GetBackupRemoteUploadURLs(s.Backup.Uuid, size) if err != nil { return err } - l.Debug("got S3 upload urls from the Panel") - partCount := len(urls.Parts) - l.WithField("parts", partCount).Info("attempting to upload backup...") + s.log().Debug("got S3 upload urls from the Panel") + s.log().WithField("parts", len(urls.Parts)).Info("attempting to upload backup to s3 endpoint...") handlePart := func(part string, size int64) (string, error) { r, err := http.NewRequest(http.MethodPut, part, nil) @@ -125,7 +118,7 @@ func (s *S3Backup) generateRemoteRequest(rc io.ReadCloser) error { for i, part := range urls.Parts { // Get the size for the current part. var partSize int64 - if i+1 < partCount { + if i+1 < len(urls.Parts) { partSize = urls.PartSize } else { // This is the remaining size for the last part, @@ -135,14 +128,14 @@ func (s *S3Backup) generateRemoteRequest(rc io.ReadCloser) error { // Attempt to upload the part. if _, err := handlePart(part, partSize); err != nil { - l.WithField("part_id", i+1).WithError(err).Warn("failed to upload part") + s.log().WithField("part_id", i+1).WithError(err).Warn("failed to upload part") return err } - l.WithField("part_id", i+1).Info("successfully uploaded backup part") + s.log().WithField("part_id", i+1).Info("successfully uploaded backup part") } - l.WithField("parts", partCount).Info("backup has been successfully uploaded") + s.log().WithField("parts", len(urls.Parts)).Info("backup has been successfully uploaded") return nil }