crash.go 1.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
  1. package waitutil
  2. import (
  3. "fmt"
  4. "log"
  5. "runtime"
  6. )
  7. // logPanic logs the caller tree when a panic occurs.
  8. func logPanic(r interface{}) {
  9. callers := getCallers(r)
  10. if _, ok := r.(string); ok {
  11. log.Printf("observed a panic: %s\n%v", r, callers)
  12. } else {
  13. log.Printf("observed a panic: %#v (%v)\n%v", r, r, callers)
  14. }
  15. }
  16. func getCallers(r interface{}) string {
  17. callers := ""
  18. for i := 0; true; i++ {
  19. _, file, line, ok := runtime.Caller(i)
  20. if !ok {
  21. break
  22. }
  23. callers = callers + fmt.Sprintf("%v:%v\n", file, line)
  24. }
  25. return callers
  26. }
  27. // PanicHandlers is a list of functions which will be invoked when a panic happens.
  28. var PanicHandlers = []func(interface{}){logPanic}
  29. // HandleCrash simply catches a crash and logs an error. Meant to be called via
  30. // defer. Additional context-specific handlers can be provided, and will be
  31. // called in case of panic. HandleCrash actually crashes, after calling the
  32. // handlers and logging the panic message.
  33. func HandleCrash(additionalHandlers ...func(interface{})) {
  34. if r := recover(); r != nil {
  35. for _, fn := range PanicHandlers {
  36. fn(r)
  37. }
  38. for _, fn := range additionalHandlers {
  39. fn(r)
  40. }
  41. // Actually proceed to panic.
  42. panic(r)
  43. }
  44. }