111 lines
2.8 KiB
Go
111 lines
2.8 KiB
Go
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
|
||
}
|