package middleware import ( "bufio" "fmt" "log" "net" "net/http" "strings" "time" ) type statusRecorder struct { http.ResponseWriter statusCode int wroteHeader bool } func newStatusRecorder(w http.ResponseWriter) *statusRecorder { return &statusRecorder{ ResponseWriter: w, statusCode: http.StatusOK, } } func (rw *statusRecorder) WriteHeader(code int) { if rw.wroteHeader { return } rw.statusCode = code rw.wroteHeader = true rw.ResponseWriter.WriteHeader(code) } func (rw *statusRecorder) Write(b []byte) (int, error) { if !rw.wroteHeader { rw.WriteHeader(http.StatusOK) } return rw.ResponseWriter.Write(b) } func (rw *statusRecorder) Flush() { if flusher, ok := rw.ResponseWriter.(http.Flusher); ok { flusher.Flush() } } func (rw *statusRecorder) Hijack() (net.Conn, *bufio.ReadWriter, error) { hijacker, ok := rw.ResponseWriter.(http.Hijacker) if !ok { return nil, nil, fmt.Errorf("response writer does not support hijacking") } return hijacker.Hijack() } func (rw *statusRecorder) Push(target string, opts *http.PushOptions) error { pusher, ok := rw.ResponseWriter.(http.Pusher) if !ok { return http.ErrNotSupported } return pusher.Push(target, opts) } func (rw *statusRecorder) Unwrap() http.ResponseWriter { return rw.ResponseWriter } func RequestLogger(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() if strings.HasPrefix(r.URL.Path, "/dist/static/") || strings.HasPrefix(r.URL.Path, "/static/") || r.URL.Path == "/favicon.ico" { next.ServeHTTP(w, r) return } recorder := newStatusRecorder(w) next.ServeHTTP(recorder, r) log.Printf("%s %s %d %s", r.Method, r.URL.Path, recorder.statusCode, time.Since(start)) }) }