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
|
package main
import (
"fmt"
"net/http"
"net/url"
"time"
log "github.com/sirupsen/logrus"
)
var (
accessLogFormat = "text"
logrusEntry = log.WithField("system", "http")
)
func configureLogging(format string, verbose bool) {
if verbose {
log.SetLevel(log.DebugLevel)
}
switch format {
case "json":
log.SetFormatter(&log.JSONFormatter{})
accessLogFormat = "json"
default:
log.SetFormatter(&log.TextFormatter{})
accessLogFormat = "text"
}
}
type loggingResponseWriter struct {
rw http.ResponseWriter
status int
written int64
started time.Time
}
func newLoggingResponseWriter(rw http.ResponseWriter) loggingResponseWriter {
return loggingResponseWriter{
rw: rw,
started: time.Now(),
}
}
func (l *loggingResponseWriter) Header() http.Header {
return l.rw.Header()
}
func (l *loggingResponseWriter) Write(data []byte) (n int, err error) {
if l.status == 0 {
l.WriteHeader(http.StatusOK)
}
n, err = l.rw.Write(data)
l.written += int64(n)
return
}
func (l *loggingResponseWriter) WriteHeader(status int) {
if l.status != 0 {
return
}
l.status = status
l.rw.WriteHeader(status)
}
func (l *loggingResponseWriter) extractLogFields(r *http.Request) log.Fields {
referer := r.Referer()
parsedReferer, err := url.Parse(referer)
// The referer query string may contain credentials, so remove if possible
if err == nil {
parsedReferer.RawQuery = ""
referer = parsedReferer.String()
}
return log.Fields{
"host": r.Host,
"remoteAddr": r.RemoteAddr,
"method": r.Method,
"uri": r.URL.Path, //The request query string may contain credentials
"proto": r.Proto,
"status": l.status,
"written": l.written,
"referer": referer,
"userAgent": r.UserAgent(),
"duration": time.Since(l.started).Seconds(),
}
}
func (l *loggingResponseWriter) Log(r *http.Request) {
fields := l.extractLogFields(r)
switch accessLogFormat {
case "text":
fmt.Printf("%s %s - - [%s] %q %d %d %q %q %f\n",
fields["host"], fields["remoteAddr"], l.started,
fmt.Sprintf("%s %s %s", fields["method"], fields["uri"], fields["proto"]),
fields["status"], fields["written"], fields["referer"], fields["userAgent"], fields["duration"],
)
case "json":
logrusEntry.WithFields(fields).Info("access")
default:
panic("invalid access log format")
}
}
func fatal(err error) {
log.WithError(err).Fatal()
}
|