init project
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"furtuna-be/internal/common/logger"
|
||||
)
|
||||
|
||||
func RequestMiddleware() (handler gin.HandlerFunc) {
|
||||
return func(ctx *gin.Context) {
|
||||
start := time.Now()
|
||||
body, _ := readRequestBody(ctx.Request)
|
||||
reqData := getRequestParam(ctx.Request, body)
|
||||
|
||||
// Check if the request contains a file
|
||||
isFileUpload := false
|
||||
contentType := ctx.Request.Header.Get("Content-Type")
|
||||
if strings.HasPrefix(contentType, "multipart/form-data") {
|
||||
isFileUpload = true
|
||||
}
|
||||
|
||||
// Log the request if it's not a file upload
|
||||
if !isFileUpload {
|
||||
logger.ContextLogger(ctx).With(reqData...).Info("Request")
|
||||
}
|
||||
|
||||
rbw := &ResponseBodyWriter{body: bytes.NewBufferString(""), ResponseWriter: ctx.Writer}
|
||||
ctx.Writer = rbw
|
||||
|
||||
stop := time.Now()
|
||||
latency := stop.Sub(start).Milliseconds()
|
||||
|
||||
resData := reqData
|
||||
resData = append(resData, getResponseParam(rbw, latency)...)
|
||||
|
||||
if !isFileUpload {
|
||||
logger.ContextLogger(ctx).With(resData...).Info("Response")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func readRequestBody(req *http.Request) ([]byte, error) {
|
||||
body, err := io.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
logger.ContextLogger(req.Context()).Error(fmt.Sprintf("Error reading body: %v", err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Body = io.NopCloser(bytes.NewBuffer(body))
|
||||
|
||||
return body, nil
|
||||
}
|
||||
|
||||
type ResponseBodyWriter struct {
|
||||
gin.ResponseWriter
|
||||
body *bytes.Buffer
|
||||
}
|
||||
|
||||
func excludeSensitiveFields(data []interface{}) []interface{} {
|
||||
var result []interface{}
|
||||
for _, item := range data {
|
||||
if param, ok := item.(gin.Param); ok {
|
||||
// Exclude Authorization and Password fields
|
||||
if param.Key != "Authorization" && param.Key != "Password" {
|
||||
result = append(result, item)
|
||||
}
|
||||
} else {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func getRequestParam(req *http.Request, body []byte) []zap.Field {
|
||||
var reqData []zap.Field
|
||||
reqData = append(reqData, zap.Any("host", req.Host),
|
||||
zap.Any("uri", req.RequestURI),
|
||||
zap.Any("method", req.Method),
|
||||
zap.Any("path", func() interface{} {
|
||||
p := req.URL.Path
|
||||
if p == "" {
|
||||
p = "/"
|
||||
}
|
||||
|
||||
return p
|
||||
}()),
|
||||
zap.Any("protocol", req.Proto),
|
||||
zap.Any("referer", req.Referer()),
|
||||
zap.Any("user_agent", req.UserAgent()),
|
||||
zap.Any("headers", req.Header),
|
||||
zap.Any("remote_ip", req.RemoteAddr),
|
||||
zap.Any("body", excludeSensitiveFieldsFromBody(body)),
|
||||
)
|
||||
|
||||
return reqData
|
||||
}
|
||||
|
||||
func getResponseParam(rbw *ResponseBodyWriter, latency int64) []zap.Field {
|
||||
var resData []zap.Field
|
||||
resData = append(resData,
|
||||
zap.Any("httpStatus", rbw.Status()),
|
||||
zap.Any("body", rbw.body.String()),
|
||||
zap.Any("latency_human", strconv.FormatInt(latency, 10)),
|
||||
zap.Any("headers", rbw.Header()),
|
||||
)
|
||||
|
||||
return resData
|
||||
}
|
||||
|
||||
func excludeSensitiveFieldsFromBody(body []byte) string {
|
||||
var data map[string]interface{}
|
||||
if err := json.Unmarshal(body, &data); err != nil {
|
||||
return string(body)
|
||||
}
|
||||
|
||||
delete(data, "password")
|
||||
|
||||
result, _ := json.Marshal(data)
|
||||
return string(result)
|
||||
}
|
||||
Reference in New Issue
Block a user