recover.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. package middleware
  2. import (
  3. "fmt"
  4. "runtime"
  5. "github.com/labstack/echo"
  6. )
  7. type (
  8. // RecoverConfig defines the config for Recover middleware.
  9. RecoverConfig struct {
  10. // Skipper defines a function to skip middleware.
  11. Skipper Skipper
  12. // Size of the stack to be printed.
  13. // Optional. Default value 4KB.
  14. StackSize int `yaml:"stack_size"`
  15. // DisableStackAll disables formatting stack traces of all other goroutines
  16. // into buffer after the trace for the current goroutine.
  17. // Optional. Default value false.
  18. DisableStackAll bool `yaml:"disable_stack_all"`
  19. // DisablePrintStack disables printing stack trace.
  20. // Optional. Default value as false.
  21. DisablePrintStack bool `yaml:"disable_print_stack"`
  22. }
  23. )
  24. var (
  25. // DefaultRecoverConfig is the default Recover middleware config.
  26. DefaultRecoverConfig = RecoverConfig{
  27. Skipper: DefaultSkipper,
  28. StackSize: 4 << 10, // 4 KB
  29. DisableStackAll: false,
  30. DisablePrintStack: false,
  31. }
  32. )
  33. // Recover returns a middleware which recovers from panics anywhere in the chain
  34. // and handles the control to the centralized HTTPErrorHandler.
  35. func Recover() echo.MiddlewareFunc {
  36. return RecoverWithConfig(DefaultRecoverConfig)
  37. }
  38. // RecoverWithConfig returns a Recover middleware with config.
  39. // See: `Recover()`.
  40. func RecoverWithConfig(config RecoverConfig) echo.MiddlewareFunc {
  41. // Defaults
  42. if config.Skipper == nil {
  43. config.Skipper = DefaultRecoverConfig.Skipper
  44. }
  45. if config.StackSize == 0 {
  46. config.StackSize = DefaultRecoverConfig.StackSize
  47. }
  48. return func(next echo.HandlerFunc) echo.HandlerFunc {
  49. return func(c echo.Context) error {
  50. if config.Skipper(c) {
  51. return next(c)
  52. }
  53. defer func() {
  54. if r := recover(); r != nil {
  55. err, ok := r.(error)
  56. if !ok {
  57. err = fmt.Errorf("%v", r)
  58. }
  59. stack := make([]byte, config.StackSize)
  60. length := runtime.Stack(stack, !config.DisableStackAll)
  61. if !config.DisablePrintStack {
  62. c.Logger().Printf("[PANIC RECOVER] %v %s\n", err, stack[:length])
  63. }
  64. c.Error(err)
  65. }
  66. }()
  67. return next(c)
  68. }
  69. }
  70. }