gin_logger.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. package http_middleware
  2. import (
  3. "bytes"
  4. "fmt"
  5. "git.aionnect.com/aionnect/go-common/utils/date"
  6. "git.aionnect.com/aionnect/go-common/utils/logger"
  7. "github.com/gin-gonic/gin"
  8. "io"
  9. "io/ioutil"
  10. "net/http"
  11. "strings"
  12. )
  13. type bodyBuffer struct {
  14. bytes.Buffer
  15. }
  16. func (b *bodyBuffer) String() string {
  17. str := b.Buffer.String()
  18. return strings.Replace(strings.Replace(str, "\n", "", -1), "\t", "", -1)
  19. }
  20. type reqBodyLogReader struct {
  21. io.ReadCloser
  22. buffer *bodyBuffer
  23. }
  24. func (r *reqBodyLogReader) Read(p []byte) (n int, err error) {
  25. b, err := ioutil.ReadAll(r.ReadCloser)
  26. if nil != err {
  27. return 0, err
  28. }
  29. oldReader := r.ReadCloser
  30. defer func(oldReader io.ReadCloser) {
  31. _ = oldReader.Close()
  32. }(oldReader)
  33. _, _ = r.buffer.Write(b)
  34. r.ReadCloser = ioutil.NopCloser(bytes.NewReader(b))
  35. return r.ReadCloser.Read(p)
  36. }
  37. func (r *reqBodyLogReader) Close() error {
  38. return r.ReadCloser.Close()
  39. }
  40. type respBodyLogWriter struct {
  41. gin.ResponseWriter
  42. buffer *bodyBuffer
  43. }
  44. func (w *respBodyLogWriter) Write(b []byte) (int, error) {
  45. _, _ = w.buffer.Write(b)
  46. return w.ResponseWriter.Write(b)
  47. }
  48. const HTTPRequestStartTime = "httpRequestStartTime"
  49. // 日志中间件
  50. func Logger(hostPrefix string, logger *logger.Logger, notLogged ...string) gin.HandlerFunc {
  51. var skip map[string]struct{}
  52. if length := len(notLogged); length > 0 {
  53. skip = make(map[string]struct{}, length)
  54. for _, path := range notLogged {
  55. skip[path] = struct{}{}
  56. }
  57. }
  58. return func(ctxt *gin.Context) {
  59. start := date.Now()
  60. ctxt.Set(HTTPRequestStartTime, start)
  61. reqReader := &reqBodyLogReader{buffer: &bodyBuffer{Buffer: *bytes.NewBufferString("")}, ReadCloser: ctxt.Request.Body}
  62. ctxt.Request.Body = reqReader
  63. respWriter := &respBodyLogWriter{buffer: &bodyBuffer{Buffer: *bytes.NewBufferString("")}, ResponseWriter: ctxt.Writer}
  64. ctxt.Writer = respWriter
  65. ctxt.Next()
  66. if ctxt.Writer.Status() < http.StatusBadRequest { // httpStatus大于等于400的不应在此记录,而应该panic抛给下面的Recovery方法处理
  67. path := ctxt.Request.URL.Path
  68. if _, ok := skip[path]; !ok {
  69. end := date.Now()
  70. latency := end.Sub(start)
  71. httpStatus := ctxt.Writer.Status()
  72. clientIP := ctxt.ClientIP()
  73. req, fields := splitUri(hostPrefix, ctxt)
  74. comment := ctxt.Errors.ByType(gin.ErrorTypePrivate).String()
  75. logHttpRequest := true
  76. if i, ok := ctxt.Get(IsNoLogHTTPRequest); ok {
  77. if isNoLogHttpRequest, ok := i.(bool); ok && isNoLogHttpRequest {
  78. logHttpRequest = false
  79. }
  80. }
  81. if logHttpRequest {
  82. logger = logger.WithField("requestBody", reqReader.buffer.String())
  83. }
  84. if i, ok := ctxt.Get(IsLogHTTPResponse); ok {
  85. if isLogHttpResponse, ok := i.(bool); ok && isLogHttpResponse {
  86. logger = logger.WithField("responseBody", respWriter.buffer.String())
  87. }
  88. }
  89. logger.
  90. WithCaller(7).
  91. WithField("tag", "API").
  92. WithField("lib", "gin").
  93. WithField("httpStatus", httpStatus).
  94. WithField("latency", fmt.Sprintf("%v", latency)).
  95. WithField("clientIP", clientIP).
  96. WithField("comment", comment).
  97. WithFields(fields).
  98. Info(req)
  99. }
  100. }
  101. }
  102. }