claude-code-proxy/proxy/internal/middleware/logging.go
Seif Ghazi 4675fee4a3
route cleanup
working

Working version
2025-08-04 21:57:44 -04:00

96 lines
2.2 KiB
Go

package middleware
import (
"bytes"
"context"
"fmt"
"io"
"log"
"net/http"
"time"
"github.com/seifghazi/claude-code-monitor/internal/model"
)
func Logging(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
// For POST requests with body, read and store the bytes
var bodyBytes []byte
if r.Body != nil && (r.Method == "POST" || r.Method == "PUT" || r.Method == "PATCH") {
var err error
bodyBytes, err = io.ReadAll(r.Body)
if err != nil {
log.Printf("❌ Error reading request body: %v", err)
http.Error(w, "Error reading request body", http.StatusBadRequest)
return
}
r.Body.Close()
r.Body = io.NopCloser(bytes.NewReader(bodyBytes))
// Store raw bytes in context for handler to use
ctx := context.WithValue(r.Context(), model.BodyBytesKey, bodyBytes)
r = r.WithContext(ctx)
}
wrapped := &responseWriter{ResponseWriter: w, statusCode: http.StatusOK}
next.ServeHTTP(wrapped, r)
duration := time.Since(start)
statusColor := getStatusColor(wrapped.statusCode)
log.Printf("%s %s %s%d%s %s (%s)",
r.Method,
r.URL.Path,
statusColor,
wrapped.statusCode,
colorReset,
http.StatusText(wrapped.statusCode),
formatDuration(duration))
})
}
type responseWriter struct {
http.ResponseWriter
statusCode int
}
func (rw *responseWriter) WriteHeader(code int) {
rw.statusCode = code
rw.ResponseWriter.WriteHeader(code)
}
// ANSI color codes
const (
colorReset = "\033[0m"
colorGreen = "\033[32m"
colorYellow = "\033[33m"
colorRed = "\033[31m"
colorBlue = "\033[34m"
colorCyan = "\033[36m"
)
func getStatusColor(status int) string {
switch {
case status >= 200 && status < 300:
return colorGreen
case status >= 300 && status < 400:
return colorBlue
case status >= 400 && status < 500:
return colorYellow
case status >= 500:
return colorRed
default:
return colorReset
}
}
func formatDuration(d time.Duration) string {
if d < time.Millisecond {
return fmt.Sprintf("%dµs", d.Microseconds())
} else if d < time.Second {
return fmt.Sprintf("%dms", d.Milliseconds())
}
return fmt.Sprintf("%.2fs", d.Seconds())
}