cerrado @ 2fb43cc1271572d26298da70f823814cae87a3a0

 1package ext
 2
 3import (
 4	"log/slog"
 5	"net/http"
 6	"time"
 7)
 8
 9type statusWraper struct {
10	statusCode  int
11	size        int
12	innerWriter http.ResponseWriter
13}
14
15func (s *statusWraper) Header() http.Header {
16	return s.innerWriter.Header()
17}
18
19func (s *statusWraper) Write(b []byte) (int, error) {
20	s.size += len(b)
21	return s.innerWriter.Write(b)
22}
23
24func (s *statusWraper) WriteHeader(statusCode int) {
25	s.statusCode = statusCode
26	s.innerWriter.WriteHeader(statusCode)
27}
28
29func (s *statusWraper) StatusCode() int {
30	if s.statusCode == 0 {
31		return 200
32	}
33	return s.statusCode
34}
35
36func wrap(w http.ResponseWriter) *statusWraper {
37	return &statusWraper{
38		innerWriter: w,
39	}
40}
41
42func Log(next http.HandlerFunc) http.HandlerFunc {
43	return func(w http.ResponseWriter, r *http.Request) {
44		t := time.Now()
45		s := wrap(w)
46		next(s, r)
47		encoding := s.Header().Get("Content-Encoding")
48		userAgent := r.Header.Get("User-Agent")
49		slog.Info(
50			"HTTP request",
51			"method", r.Method,
52			"code", s.StatusCode(),
53			"path", r.URL,
54			"encoding", encoding,
55			"user-agent", userAgent,
56			"elapsed", time.Since(t),
57			"body-size", s.size,
58		)
59	}
60}