package middleware import ( "bytes" "encoding/json" "io" "time" "github.com/perfect-panel/server/pkg/logger" "github.com/perfect-panel/server/pkg/xerr" "github.com/pkg/errors" "github.com/gin-gonic/gin" "github.com/perfect-panel/server/internal/svc" ) type responseBodyWriter struct { gin.ResponseWriter body *bytes.Buffer } func (r responseBodyWriter) Write(b []byte) (int, error) { r.body.Write(b) return r.ResponseWriter.Write(b) } func LoggerMiddleware(svc *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { // get response body w := &responseBodyWriter{body: &bytes.Buffer{}, ResponseWriter: c.Writer} c.Writer = w // get request body var requestBody []byte if c.Request.Body != nil { // c.Request.Body It can only be read once, and after reading, it needs to be reassigned to c.Request Body requestBody, _ = io.ReadAll(c.Request.Body) // After reading, reassign c.Request Body , For subsequent operations c.Request.Body = io.NopCloser(bytes.NewBuffer(requestBody)) } // start time start := time.Now() c.Next() // Start recording logs cost := time.Since(start) responseStatus := c.Writer.Status() logs := []logger.LogField{ { Key: "status", Value: responseStatus, }, { Key: "request", Value: c.Request.Method + " " + c.Request.URL.String(), }, { Key: "query", Value: c.Request.URL.RawQuery, }, { Key: "ip", Value: c.ClientIP(), }, { Key: "user-agent", Value: c.Request.UserAgent(), }, } if c.Errors.Last() != nil { var e *xerr.CodeError var errMessage string if errors.As(c.Errors.Last().Err, &e) { errMessage = e.GetErrMsg() } else { errMessage = c.Errors.Last().Error() } logs = append(logs, logger.Field("error", errMessage)) } if c.Request.Method == "POST" || c.Request.Method == "PUT" || c.Request.Method == "DELETE" { // request content logs = append(logs, logger.Field("request_body", string(maskSensitiveFields(requestBody, []string{"password", "old_password", "new_password"})))) // response content logs = append(logs, logger.Field("response_body", w.body.String())) } logs = append(logs, logger.Field("duration", cost)) if responseStatus >= 500 && responseStatus <= 599 { logger.WithContext(c.Request.Context()).Errorw("HTTP Error", logs...) } else { logger.WithContext(c.Request.Context()).Infow("HTTP Request", logs...) } } } func maskSensitiveFields(data []byte, fieldsToMask []string) []byte { var jsonData map[string]interface{} if err := json.Unmarshal(data, &jsonData); err != nil { return data } for _, field := range fieldsToMask { if _, exists := jsonData[field]; exists { jsonData[field] = "***" // use *** to mask sensitive fields } } maskedData, err := json.Marshal(jsonData) if err != nil { return data } return maskedData }