log.go 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. package middlewares
  2. import (
  3. "github.com/gin-gonic/gin"
  4. "go.uber.org/zap"
  5. "net"
  6. "net/http"
  7. "net/http/httputil"
  8. "os"
  9. "runtime/debug"
  10. "strings"
  11. "time"
  12. )
  13. func GinLogger(logger *zap.Logger) gin.HandlerFunc {
  14. return func(c *gin.Context) {
  15. timeFormat := "ISO8601"
  16. utc := true
  17. start := time.Now()
  18. // some evil middlewares modify this values
  19. path := c.Request.URL.Path
  20. query := c.Request.URL.RawQuery
  21. c.Next()
  22. end := time.Now()
  23. latency := end.Sub(start)
  24. if utc {
  25. end = end.UTC()
  26. }
  27. if len(c.Errors) > 0 {
  28. // Append error field if this is an erroneous request.
  29. for _, e := range c.Errors.Errors() {
  30. logger.Error(e)
  31. }
  32. } else {
  33. logger.Info(path,
  34. zap.Int("status", c.Writer.Status()),
  35. zap.String("method", c.Request.Method),
  36. zap.String("path", path),
  37. zap.String("query", query),
  38. zap.String("ip", c.ClientIP()),
  39. zap.String("user-agent", c.Request.UserAgent()),
  40. zap.String("time", end.Format(timeFormat)),
  41. zap.Duration("latency", latency),
  42. )
  43. }
  44. }
  45. }
  46. func RecoveryWithZap(logger *zap.Logger, stack bool) gin.HandlerFunc {
  47. return func(c *gin.Context) {
  48. defer func() {
  49. if err := recover(); err != nil {
  50. // Check for a broken connection, as it is not really a
  51. // condition that warrants a panic stack trace.
  52. var brokenPipe bool
  53. if ne, ok := err.(*net.OpError); ok {
  54. if se, ok := ne.Err.(*os.SyscallError); ok {
  55. if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
  56. brokenPipe = true
  57. }
  58. }
  59. }
  60. httpRequest, _ := httputil.DumpRequest(c.Request, false)
  61. if brokenPipe {
  62. logger.Error(c.Request.URL.Path,
  63. zap.Any("error", err),
  64. zap.String("request", string(httpRequest)),
  65. )
  66. // If the connection is dead, we can't write a status to it.
  67. c.Error(err.(error)) // nolint: errcheck
  68. c.Abort()
  69. return
  70. }
  71. if stack {
  72. logger.Error("[Recovery from panic]",
  73. zap.Time("time", time.Now()),
  74. zap.Any("error", err),
  75. zap.String("request", string(httpRequest)),
  76. zap.String("stack", string(debug.Stack())),
  77. )
  78. } else {
  79. logger.Error("[Recovery from panic]",
  80. zap.Time("time", time.Now()),
  81. zap.Any("error", err),
  82. zap.String("request", string(httpRequest)),
  83. )
  84. }
  85. c.AbortWithStatus(http.StatusInternalServerError)
  86. }
  87. }()
  88. c.Next()
  89. }
  90. }