Include more (and customizable) context with backup logs
This commit is contained in:
parent
b26db99ee7
commit
902f9f5944
|
@ -1,7 +1,7 @@
|
||||||
package router
|
package router
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"emperror.dev/errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/pterodactyl/wings/server"
|
"github.com/pterodactyl/wings/server"
|
||||||
|
@ -38,9 +38,14 @@ func postServerBackup(c *gin.Context) {
|
||||||
return
|
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) {
|
go func(b backup.BackupInterface, serv *server.Server) {
|
||||||
if err := serv.Backup(b); err != nil {
|
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)
|
}(adapter, s)
|
||||||
|
|
||||||
|
|
|
@ -70,10 +70,7 @@ func (s *Server) Backup(b backup.BackupInterface) error {
|
||||||
"error": notifyError,
|
"error": notifyError,
|
||||||
}).Warn("failed to notify panel of failed backup state")
|
}).Warn("failed to notify panel of failed backup state")
|
||||||
} else {
|
} else {
|
||||||
s.Log().WithFields(log.Fields{
|
s.Log().WithFields(log.Fields{"backup": b.Identifier()}).Info("notified panel of failed backup state")
|
||||||
"backup": b.Identifier(),
|
|
||||||
"error": err,
|
|
||||||
}).Info("notified panel of failed backup state")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = s.Events().PublishJson(BackupCompletedEvent+":"+b.Identifier(), map[string]interface{}{
|
_ = s.Events().PublishJson(BackupCompletedEvent+":"+b.Identifier(), map[string]interface{}{
|
||||||
|
|
|
@ -12,9 +12,11 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type AdapterType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
LocalBackupAdapter = "wings"
|
LocalBackupAdapter AdapterType = "wings"
|
||||||
S3BackupAdapter = "s3"
|
S3BackupAdapter AdapterType = "s3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ArchiveDetails struct {
|
type ArchiveDetails struct {
|
||||||
|
@ -41,6 +43,9 @@ type Backup struct {
|
||||||
// An array of files to ignore when generating this backup. This should be
|
// An array of files to ignore when generating this backup. This should be
|
||||||
// compatible with a standard .gitignore structure.
|
// compatible with a standard .gitignore structure.
|
||||||
Ignore string `json:"ignore"`
|
Ignore string `json:"ignore"`
|
||||||
|
|
||||||
|
adapter AdapterType
|
||||||
|
logContext map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// noinspection GoNameStartsWithPackageName
|
// noinspection GoNameStartsWithPackageName
|
||||||
|
@ -48,6 +53,9 @@ type BackupInterface interface {
|
||||||
// Returns the UUID of this backup as tracked by the panel instance.
|
// Returns the UUID of this backup as tracked by the panel instance.
|
||||||
Identifier() string
|
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
|
// Generates a backup in whatever the configured source for the specific
|
||||||
// implementation is.
|
// implementation is.
|
||||||
Generate(string, string) (*ArchiveDetails, error)
|
Generate(string, string) (*ArchiveDetails, error)
|
||||||
|
@ -160,3 +168,13 @@ func (b *Backup) Details() *ArchiveDetails {
|
||||||
func (b *Backup) Ignored() string {
|
func (b *Backup) Ignored() string {
|
||||||
return b.Ignore
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package backup
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/apex/log"
|
|
||||||
"github.com/pterodactyl/wings/server/filesystem"
|
"github.com/pterodactyl/wings/server/filesystem"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
@ -40,6 +39,11 @@ func (b *LocalBackup) Remove() error {
|
||||||
return os.Remove(b.Path())
|
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
|
// Generates a backup of the selected files and pushes it to the defined location
|
||||||
// for this instance.
|
// for this instance.
|
||||||
func (b *LocalBackup) Generate(basePath, ignore string) (*ArchiveDetails, error) {
|
func (b *LocalBackup) Generate(basePath, ignore string) (*ArchiveDetails, error) {
|
||||||
|
@ -48,16 +52,11 @@ func (b *LocalBackup) Generate(basePath, ignore string) (*ArchiveDetails, error)
|
||||||
Ignore: ignore,
|
Ignore: ignore,
|
||||||
}
|
}
|
||||||
|
|
||||||
l := log.WithFields(log.Fields{
|
b.log().Info("creating backup for server...")
|
||||||
"backup_id": b.Uuid,
|
|
||||||
"adapter": "local",
|
|
||||||
})
|
|
||||||
|
|
||||||
l.Info("creating backup for server...")
|
|
||||||
if err := a.Create(b.Path()); err != nil {
|
if err := a.Create(b.Path()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
l.Info("created backup successfully")
|
b.log().Info("created backup successfully")
|
||||||
|
|
||||||
return b.Details(), nil
|
return b.Details(), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Request struct {
|
type Request struct {
|
||||||
Adapter string `json:"adapter"`
|
Adapter AdapterType `json:"adapter"`
|
||||||
Uuid string `json:"uuid"`
|
Uuid string `json:"uuid"`
|
||||||
Ignore string `json:"ignore"`
|
Ignore string `json:"ignore"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates a new local backup struct.
|
// Generates a new local backup struct.
|
||||||
|
@ -19,8 +19,9 @@ func (r *Request) NewLocalBackup() (*LocalBackup, error) {
|
||||||
|
|
||||||
return &LocalBackup{
|
return &LocalBackup{
|
||||||
Backup{
|
Backup{
|
||||||
Uuid: r.Uuid,
|
Uuid: r.Uuid,
|
||||||
Ignore: r.Ignore,
|
Ignore: r.Ignore,
|
||||||
|
adapter: LocalBackupAdapter,
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -33,8 +34,9 @@ func (r *Request) NewS3Backup() (*S3Backup, error) {
|
||||||
|
|
||||||
return &S3Backup{
|
return &S3Backup{
|
||||||
Backup: Backup{
|
Backup: Backup{
|
||||||
Uuid: r.Uuid,
|
Uuid: r.Uuid,
|
||||||
Ignore: r.Ignore,
|
Ignore: r.Ignore,
|
||||||
|
adapter: S3BackupAdapter,
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package backup
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/apex/log"
|
|
||||||
"github.com/pterodactyl/wings/api"
|
"github.com/pterodactyl/wings/api"
|
||||||
"github.com/pterodactyl/wings/server/filesystem"
|
"github.com/pterodactyl/wings/server/filesystem"
|
||||||
"io"
|
"io"
|
||||||
|
@ -17,6 +16,16 @@ type S3Backup struct {
|
||||||
|
|
||||||
var _ BackupInterface = (*S3Backup)(nil)
|
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
|
// 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.
|
// presigned URL, and then deletes the backup from the disk.
|
||||||
func (s *S3Backup) Generate(basePath, ignore string) (*ArchiveDetails, error) {
|
func (s *S3Backup) Generate(basePath, ignore string) (*ArchiveDetails, error) {
|
||||||
|
@ -27,16 +36,11 @@ func (s *S3Backup) Generate(basePath, ignore string) (*ArchiveDetails, error) {
|
||||||
Ignore: ignore,
|
Ignore: ignore,
|
||||||
}
|
}
|
||||||
|
|
||||||
l := log.WithFields(log.Fields{
|
s.log().Info("creating backup for server...")
|
||||||
"backup_id": s.Uuid,
|
|
||||||
"adapter": "s3",
|
|
||||||
})
|
|
||||||
|
|
||||||
l.Info("creating backup for server...")
|
|
||||||
if err := a.Create(s.Path()); err != nil {
|
if err := a.Create(s.Path()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
l.Info("created backup successfully")
|
s.log().Info("created backup successfully")
|
||||||
|
|
||||||
rc, err := os.Open(s.Path())
|
rc, err := os.Open(s.Path())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -51,11 +55,6 @@ func (s *S3Backup) Generate(basePath, ignore string) (*ArchiveDetails, error) {
|
||||||
return s.Details(), nil
|
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
|
// Reader provides a wrapper around an existing io.Reader
|
||||||
// but implements io.Closer in order to satisfy an io.ReadCloser.
|
// but implements io.Closer in order to satisfy an io.ReadCloser.
|
||||||
type Reader struct {
|
type Reader struct {
|
||||||
|
@ -70,26 +69,20 @@ func (Reader) Close() error {
|
||||||
func (s *S3Backup) generateRemoteRequest(rc io.ReadCloser) error {
|
func (s *S3Backup) generateRemoteRequest(rc io.ReadCloser) error {
|
||||||
defer rc.Close()
|
defer rc.Close()
|
||||||
|
|
||||||
l := log.WithFields(log.Fields{
|
s.log().Debug("attempting to get size of backup...")
|
||||||
"backup_id": s.Uuid,
|
|
||||||
"adapter": "s3",
|
|
||||||
})
|
|
||||||
|
|
||||||
l.Debug("attempting to get size of backup...")
|
|
||||||
size, err := s.Backup.Size()
|
size, err := s.Backup.Size()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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)
|
urls, err := api.New().GetBackupRemoteUploadURLs(s.Backup.Uuid, size)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
l.Debug("got S3 upload urls from the Panel")
|
s.log().Debug("got S3 upload urls from the Panel")
|
||||||
partCount := len(urls.Parts)
|
s.log().WithField("parts", len(urls.Parts)).Info("attempting to upload backup to s3 endpoint...")
|
||||||
l.WithField("parts", partCount).Info("attempting to upload backup...")
|
|
||||||
|
|
||||||
handlePart := func(part string, size int64) (string, error) {
|
handlePart := func(part string, size int64) (string, error) {
|
||||||
r, err := http.NewRequest(http.MethodPut, part, nil)
|
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 {
|
for i, part := range urls.Parts {
|
||||||
// Get the size for the current part.
|
// Get the size for the current part.
|
||||||
var partSize int64
|
var partSize int64
|
||||||
if i+1 < partCount {
|
if i+1 < len(urls.Parts) {
|
||||||
partSize = urls.PartSize
|
partSize = urls.PartSize
|
||||||
} else {
|
} else {
|
||||||
// This is the remaining size for the last part,
|
// 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.
|
// Attempt to upload the part.
|
||||||
if _, err := handlePart(part, partSize); err != nil {
|
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
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user