-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathmiddleware.go
More file actions
132 lines (107 loc) · 2.89 KB
/
middleware.go
File metadata and controls
132 lines (107 loc) · 2.89 KB
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Package muxlogrus is a logrus middleware for gorilla/mux.
// Every request information will be record and output.
package muxlogrus
import (
"net"
"net/http"
"strings"
"time"
"github.com/sirupsen/logrus"
)
type timer interface {
Now() time.Time
Since(time.Time) time.Duration
}
// realClock save request times
type realClock struct{}
func (rc *realClock) Now() time.Time {
return time.Now()
}
func (rc *realClock) Since(t time.Time) time.Duration {
return time.Since(t)
}
// LogOptions logging middleware options
type LogOptions struct {
Formatter logrus.Formatter
EnableStarting bool
}
// LoggingMiddleware is a middleware handler that logs the request as it goes in and the response as it goes out.
type LoggingMiddleware struct {
logger *logrus.Logger
clock timer
enableStarting bool
}
// NewLogger returns a new *LoggingMiddleware, yay!
func NewLogger(opts ...LogOptions) *LoggingMiddleware {
var opt LogOptions
if len(opts) == 0 {
opt = LogOptions{}
} else {
opt = opts[0]
}
if opt.Formatter == nil {
opt.Formatter = &logrus.TextFormatter{
DisableColors: true,
TimestampFormat: time.RFC3339,
}
}
log := logrus.New()
log.Formatter = opt.Formatter
return &LoggingMiddleware{
logger: log,
clock: &realClock{},
enableStarting: opt.EnableStarting,
}
}
// realIP get the real IP from http request
func realIP(req *http.Request) string {
ra := req.RemoteAddr
if ip := req.Header.Get("X-Forwarded-For"); ip != "" {
ra = strings.Split(ip, ", ")[0]
} else if ip := req.Header.Get("X-Real-IP"); ip != "" {
ra = ip
} else {
ra, _, _ = net.SplitHostPort(ra)
}
return ra
}
type loggingResponseWriter struct {
http.ResponseWriter
statusCode int
}
func newLoggingResponseWriter(w http.ResponseWriter) *loggingResponseWriter {
return &loggingResponseWriter{w, http.StatusOK}
}
func (lw *loggingResponseWriter) WriteHeader(code int) {
lw.statusCode = code
lw.ResponseWriter.WriteHeader(code)
}
func (lw *loggingResponseWriter) Write(b []byte) (int, error) {
return lw.ResponseWriter.Write(b)
}
// Middleware implement mux middleware interface
func (m *LoggingMiddleware) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
entry := logrus.NewEntry(m.logger)
start := m.clock.Now()
if reqID := r.Header.Get("X-Request-Id"); reqID != "" {
entry = entry.WithField("requestId", reqID)
}
if remoteAddr := realIP(r); remoteAddr != "" {
entry = entry.WithField("remoteAddr", remoteAddr)
}
if m.enableStarting {
entry.WithFields(logrus.Fields{
"request": r.RequestURI,
"method": r.Method,
}).Info("started handling request")
}
lw := newLoggingResponseWriter(w)
next.ServeHTTP(lw, r)
latency := m.clock.Since(start)
entry.WithFields(logrus.Fields{
"status": lw.statusCode,
"took": latency,
}).Info("completed handling request")
})
}