log.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. package middleware
  2. import (
  3. "bytes"
  4. "io"
  5. "io/ioutil"
  6. "net/http"
  7. "runtime"
  8. "runtime/debug"
  9. "strings"
  10. "time"
  11. "gitee.com/xuyiping_admin/pkg/logger/zaplog"
  12. "github.com/gin-gonic/gin"
  13. "go.uber.org/zap"
  14. )
  15. type responseBodyWriter struct {
  16. gin.ResponseWriter
  17. body *bytes.Buffer
  18. }
  19. type stackErr struct {
  20. Err error
  21. Stack string
  22. }
  23. func (s *stackErr) Error() string {
  24. return s.Err.Error()
  25. }
  26. func (r responseBodyWriter) Write(b []byte) (int, error) {
  27. r.body.Write(b)
  28. return r.ResponseWriter.Write(b)
  29. }
  30. // GinLogger 接管gin框架默认的日志
  31. func GinLogger() gin.HandlerFunc {
  32. return func(c *gin.Context) {
  33. // 获取 response 内容
  34. w := &responseBodyWriter{body: &bytes.Buffer{}, ResponseWriter: c.Writer}
  35. c.Writer = w
  36. var requestBody []byte
  37. if c.Request.Body != nil {
  38. requestBody, _ = ioutil.ReadAll(c.Request.Body)
  39. c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(requestBody))
  40. }
  41. start := time.Now()
  42. c.Next()
  43. cost := time.Since(start)
  44. logFields := []zap.Field{
  45. zap.Int("status", c.Writer.Status()),
  46. zap.String("request", c.Request.Method+" "+c.Request.URL.String()),
  47. zap.String("query", c.Request.URL.RawQuery),
  48. zap.String("ip", c.ClientIP()),
  49. zap.String("user-agent", c.Request.UserAgent()),
  50. zap.String("time", cost.String()),
  51. zap.String("Request body", string(requestBody)),
  52. zap.String("Response body", w.body.String()),
  53. }
  54. if len(c.Errors) > 0 {
  55. logFields = append(logFields, zap.Any("stack", string(debug.Stack())))
  56. zaplog.Error("Http-Access-Error", logFields...)
  57. c.Abort()
  58. } else {
  59. zaplog.Info("Http-Access-Log", logFields...)
  60. }
  61. }
  62. }
  63. // GinRecovery recover掉我的项目可能呈现的panic
  64. func GinRecovery(stack bool) gin.HandlerFunc {
  65. return func(c *gin.Context) {
  66. defer func() {
  67. if err := recover(); err != nil {
  68. /*// Check for a broken connection, as it is not really a
  69. // condition that warrants a panic stack trace.
  70. var brokenPipe bool
  71. if ne, ok := err.(*net.OpError); ok {
  72. if se, ok := ne.Err.(*os.SyscallError); ok {
  73. if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
  74. brokenPipe = true
  75. }
  76. }
  77. }
  78. httpRequest, _ := httputil.DumpRequest(c.Request, false)
  79. if brokenPipe {
  80. zaplog.Error(c.Request.URL.Path,
  81. zap.Any("error", err),
  82. zap.String("request", string(httpRequest)),
  83. )
  84. // If the connection is dead, we can't write a status to it.
  85. c.Error(err.(error)) // nolint: errcheck
  86. c.Abort()
  87. return
  88. }
  89. if stack {
  90. zaplog.Error("[Recovery from panic]",
  91. zap.Any("error", err),
  92. zap.String("request", string(httpRequest)),
  93. zap.String("stack", string(debug.Stack())),
  94. )
  95. } else {
  96. zaplog.Error("[Recovery from panic]",
  97. zap.Any("error", err),
  98. zap.String("request", string(httpRequest)),
  99. )
  100. }*/
  101. defer func() {
  102. if err = recover(); err != nil {
  103. body, _ := ioutil.ReadAll(c.Request.Body)
  104. // 获取 panic 发生的位置
  105. pc, file, line, ok := runtime.Caller(2)
  106. funcName := ""
  107. if ok {
  108. fn := runtime.FuncForPC(pc).Name()
  109. // 去除包路径,只保留函数名
  110. /*funcName = filepath.Base(fn)
  111. file = filepath.Base(file)*/
  112. parts := strings.Split(fn, "/")
  113. if len(parts) > 0 {
  114. lastPart := parts[len(parts)-1]
  115. parts = strings.Split(lastPart, ".")
  116. if len(parts) > 0 {
  117. funcName = parts[len(parts)-1]
  118. }
  119. }
  120. file = strings.TrimPrefix(file, c.Request.Context().Value(gin.ContextKey).(string)+"/") // 尝试去除项目路径前缀(可选)
  121. }
  122. zaplog.Error("cors",
  123. zap.Any("recover", err),
  124. zap.Any("url", c.Request.URL),
  125. zap.Any("file", file),
  126. zap.Any("line", line),
  127. zap.Any("func", funcName),
  128. zap.Any("request", string(body)),
  129. )
  130. c.Request.Body = io.NopCloser(bytes.NewBuffer(body))
  131. }
  132. }()
  133. c.AbortWithStatus(http.StatusInternalServerError)
  134. }
  135. }()
  136. c.Next()
  137. }
  138. }