error.go 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. package middleware
  2. import (
  3. "github.com/sirupsen/logrus"
  4. "net"
  5. "net/http"
  6. "net/http/httputil"
  7. "os"
  8. "runtime/debug"
  9. "strings"
  10. "github.com/gin-gonic/gin"
  11. "go.uber.org/zap"
  12. )
  13. // GinRecovery recover掉项目可能出现的panic,并使用zap记录相关日志
  14. func GinRecovery(stack bool) gin.HandlerFunc {
  15. return func(c *gin.Context) {
  16. defer func() {
  17. if err := recover(); err != nil {
  18. // Check for a broken connection, as it is not really a
  19. // condition that warrants a panic stack trace.
  20. var brokenPipe bool
  21. if ne, ok := err.(*net.OpError); ok {
  22. if se, ok := ne.Err.(*os.SyscallError); ok {
  23. if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
  24. brokenPipe = true
  25. }
  26. }
  27. }
  28. httpRequest, _ := httputil.DumpRequest(c.Request, false)
  29. if brokenPipe {
  30. logrus.Error(c.Request.URL.Path,
  31. zap.Any("error", err),
  32. zap.String("request", string(httpRequest)),
  33. )
  34. // If the connection is dead, we can't write a status to it.
  35. _ = c.Error(err.(error)) // nolint: errcheck
  36. c.Abort()
  37. return
  38. }
  39. if stack {
  40. logrus.Error("[Recovery from panic]",
  41. zap.Any("error", err),
  42. zap.String("request", string(httpRequest)),
  43. zap.String("stack", string(debug.Stack())),
  44. )
  45. } else {
  46. logrus.Error("[Recovery from panic]",
  47. zap.Any("error", err),
  48. zap.String("request", string(httpRequest)),
  49. )
  50. }
  51. c.AbortWithStatus(http.StatusInternalServerError)
  52. }
  53. }()
  54. c.Next()
  55. }
  56. }