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}