Keepers 533164744b
standardize panic recovery (#2530)
## Does this PR need a docs update or release note?

- [x]  No 

## Type of change

- [x] 🧹 Tech Debt/Cleanup

## Issue(s)

* #2529

## Test Plan

- [x]  Unit test
2023-02-21 18:36:56 +00:00

55 lines
1.1 KiB
Go

package crash
import (
"context"
"fmt"
"runtime"
"runtime/debug"
"github.com/alcionai/clues"
"github.com/alcionai/corso/src/pkg/logger"
)
// Recovery provides a deferrable func that can be called
// to recover from, and log context about, crashes.
// If an error is returned, then a panic recovery occurred.
//
// Call it as follows:
//
// defer func() {
// if crErr := crash.Recovery(ctx, recover()); crErr != nil {
// err = crErr // err needs to be a named return variable
// }
// }()
func Recovery(ctx context.Context, r any) error {
var (
err error
inFile string
)
if r != nil {
if re, ok := r.(error); ok {
err = re
} else if re, ok := r.(string); ok {
err = clues.New(re)
} else {
err = clues.New(fmt.Sprintf("%v", r))
}
_, file, _, ok := runtime.Caller(2)
if ok {
inFile = " in file: " + file
}
err = clues.Wrap(err, "panic recovery"+inFile).
WithClues(ctx).
With("stacktrace", string(debug.Stack()))
logger.Ctx(ctx).
With("err", err).
Errorw("backup panic", clues.InErr(err).Slice()...)
}
return err
}