feat: add debug log stream support
This commit is contained in:
89
internal/middleware/debug_http_log.go
Normal file
89
internal/middleware/debug_http_log.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"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 isDebugLogRoute(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/ws/logs")
|
||||
}
|
||||
Reference in New Issue
Block a user