db_log.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. package middleware
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "github.com/gin-gonic/gin"
  7. "github.com/go-nunu/nunu-layout-advanced/internal/model"
  8. "github.com/go-nunu/nunu-layout-advanced/internal/service"
  9. "github.com/go-nunu/nunu-layout-advanced/pkg/jwt"
  10. "io"
  11. "net/http"
  12. "strconv"
  13. )
  14. // OperationLogMiddleware 记录操作日志到数据库
  15. func OperationLogMiddleware(logService service.LogService) gin.HandlerFunc {
  16. return func(c *gin.Context) {
  17. var requestBody []byte
  18. if c.Request.Body != nil {
  19. requestBody, _ = io.ReadAll(c.Request.Body)
  20. c.Request.Body = io.NopCloser(bytes.NewBuffer(requestBody))
  21. }
  22. blw := &bodyLogWriter{
  23. body: bytes.NewBufferString(""),
  24. ResponseWriter: c.Writer,
  25. }
  26. c.Writer = blw
  27. c.Next()
  28. go func() {
  29. ctxCopy := c.Copy()
  30. statusCode := ctxCopy.Writer.Status()
  31. var userID uint
  32. if claims, exists := ctxCopy.Get("claims"); exists {
  33. if customClaims, ok := claims.(*jwt.MyCustomClaims); ok {
  34. userID = customClaims.UserId
  35. }
  36. }
  37. // 如果JWT和Query中都没有,尝试从请求体中获取
  38. if userID == 0 && len(requestBody) > 0 {
  39. var bodyData map[string]interface{}
  40. if err := json.Unmarshal(requestBody, &bodyData); err == nil {
  41. if uidVal, ok := bodyData["uid"]; ok {
  42. if uidFloat, ok := uidVal.(float64); ok {
  43. userID = uint(uidFloat)
  44. }
  45. }
  46. }
  47. }
  48. if userID == 0 {
  49. if uidStr := ctxCopy.Query("uid"); uidStr != "" {
  50. if uid, err := strconv.ParseUint(uidStr, 10, 64); err == nil {
  51. userID = uint(uid)
  52. }
  53. }
  54. }
  55. if userID == 0 && (ctxCopy.Request.URL.Path == "/api/v1/login" || ctxCopy.Request.URL.Path == "/api/v1/user/login") && statusCode == http.StatusOK {
  56. var response struct {
  57. Data struct {
  58. ID uint `json:"id"`
  59. } `json:"data"`
  60. }
  61. if err := json.Unmarshal(blw.body.Bytes(), &response); err == nil {
  62. userID = response.Data.ID
  63. }
  64. }
  65. var traceID string
  66. if id, ok := ctxCopy.Get(TraceIDKey); ok {
  67. traceID, _ = id.(string)
  68. }
  69. var requestBodyForLog interface{}
  70. if len(requestBody) > 0 {
  71. if err := json.Unmarshal(requestBody, &requestBodyForLog); err != nil {
  72. // 如果解析失败, 则按原始字符串存储
  73. requestBodyForLog = string(requestBody)
  74. }
  75. }
  76. var responseBodyForLog interface{}
  77. responseBodyBytes := blw.body.Bytes()
  78. if len(responseBodyBytes) > 0 {
  79. if err := json.Unmarshal(responseBodyBytes, &responseBodyForLog); err != nil {
  80. // 如果解析失败, 则按原始字符串存储
  81. responseBodyForLog = blw.body.String()
  82. }
  83. }
  84. // 只记录请求体到 ExtraData
  85. extraData, _ := json.Marshal(requestBodyForLog)
  86. logEntry := &model.Log{
  87. TraceId: traceID,
  88. Uid: int64(userID),
  89. RequestIp: ctxCopy.ClientIP(),
  90. Api: ctxCopy.Request.RequestURI,
  91. Message: fmt.Sprintf("[%s] %s - %d", ctxCopy.Request.Method, ctxCopy.Request.URL.Path, statusCode),
  92. ExtraData: extraData,
  93. UserAgent: ctxCopy.Request.UserAgent(),
  94. StatusCode: statusCode,
  95. }
  96. _ = logService.AddLog(ctxCopy, logEntry)
  97. }()
  98. }
  99. }