diff --git a/cmd/dump.go b/cmd/dump.go index ec5da90..39bb9b4 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -10,6 +10,7 @@ import ( "github.com/google/uuid" "github.com/spf13/cobra" "github.com/spf13/viper" + "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "github.com/databacker/api/go/api" @@ -252,8 +253,22 @@ func dumpCmd(passedExecs execs, cmdConfig *cmdConfiguration) (*cobra.Command, er if err := executor.Timer(timerOpts, func() error { // start a new span for the dump, should not be a child of the startup one tracerCtx, dumpSpan := tracer.Start(ctx, "run") - defer dumpSpan.End() uid := uuid.New() + bytes := int64(0) + exitCode := 0 + backupStatus := "ok" + dumpSpan.SetAttributes(attribute.String("backup.run_id", uid.String())) + defer func() { + attrs := []attribute.KeyValue{ + attribute.String("backup.status", backupStatus), + attribute.Int("backup.exit_code", exitCode), + } + if bytes > 0 { + attrs = append(attrs, attribute.Int64("backup.bytes", bytes)) + } + dumpSpan.SetAttributes(attrs...) + dumpSpan.End() + }() dumpOpts := core.DumpOptions{ Targets: targets, Safechars: safechars, @@ -274,13 +289,18 @@ func dumpCmd(passedExecs execs, cmdConfig *cmdConfiguration) (*cobra.Command, er FilenamePattern: filenamePattern, Parallelism: parallel, } - _, err := executor.Dump(tracerCtx, dumpOpts) + results, err := executor.Dump(tracerCtx, dumpOpts) if err != nil { + exitCode = 1 + backupStatus = "error" dumpSpan.SetStatus(codes.Error, fmt.Sprintf("error running dump: %v", err)) return fmt.Errorf("error running dump: %w", err) } + bytes = results.Bytes if retention != "" { if err := executor.Prune(tracerCtx, core.PruneOptions{Targets: targets, Retention: retention, Run: uid}); err != nil { + exitCode = 1 + backupStatus = "error" dumpSpan.SetStatus(codes.Error, fmt.Sprintf("error running prune: %v", err)) return fmt.Errorf("error running prune: %w", err) } diff --git a/pkg/core/dump.go b/pkg/core/dump.go index 00347a4..fa614ac 100644 --- a/pkg/core/dump.go +++ b/pkg/core/dump.go @@ -136,27 +136,42 @@ func (e *Executor) Dump(ctx context.Context, opts DumpOptions) (DumpResults, err return results, fmt.Errorf("failed to open output file '%s': %v", outFile, err) } defer func() { _ = f.Close() }() - cw, err := compressor.Compress(f) + compressedWriter, err := compressor.Compress(f) if err != nil { tarSpan.SetStatus(codes.Error, err.Error()) tarSpan.End() return results, fmt.Errorf("failed to create compressor: %v", err) } + archiveWriter := compressedWriter if encryptor != nil { - cw, err = encryptor.Encrypt(cw) + archiveWriter, err = encryptor.Encrypt(compressedWriter) if err != nil { tarSpan.SetStatus(codes.Error, err.Error()) tarSpan.End() return results, fmt.Errorf("failed to create encryptor: %v", err) } } - if err := archive.Tar(workdir, cw); err != nil { + if err := archive.Tar(workdir, archiveWriter); err != nil { tarSpan.SetStatus(codes.Error, err.Error()) tarSpan.End() return results, fmt.Errorf("error creating the compressed archive: %v", err) } - // we need to close it explicitly before moving ahead - defer func() { _ = f.Close() }() + if err := archiveWriter.Close(); err != nil { + tarSpan.SetStatus(codes.Error, err.Error()) + tarSpan.End() + return results, fmt.Errorf("failed to close archive writer: %v", err) + } + if archiveWriter != compressedWriter { + if err := compressedWriter.Close(); err != nil { + tarSpan.SetStatus(codes.Error, err.Error()) + tarSpan.End() + return results, fmt.Errorf("failed to close compressor: %v", err) + } + } + if info, err := os.Stat(outFile); err == nil { + results.Bytes = info.Size() + tarSpan.SetAttributes(attribute.Int64("bytes", results.Bytes)) + } tarSpan.SetStatus(codes.Ok, "completed") tarSpan.End() diff --git a/pkg/core/dumpresults.go b/pkg/core/dumpresults.go index b785663..63ac3f5 100644 --- a/pkg/core/dumpresults.go +++ b/pkg/core/dumpresults.go @@ -10,13 +10,14 @@ type DumpResults struct { Timestamp string DumpStart time.Time DumpEnd time.Time + Bytes int64 Uploads []UploadResult } // UploadResult lists results of an individual upload type UploadResult struct { - Target string + Target string Filename string - Start time.Time - End time.Time + Start time.Time + End time.Time }