all repos

mugit @ 7b26905

🐮 git server that your cow will love
2 files changed, 56 insertions(+), 2 deletions(-)
add http logger
Author: Oleksandr Smirnov olexsmir@gmail.com
Committed at: 2026-01-28 18:40:04 +0200
Change ID: puktuymontoyukwmpknvlltopqztpuxv
Parent: 1043e31
M internal/handlers/handlers.go

@@ -18,7 +18,7 @@ c *config.Config

t *template.Template } -func InitRoutes(cfg *config.Config) *http.ServeMux { +func InitRoutes(cfg *config.Config) http.Handler { tmpls := template.Must(template.New(""). Funcs(templateFuncs). ParseFS(web.TemplatesFS, "*"))

@@ -36,7 +36,9 @@ mux.HandleFunc("GET /{name}/blob/{ref}/{rest...}", h.fileContentsHandler)

mux.HandleFunc("GET /{name}/log/{ref}", h.logHandler) mux.HandleFunc("GET /{name}/commit/{ref}", h.commitHandler) mux.HandleFunc("GET /{name}/refs/{$}", h.refsHandler) - return mux + + handler := h.recoverMiddleware(mux) + return h.loggingMiddleware(handler) } func (h *handlers) serveStatic(w http.ResponseWriter, r *http.Request) {
M internal/handlers/util.go

@@ -1,8 +1,10 @@

package handlers import ( + "fmt" "log/slog" "net/http" + "time" ) func (h *handlers) templ(w http.ResponseWriter, name string, data any) {

@@ -23,3 +25,53 @@ slog.Info("500", "err", err)

w.WriteHeader(http.StatusInternalServerError) h.templ(w, "500", nil) } + +func (h *handlers) recoverMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + defer func() { + if err := recover(); err != nil { + h.write500(w, fmt.Errorf("panic: %v", err)) + } + }() + next.ServeHTTP(w, r) + }) +} + +func (h *handlers) loggingMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + wrapped := wrapResponseWriter(w) + next.ServeHTTP(wrapped, r) + + slog.Info("http request", + "method", r.Method, + "path", r.URL.Path, + "status", wrapped.status, + "latency", time.Since(start).String(), + ) + }) +} + +type responseWriter struct { + http.ResponseWriter + status int + wroteHeader bool +} + +func wrapResponseWriter(w http.ResponseWriter) *responseWriter { + return &responseWriter{ResponseWriter: w} +} + +func (rw *responseWriter) Status() int { + return rw.status +} + +func (rw *responseWriter) WriteHeader(code int) { + if rw.wroteHeader { + return + } + + rw.status = code + rw.ResponseWriter.WriteHeader(code) + rw.wroteHeader = true +}