2 files changed,
56 insertions(+),
2 deletions(-)
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 +}