package middleware import ( "bytes" "encoding/json" "strings" "github.com/gin-gonic/gin" ) 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 = 32768 } 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) string { return redactJSONLimit(raw, 32768) } func redactJSONLimit(raw []byte, limit int) string { if len(raw) == 0 { return "" } if limit <= 0 { limit = 32768 } if len(raw) > limit { raw = raw[:limit] } var value any if json.Unmarshal(raw, &value) != nil { return string(raw) } var clean func(any) clean = func(current any) { switch v := current.(type) { case map[string]any: for key, item := range v { lower := strings.ToLower(key) if strings.Contains(lower, "password") || strings.Contains(lower, "token") || strings.Contains(lower, "secret") { v[key] = "******" } else { clean(item) } } case []any: for _, item := range v { clean(item) } } } clean(value) encoded, _ := json.Marshal(value) 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/") }