/
middleware.go
99 lines (80 loc) · 2.23 KB
/
middleware.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package observ
import (
"io"
"net"
"net/http"
"time"
"go.opentelemetry.io/otel/api/metric"
"go.opentelemetry.io/otel/plugin/othttp"
"go.uber.org/zap"
)
type ReadCounter struct {
io.ReadCloser
Size int
}
func (r *ReadCounter) Read(b []byte) (int, error) {
n, err := r.ReadCloser.Read(b)
r.Size += n
return n, err
}
type WriterInterceptor struct {
http.ResponseWriter
Size int
code int
}
func (w *WriterInterceptor) WriteHeader(code int) {
w.code = code
w.ResponseWriter.WriteHeader(code)
}
func (w *WriterInterceptor) Write(b []byte) (int, error) {
n, err := w.ResponseWriter.Write(b)
w.Size += n
return n, err
}
func (w *WriterInterceptor) Code() int {
if w.code == 0 {
return http.StatusOK
}
return w.code
}
func Middleware(log *zap.Logger, meter metric.Meter) func(next http.Handler) http.Handler {
dur, _ := meter.NewFloat64Measure("http_handler_duration", metric.WithDescription("HTTP Handler work time"))
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
_, port, _ := net.SplitHostPort(r.RemoteAddr)
r.RemoteAddr = net.JoinHostPort(ReadUserIP(r), port)
readCounter := ReadCounter{ReadCloser: r.Body}
writerInterceptor := WriterInterceptor{ResponseWriter: w}
r.Body = &readCounter
next.ServeHTTP(&writerInterceptor, r)
latency := time.Since(start)
dur.Record(r.Context(), latency.Seconds(),
othttp.PathKey.String(r.URL.Path),
othttp.MethodKey.String(r.Method),
othttp.StatusCodeKey.Int(writerInterceptor.Code()),
)
log.Info("HTTP Request",
zap.String("method", r.Method),
zap.Stringer("url", r.URL),
zap.Duration("latency", latency),
zap.Int("request_size", readCounter.Size),
zap.Int("response_size", writerInterceptor.Size),
zap.Int("response_code", writerInterceptor.Code()),
zap.String("host", r.Host),
zap.String("from", r.RemoteAddr),
zap.String("user-agent", r.Header.Get("User-Agent")),
)
})
}
}
func ReadUserIP(r *http.Request) string {
IPAddress := r.Header.Get("X-Real-Ip")
if IPAddress == "" {
IPAddress = r.Header.Get("X-Forwarded-For")
}
if IPAddress == "" {
IPAddress, _, _ = net.SplitHostPort(r.RemoteAddr)
}
return IPAddress
}