## 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
55 lines
1.1 KiB
Go
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
|
|
}
|