operation.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. package middleware
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "github.com/sirupsen/logrus"
  6. "io"
  7. "net/http"
  8. "net/url"
  9. "strconv"
  10. "strings"
  11. "sync"
  12. "time"
  13. "lc-base-frame/utils"
  14. "github.com/gin-gonic/gin"
  15. "go.uber.org/zap"
  16. "lc-base-frame/model/system"
  17. "lc-base-frame/service"
  18. )
  19. var operationRecordService = service.ServiceGroupApp.SystemServiceGroup.OperationRecordService
  20. var respPool sync.Pool
  21. func init() {
  22. respPool.New = func() interface{} {
  23. return make([]byte, 1024)
  24. }
  25. }
  26. func OperationRecord() gin.HandlerFunc {
  27. return func(c *gin.Context) {
  28. var body []byte
  29. var userId int
  30. if c.Request.Method != http.MethodGet {
  31. var err error
  32. body, err = io.ReadAll(c.Request.Body)
  33. if err != nil {
  34. logrus.Error("read body from request error:", zap.Error(err))
  35. } else {
  36. c.Request.Body = io.NopCloser(bytes.NewBuffer(body))
  37. }
  38. } else {
  39. query := c.Request.URL.RawQuery
  40. query, _ = url.QueryUnescape(query)
  41. split := strings.Split(query, "&")
  42. m := make(map[string]string)
  43. for _, v := range split {
  44. kv := strings.Split(v, "=")
  45. if len(kv) == 2 {
  46. m[kv[0]] = kv[1]
  47. }
  48. }
  49. body, _ = json.Marshal(&m)
  50. }
  51. claims, _ := utils.GetClaims(c)
  52. if claims.BaseClaims.ID != 0 {
  53. userId = int(claims.BaseClaims.ID)
  54. } else {
  55. id, err := strconv.Atoi(c.Request.Header.Get("x-user-id"))
  56. if err != nil {
  57. userId = 0
  58. }
  59. userId = id
  60. }
  61. record := system.SysOperationRecord{
  62. Ip: c.ClientIP(),
  63. Method: c.Request.Method,
  64. Path: c.Request.URL.Path,
  65. Agent: c.Request.UserAgent(),
  66. Body: string(body),
  67. UserID: userId,
  68. }
  69. // 上传文件时候 中间件日志进行裁断操作
  70. if strings.Contains(c.GetHeader("Content-Type"), "multipart/form-data") {
  71. if len(record.Body) > 1024 {
  72. // 截断
  73. newBody := respPool.Get().([]byte)
  74. copy(newBody, record.Body)
  75. record.Body = string(newBody)
  76. defer respPool.Put(newBody[:0])
  77. }
  78. }
  79. writer := responseBodyWriter{
  80. ResponseWriter: c.Writer,
  81. body: &bytes.Buffer{},
  82. }
  83. c.Writer = writer
  84. now := time.Now()
  85. c.Next()
  86. latency := time.Since(now)
  87. record.ErrorMessage = c.Errors.ByType(gin.ErrorTypePrivate).String()
  88. record.Status = c.Writer.Status()
  89. record.Latency = latency
  90. record.Resp = writer.body.String()
  91. if strings.Contains(c.Writer.Header().Get("Pragma"), "public") ||
  92. strings.Contains(c.Writer.Header().Get("Expires"), "0") ||
  93. strings.Contains(c.Writer.Header().Get("Cache-Control"), "must-revalidate, post-check=0, pre-check=0") ||
  94. strings.Contains(c.Writer.Header().Get("Content-Type"), "application/force-download") ||
  95. strings.Contains(c.Writer.Header().Get("Content-Type"), "application/octet-stream") ||
  96. strings.Contains(c.Writer.Header().Get("Content-Type"), "application/vnd.ms-excel") ||
  97. strings.Contains(c.Writer.Header().Get("Content-Type"), "application/download") ||
  98. strings.Contains(c.Writer.Header().Get("Content-Disposition"), "attachment") ||
  99. strings.Contains(c.Writer.Header().Get("Content-Transfer-Encoding"), "binary") {
  100. if len(record.Resp) > 1024 {
  101. // 截断
  102. newBody := respPool.Get().([]byte)
  103. copy(newBody, record.Resp)
  104. record.Resp = string(newBody)
  105. defer respPool.Put(newBody[:0])
  106. }
  107. }
  108. if err := operationRecordService.CreateSysOperationRecord(record); err != nil {
  109. logrus.Error("create operation record error:", zap.Error(err))
  110. }
  111. }
  112. }
  113. type responseBodyWriter struct {
  114. gin.ResponseWriter
  115. body *bytes.Buffer
  116. }
  117. func (r responseBodyWriter) Write(b []byte) (int, error) {
  118. r.body.Write(b)
  119. return r.ResponseWriter.Write(b)
  120. }