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
package api
import (
"net/http"
"strings"
"time"
"github.com/go-chi/chi/middleware"
"go.uber.org/zap"
"github.com/cortezaproject/corteza-server/pkg/logger"
)
// contextLogger middleware binds logger to request's context.
//
// This allows us to use logger from context (with requestID)
// inside our (generated) handlers and controllers
func contextLogger(log *zap.Logger) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
var requestID = middleware.GetReqID(req.Context())
w.Header().Add("X-Request-Id", requestID)
req = req.WithContext(logger.ContextWithValue(
req.Context(),
log.With(zap.String("requestID", requestID)).Named("rest"),
))
next.ServeHTTP(w, req)
})
}
}
// LogRequest middleware logs request details
//
// It uses logger from context, see contextLogger()
func LogRequest(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
var remote = req.RemoteAddr
if l := strings.LastIndex(remote, ":"); l > -1 {
remote = remote[:l]
}
logger.ContextValue(req.Context()).Info(
"HTTP request "+req.Method+" "+req.URL.Path,
zap.String("method", req.Method),
zap.String("path", req.URL.Path),
zap.Int64("size", req.ContentLength),
zap.String("remote", remote),
)
next.ServeHTTP(w, req)
})
}
// LogResponse middleware logs response details
//
// It uses logger from context, see contextLogger()
func LogResponse(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
wrapped := middleware.NewWrapResponseWriter(w, req.ProtoMajor)
t := time.Now()
defer func() {
logger.ContextValue(req.Context()).Info(
"HTTP response "+req.Method+" "+req.URL.Path,
zap.String("method", req.Method),
zap.String("path", req.URL.Path),
zap.Int("status", wrapped.Status()),
zap.Int("size", wrapped.BytesWritten()),
zap.Float64("duration", time.Since(t).Seconds()),
)
}()
next.ServeHTTP(wrapped, req)
})
}