104 lines
2.4 KiB
Go
104 lines
2.4 KiB
Go
package middleware
|
|
|
|
import (
|
|
"bytes"
|
|
"ckwk/internal/conf"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"ckwk/pkg/log"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"go.uber.org/zap/zapcore"
|
|
)
|
|
|
|
const maxDebugBodySize = 4 * 1024
|
|
|
|
type debugBodyWriter struct {
|
|
gin.ResponseWriter
|
|
body bytes.Buffer
|
|
}
|
|
|
|
func (w *debugBodyWriter) Write(data []byte) (int, error) {
|
|
w.body.Write(data)
|
|
return w.ResponseWriter.Write(data)
|
|
}
|
|
|
|
func (w *debugBodyWriter) WriteString(data string) (int, error) {
|
|
w.body.WriteString(data)
|
|
return w.ResponseWriter.WriteString(data)
|
|
}
|
|
|
|
func DebugHTTPLog() gin.HandlerFunc {
|
|
return func(ctx *gin.Context) {
|
|
if !conf.IsRuntimeDebugEnabled() {
|
|
ctx.Next()
|
|
return
|
|
}
|
|
|
|
if !shouldCaptureBackendRoute(ctx.Request.URL.Path) {
|
|
ctx.Next()
|
|
return
|
|
}
|
|
|
|
startAt := time.Now()
|
|
requestBody := readRequestBody(ctx.Request)
|
|
|
|
writer := &debugBodyWriter{ResponseWriter: ctx.Writer}
|
|
ctx.Writer = writer
|
|
ctx.Next()
|
|
|
|
fields := map[string]any{
|
|
"method": ctx.Request.Method,
|
|
"path": ctx.Request.URL.Path,
|
|
"rawQuery": ctx.Request.URL.RawQuery,
|
|
"status": writer.Status(),
|
|
"durationMs": time.Since(startAt).Milliseconds(),
|
|
"clientIP": ctx.ClientIP(),
|
|
"requestHeader": log.SanitizeHeaders(ctx.Request.Header),
|
|
"requestBody": truncate(log.SanitizeBody(ctx.ContentType(), requestBody), maxDebugBodySize),
|
|
"responseHeader": log.SanitizeHeaders(http.Header(writer.Header().Clone())),
|
|
"responseBody": truncate(log.SanitizeBody(writer.Header().Get("Content-Type"), writer.body.String()), maxDebugBodySize),
|
|
"responseSize": writer.Size(),
|
|
"handler": ctx.HandlerName(),
|
|
"abortWithErrors": ctx.Errors.ByType(gin.ErrorTypeAny).String(),
|
|
}
|
|
|
|
log.Capture(zapcore.DebugLevel, "http", "incoming exchange", fields)
|
|
}
|
|
}
|
|
|
|
func readRequestBody(r *http.Request) string {
|
|
if r == nil || r.Body == nil {
|
|
return ""
|
|
}
|
|
|
|
body, err := io.ReadAll(r.Body)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
r.Body = io.NopCloser(bytes.NewBuffer(body))
|
|
return string(body)
|
|
}
|
|
|
|
func truncate(value string, limit int) string {
|
|
if len(value) <= limit {
|
|
return value
|
|
}
|
|
return value[:limit] + "...(truncated)"
|
|
}
|
|
|
|
func isDebugLogRoute(path string) bool {
|
|
return strings.HasPrefix(path, "/api/debug/")
|
|
}
|
|
|
|
func shouldCaptureBackendRoute(path string) bool {
|
|
if !strings.HasPrefix(path, "/api/") {
|
|
return false
|
|
}
|
|
|
|
return !isDebugLogRoute(path)
|
|
}
|