Files
wk-backend/internal/middleware/debug_http_log.go
2026-04-03 14:24:29 +08:00

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)
}