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  }