cmd: make stats be printed on non-zero exit code

This also rationalises the exit sequence so that dumping
goroutines/open files happens regardless of exit error state.

See: https://forum.rclone.org/t/transfer-stats-on-non-0-exit/14211
This commit is contained in:
Nick Craig-Wood 2020-02-07 10:34:55 +00:00
parent a54210a2e4
commit 5c869d5bd3

View file

@ -226,7 +226,7 @@ func ShowStats() bool {
// Run the function with stats and retries if required // Run the function with stats and retries if required
func Run(Retry bool, showStats bool, cmd *cobra.Command, f func() error) { func Run(Retry bool, showStats bool, cmd *cobra.Command, f func() error) {
var err error var cmdErr error
stopStats := func() {} stopStats := func() {}
if !showStats && ShowStats() { if !showStats && ShowStats() {
showStats = true showStats = true
@ -238,11 +238,11 @@ func Run(Retry bool, showStats bool, cmd *cobra.Command, f func() error) {
} }
SigInfoHandler() SigInfoHandler()
for try := 1; try <= *retries; try++ { for try := 1; try <= *retries; try++ {
err = f() cmdErr = f()
err = fs.CountError(err) cmdErr = fs.CountError(cmdErr)
lastErr := accounting.GlobalStats().GetLastError() lastErr := accounting.GlobalStats().GetLastError()
if err == nil { if cmdErr == nil {
err = lastErr cmdErr = lastErr
} }
if !Retry || !accounting.GlobalStats().Errored() { if !Retry || !accounting.GlobalStats().Errored() {
if try > 1 { if try > 1 {
@ -278,15 +278,6 @@ func Run(Retry bool, showStats bool, cmd *cobra.Command, f func() error) {
} }
} }
stopStats() stopStats()
if err != nil {
nerrs := accounting.GlobalStats().GetErrors()
if nerrs <= 1 {
log.Printf("Failed to %s: %v", cmd.Name(), err)
} else {
log.Printf("Failed to %s with %d errors: last error was: %v", cmd.Name(), nerrs, err)
}
resolveExitCode(err)
}
if showStats && (accounting.GlobalStats().Errored() || *statsInterval > 0) { if showStats && (accounting.GlobalStats().Errored() || *statsInterval > 0) {
accounting.GlobalStats().Log() accounting.GlobalStats().Log()
} }
@ -294,7 +285,7 @@ func Run(Retry bool, showStats bool, cmd *cobra.Command, f func() error) {
// dump all running go-routines // dump all running go-routines
if fs.Config.Dump&fs.DumpGoRoutines != 0 { if fs.Config.Dump&fs.DumpGoRoutines != 0 {
err = pprof.Lookup("goroutine").WriteTo(os.Stdout, 1) err := pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
if err != nil { if err != nil {
fs.Errorf(nil, "Failed to dump goroutines: %v", err) fs.Errorf(nil, "Failed to dump goroutines: %v", err)
} }
@ -305,15 +296,22 @@ func Run(Retry bool, showStats bool, cmd *cobra.Command, f func() error) {
c := exec.Command("lsof", "-p", strconv.Itoa(os.Getpid())) c := exec.Command("lsof", "-p", strconv.Itoa(os.Getpid()))
c.Stdout = os.Stdout c.Stdout = os.Stdout
c.Stderr = os.Stderr c.Stderr = os.Stderr
err = c.Run() err := c.Run()
if err != nil { if err != nil {
fs.Errorf(nil, "Failed to list open files: %v", err) fs.Errorf(nil, "Failed to list open files: %v", err)
} }
} }
if accounting.GlobalStats().Errored() { // Log the final error message and exit
resolveExitCode(accounting.GlobalStats().GetLastError()) if cmdErr != nil {
nerrs := accounting.GlobalStats().GetErrors()
if nerrs <= 1 {
log.Printf("Failed to %s: %v", cmd.Name(), cmdErr)
} else {
log.Printf("Failed to %s with %d errors: last error was: %v", cmd.Name(), nerrs, cmdErr)
}
} }
resolveExitCode(cmdErr)
} }
// CheckArgs checks there are enough arguments and prints a message if not // CheckArgs checks there are enough arguments and prints a message if not