package main
import (
"errors"
"fmt"
"net/http"
"runtime"
)
func main() {
Hello()
// 这里将继续执行
fmt.Println("keep going")
}
func Hello(){
defer HandleCrash()
panic(errors.New("no hello"))
}
// HandleCrash simply catches a crash and logs an error.
// E.g., you can provide one or more additional handlers for something like shutting down go routines gracefully.
func HandleCrash(additionalHandlers ...func(interface{})) {
if r := recover(); r != nil {
logPanic(r)
}
}
// logPanic logs the caller tree when a panic occurs
func logPanic(r interface{}) {
if r == http.ErrAbortHandler {
// honor the http.ErrAbortHandler sentinel panic value:
// ErrAbortHandler is a sentinel panic value to abort a handler.
// While any panic from ServeHTTP aborts the response to the client,
// panicking with ErrAbortHandler also suppresses logging of a stack trace to the server's error log.
return
}
// Same as stdlib http server code. Manually allocate stack trace buffer size
// to prevent excessively large logs
const size = 64 << 10
stacktrace := make([]byte, size)
stacktrace = stacktrace[:runtime.Stack(stacktrace, false)]
if _, ok := r.(string); ok {
fmt.Printf("Observed a panic: %s\n%s", r, stacktrace)
} else {
fmt.Printf("Observed a panic: %#v (%v)\n%s", r, r, stacktrace)
}
}
输出:
- 当出现panic时,recover会恢复程序执行
- 打印出完整的调用栈
Observed a panic: &errors.errorString{s:"no hello"} (no hello)
goroutine 1 [running]:
main.logPanic({0x51a680, 0xc000012c10})
/root/go/src/awesomeProject/test/main.go:58 +0x99
main.HandleCrash({0x0, 0xc0000445f8, 0x26})
/root/go/src/awesomeProject/test/main.go:39 +0x2a
panic({0x51a680, 0xc000012c10})
/usr/local/go/src/runtime/panic.go:1038 +0x215
main.Hello()
/root/go/src/awesomeProject/test/main.go:28 +0x8f
main.main()
/root/go/src/awesomeProject/test/main.go:16 +0x19
keep going
这串代码可以用于web服务的崩溃恢复.