package middleware import ( "app/commons/core" "app/commons/model/entity" "bytes" "fmt" "github.com/gin-gonic/gin" "io" "strings" "time" ) func UserLogger() gin.HandlerFunc { return func(c *gin.Context) { // 开始时间 start := time.Now() // 记录请求信息 clientIP := c.ClientIP() method := c.Request.Method path := c.Request.URL.Path query := c.Request.URL.RawQuery // 读取请求体 var requestBody []byte var requestBodyStr string contentType := c.Request.Header.Get("Content-Type") // 检查是否为文件上传请求(multipart/form-data) isFileUpload := strings.Contains(contentType, "multipart/form-data") if c.Request.Body != nil { requestBody, _ = io.ReadAll(c.Request.Body) // 读取后重新赋值,因为读取后body会被清空 c.Request.Body = io.NopCloser(bytes.NewBuffer(requestBody)) } // 文件上传请求不记录请求体(避免二进制数据存储问题) if isFileUpload { requestBodyStr = "[file upload]" } else { requestBodyStr = string(requestBody) } // 创建一个自定义的 ResponseWriter 来捕获响应 blw := &bodyLogWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer} c.Writer = blw c.Next() // 在请求结束时记录日志 elapsed := time.Since(start) core.Log.Infof("GIN|%d|%s|IP:%s|%s|URI:%s|", c.Writer.Status(), elapsed.Round(time.Millisecond), c.ClientIP(), c.Request.Method, c.Request.URL.Path) userId := c.GetInt64("userId") userLog := &entity.UserLogs{ UserId: userId, UserAgent: c.Request.UserAgent(), Ip: clientIP, Action: method, Path: path, Query: query, Status: c.Writer.Status(), Request: requestBodyStr, Response: blw.body.String(), Elapsed: fmt.Sprintf("%s", elapsed.Round(time.Millisecond)), } err := core.MainDb().Create(&userLog).Error if err != nil { core.Log.Error(err) } } } // bodyLogWriter 自定义ResponseWriter用于捕获响应体 type bodyLogWriter struct { gin.ResponseWriter body *bytes.Buffer } func (w bodyLogWriter) Write(b []byte) (int, error) { w.body.Write(b) return w.ResponseWriter.Write(b) }