Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I recover from panic, handle the error, then panic again and keep the original stack trace?

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.

like image 607
user7610 Avatar asked Jan 17 '16 18:01

user7610


People also ask

How do you handle panic errors?

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.

What is panic error?

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.

How do you stop panic in Golang?

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.

Does defer run in panic?

Panics happen after a deferred statement is executed. the program ends after the panic statement is run.


2 Answers

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
}
like image 188
user7610 Avatar answered Nov 19 '22 15:11

user7610


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
like image 6
Filip Haglund Avatar answered Nov 19 '22 17:11

Filip Haglund