recover.go 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. // Package recover provides recovery for specific routes or for the whole app via middleware. See _examples/recover
  2. package recover
  3. import (
  4. "fmt"
  5. "net/http/httputil"
  6. "runtime"
  7. "runtime/debug"
  8. "strings"
  9. "github.com/kataras/iris/v12/context"
  10. )
  11. func init() {
  12. context.SetHandlerName("iris/middleware/recover.*", "iris.recover")
  13. }
  14. func getRequestLogs(ctx *context.Context) string {
  15. rawReq, _ := httputil.DumpRequest(ctx.Request(), false)
  16. return string(rawReq)
  17. }
  18. // New returns a new recover middleware,
  19. // it recovers from panics and logs
  20. // the panic message to the application's logger "Warn" level.
  21. func New() context.Handler {
  22. return func(ctx *context.Context) {
  23. defer func() {
  24. if err := recover(); err != nil {
  25. if ctx.IsStopped() { // handled by other middleware.
  26. return
  27. }
  28. var callers []string
  29. for i := 1; ; i++ {
  30. _, file, line, got := runtime.Caller(i)
  31. if !got {
  32. break
  33. }
  34. callers = append(callers, fmt.Sprintf("%s:%d", file, line))
  35. }
  36. // when stack finishes
  37. logMessage := fmt.Sprintf("Recovered from a route's Handler('%s')\n", ctx.HandlerName())
  38. logMessage += fmt.Sprint(getRequestLogs(ctx))
  39. logMessage += fmt.Sprintf("%s\n", err)
  40. logMessage += fmt.Sprintf("%s\n", strings.Join(callers, "\n"))
  41. ctx.Application().Logger().Warn(logMessage)
  42. // get the list of registered handlers and the
  43. // handler which panic derived from.
  44. handlers := ctx.Handlers()
  45. handlersFileLines := make([]string, 0, len(handlers))
  46. currentHandlerIndex := ctx.HandlerIndex(-1)
  47. currentHandlerFileLine := "???"
  48. for i, h := range ctx.Handlers() {
  49. file, line := context.HandlerFileLine(h)
  50. fileline := fmt.Sprintf("%s:%d", file, line)
  51. handlersFileLines = append(handlersFileLines, fileline)
  52. if i == currentHandlerIndex {
  53. currentHandlerFileLine = fileline
  54. }
  55. }
  56. // see accesslog.wasRecovered too.
  57. ctx.StopWithPlainError(500, &context.ErrPanicRecovery{
  58. Cause: err,
  59. Callers: callers,
  60. Stack: debug.Stack(),
  61. RegisteredHandlers: handlersFileLines,
  62. CurrentHandler: currentHandlerFileLine,
  63. })
  64. }
  65. }()
  66. ctx.Next()
  67. }
  68. }