package middleware import ( "bytes" "encoding/json" "strings" "github.com/gin-gonic/gin" ) // The global access logger is the single request/response capture point. // OperationAudit consumes these values after the handler returns, avoiding a // second body read/writer wrapper. const ( ctxReqBodyKey = "kra_req_body" ctxRespBufferKey = "kra_resp_buffer" ) type captureWriter struct { gin.ResponseWriter body bytes.Buffer maxBytes int } func (w *captureWriter) Write(data []byte) (int, error) { limit := w.maxBytes if limit <= 0 { limit = 1024 } if w.body.Len() < limit { remaining := limit - w.body.Len() if len(data) > remaining { _, _ = w.body.Write(data[:remaining]) } else { _, _ = w.body.Write(data) } } return w.ResponseWriter.Write(data) } func redactJSON(raw []byte, contentType string, limit int) string { if len(raw) == 0 { return "" } if limit <= 0 { limit = 1024 } text := string(raw) if !strings.Contains(strings.ToLower(contentType), "json") { if len(text) > limit { return "[超出记录长度]" } return text } var value any if json.Unmarshal(raw, &value) != nil { if len(text) > limit { return "[超出记录长度]" } return text } maskOperationBody(value) encoded, _ := json.Marshal(value) if len(encoded) > limit { return "[超出记录长度]" } return string(encoded) } func stringValue(value any) string { text, _ := value.(string); return text } func isBootstrapPath(path string) bool { return strings.HasSuffix(path, "/health") || strings.Contains(path, "/init/") }