github.com/shoshinnikita/budget-manager@v0.7.1-0.20220131195411-8c46ff1c6778/internal/web/middlewares/logging.go (about) 1 package middlewares 2 3 import ( 4 "net/http" 5 "strings" 6 "time" 7 8 "github.com/ShoshinNikita/budget-manager/internal/logger" 9 "github.com/ShoshinNikita/budget-manager/internal/pkg/reqid" 10 ) 11 12 // LoggingMiddleware logs HTTP requests. Logs include execution time, content length and status code 13 func LoggingMiddleware(h http.Handler, log logger.Logger) http.Handler { 14 shouldSkip := func(r *http.Request) bool { 15 return strings.HasPrefix(r.URL.Path, "/static/") 16 } 17 18 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 19 if shouldSkip(r) { 20 h.ServeHTTP(w, r) 21 return 22 } 23 24 log := reqid.FromContextToLogger(r.Context(), log) 25 log = log.WithFields(logger.Fields{"method": r.Method, "url": r.URL.Path}) 26 27 log.Debug("start request") 28 29 respWriter := newResponseWriter(w) 30 now := time.Now() 31 h.ServeHTTP(respWriter, r) 32 since := time.Since(now) 33 34 log.WithFields(logger.Fields{ 35 "time": since, 36 "status_code": respWriter.statusCode, 37 "content_length": respWriter.contentLength, 38 }).Debug("finish request") 39 }) 40 } 41 42 // responseWriter implents 'http.ResponseWriter' interface and contains the information 43 // about status code and content length 44 type responseWriter struct { 45 http.ResponseWriter 46 47 statusCode int 48 contentLength int 49 } 50 51 func newResponseWriter(w http.ResponseWriter) *responseWriter { 52 return &responseWriter{ 53 ResponseWriter: w, 54 statusCode: http.StatusOK, 55 } 56 } 57 58 func (w *responseWriter) WriteHeader(statusCode int) { 59 w.statusCode = statusCode 60 w.ResponseWriter.WriteHeader(statusCode) 61 } 62 63 func (w *responseWriter) Write(data []byte) (int, error) { 64 w.contentLength += len(data) 65 return w.ResponseWriter.Write(data) 66 }