package middleware import ( "fmt" "net/http" "runtime/debug" "time" "github.com/konduktor/konduktor/internal/logging" ) type responseWriter struct { http.ResponseWriter status int size int } func (rw *responseWriter) WriteHeader(code int) { rw.status = code rw.ResponseWriter.WriteHeader(code) } func (rw *responseWriter) Write(b []byte) (int, error) { size, err := rw.ResponseWriter.Write(b) rw.size += size return size, err } func ServerHeader(next http.Handler, version string) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Server", fmt.Sprintf("konduktor/%s", version)) next.ServeHTTP(w, r) }) } func AccessLog(next http.Handler, logger *logging.Logger) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() wrapped := &responseWriter{ ResponseWriter: w, status: http.StatusOK, } next.ServeHTTP(wrapped, r) duration := time.Since(start) logger.Info("HTTP request", "method", r.Method, "path", r.URL.Path, "status", wrapped.status, "duration_ms", duration.Milliseconds(), "client_ip", r.RemoteAddr, "user_agent", r.UserAgent(), ) }) } func Recovery(next http.Handler, logger *logging.Logger) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer func() { if err := recover(); err != nil { logger.Error("Panic recovered", "error", fmt.Sprintf("%v", err), "stack", string(debug.Stack()), ) http.Error(w, "Internal Server Error", http.StatusInternalServerError) } }() next.ServeHTTP(w, r) }) }