| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970 |
- package errors
- import (
- "fmt"
- "runtime"
- )
- // Panic represents a panic that occurred, captured by a recovery.
- type Panic struct {
- Error interface{}
- Stack string
- }
- // PanicHandler is a func that receives a Panic and returns a bool representing whether or not
- // the panic should recover or not.
- type PanicHandler = func(p Panic) bool
- var (
- enabled = false
- dispatcher = make(chan Panic)
- )
- // SetPanicHandler sets the handler that is executed when
- func SetPanicHandler(handler PanicHandler) error {
- if enabled {
- return fmt.Errorf("Panic Handler has already been set")
- }
- enabled = true
- // Setup a go routine which receives via the panic channel, passes
- // resulting Panic to the handler passed.
- go func() {
- for {
- p := <-dispatcher
- // If we do not wish to recover, panic using same error
- if !handler(p) {
- panic(p.Error)
- }
- }
- }()
- return nil
- }
- // HandlePanic should be executed in a deferred method (or deferred directly). It will
- // capture any panics that occur in the goroutine it exists, and report to the registered
- // global panic handler.
- func HandlePanic() {
- // Do not handle/recover if disabled
- if !enabled {
- return
- }
- if err := recover(); err != nil {
- dispatch(err)
- }
- }
- // generate stacktrace, dispatch the panic via channel
- func dispatch(err interface{}) {
- stack := make([]byte, 1024*8)
- stack = stack[:runtime.Stack(stack, false)]
- dispatcher <- Panic{
- Error: err,
- Stack: string(stack),
- }
- }
|