Is it possible to "rethrow" an error from recover
and keep the original stack trace? The best I know how to do is to panic again, but that does create a new stacktrace.
func do() {
defer func() {
cleanUp()
if x := recover(); x != nil {
handleError()
panic(x)
}
}()
doStuff()
}
My motivation for wanting this is that unless my function exits normally or handleError
runs, my program deadlocks. And unless I preserve the original strack trace, I do not know where it crashed.
A panicking program can recover with the builtin recover() function: The recover function allows a program to manage behavior of a panicking goroutine. Suppose a function G defers a function D that calls recover and a panic occurs in a function on the same goroutine in which G is executing.
panic() is either raised by the program itself when an unexpected error occurs or the programmer throws the exception on purpose for handling particular errors. The panic() function is inbuilt in Go Language and when it is raised, the code prints a panic message, and the function crashes.
Panics have a single recovery mechanism—the recover builtin function. This function allows you to intercept a panic on its way up through the call stack and prevent it from unexpectedly terminating your program. It has strict rules for its use, but can be invaluable in a production application.
Panics happen after a deferred statement is executed. the program ends after the panic statement is run.
The solution is to not call recover
, because then neither rethrowing nor accessing the stack trace is possible. Use a bool flag instead of recover
to check for panic.
https://play.golang.org/p/PKeP9s-3tF
func do() {
panicked := true
defer func() {
cleanUp()
if panicked {
handleError()
}
}()
doStuff()
panicked = false
}
Defered functions higher up in the stack will run on panic, even if they don't call recover()
.
Simply remove the if-statement and the re-panic. Then handle your error, and let the panic continue up the stack.
func do() {
defer handleError()
doStuff()
}
a simple demo:
https://play.golang.org/p/UiRou5MhUR
func a() {
defer func() {
fmt.Println("a")
}()
panic("test")
}
func b() {
defer func() {
fmt.Println("b")
}()
}
func main() {
fmt.Println("Hello, playground")
b()
}
outputs
Hello, playground
b
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With