@@ -9,9 +9,14 @@ import (
9
9
"net"
10
10
"net/http"
11
11
"net/url"
12
+ "text/template"
12
13
"time"
13
14
)
14
15
16
+ const (
17
+ defaultRequestLoggingFormat = "{{.Client}} - {{.Username}} [{{.Timestamp}}] {{.Host}} {{.RequestMethod}} {{.Upstream}} {{.RequestURI}} {{.Protocol}} {{.UserAgent}} {{.StatusCode}} {{.ResponseSize}} {{.RequestDuration}}"
18
+ )
19
+
15
20
// responseLogger is wrapper of http.ResponseWriter that keeps track of its HTTP status
16
21
// code and body size
17
22
type responseLogger struct {
@@ -64,15 +69,38 @@ func (l *responseLogger) Size() int {
64
69
return l .size
65
70
}
66
71
72
+ // logMessageData is the container for all values that are available as variables in the request logging format.
73
+ // All values are pre-formatted strings so it is easy to use them in the format string.
74
+ type logMessageData struct {
75
+ Client ,
76
+ Host ,
77
+ Protocol ,
78
+ RequestDuration ,
79
+ RequestMethod ,
80
+ RequestURI ,
81
+ ResponseSize ,
82
+ StatusCode ,
83
+ Timestamp ,
84
+ Upstream ,
85
+ UserAgent ,
86
+ Username string
87
+ }
88
+
67
89
// loggingHandler is the http.Handler implementation for LoggingHandlerTo and its friends
68
90
type loggingHandler struct {
69
- writer io.Writer
70
- handler http.Handler
71
- enabled bool
91
+ writer io.Writer
92
+ handler http.Handler
93
+ enabled bool
94
+ logTemplate * template.Template
72
95
}
73
96
74
- func LoggingHandler (out io.Writer , h http.Handler , v bool ) http.Handler {
75
- return loggingHandler {out , h , v }
97
+ func LoggingHandler (out io.Writer , h http.Handler , v bool , requestLoggingTpl string ) http.Handler {
98
+ return loggingHandler {
99
+ writer : out ,
100
+ handler : h ,
101
+ enabled : v ,
102
+ logTemplate : template .Must (template .New ("request-log" ).Parse (requestLoggingTpl )),
103
+ }
76
104
}
77
105
78
106
func (h loggingHandler ) ServeHTTP (w http.ResponseWriter , req * http.Request ) {
@@ -83,14 +111,13 @@ func (h loggingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
83
111
if ! h .enabled {
84
112
return
85
113
}
86
- logLine := buildLogLine (logger .authInfo , logger .upstream , req , url , t , logger .Status (), logger .Size ())
87
- h .writer .Write (logLine )
114
+ h .writeLogLine (logger .authInfo , logger .upstream , req , url , t , logger .Status (), logger .Size ())
88
115
}
89
116
90
117
// Log entry for req similar to Apache Common Log Format.
91
118
// ts is the timestamp with which the entry should be logged.
92
119
// status, size are used to provide the response HTTP status and size.
93
- func buildLogLine ( username , upstream string , req * http.Request , url url.URL , ts time.Time , status int , size int ) [] byte {
120
+ func ( h loggingHandler ) writeLogLine ( username , upstream string , req * http.Request , url url.URL , ts time.Time , status int , size int ) {
94
121
if username == "" {
95
122
username = "-"
96
123
}
@@ -114,19 +141,20 @@ func buildLogLine(username, upstream string, req *http.Request, url url.URL, ts
114
141
115
142
duration := float64 (time .Now ().Sub (ts )) / float64 (time .Second )
116
143
117
- logLine := fmt .Sprintf ("%s - %s [%s] %s %s %s %q %s %q %d %d %0.3f\n " ,
118
- client ,
119
- username ,
120
- ts .Format ("02/Jan/2006:15:04:05 -0700" ),
121
- req .Host ,
122
- req .Method ,
123
- upstream ,
124
- url .RequestURI (),
125
- req .Proto ,
126
- req .UserAgent (),
127
- status ,
128
- size ,
129
- duration ,
130
- )
131
- return []byte (logLine )
144
+ h .logTemplate .Execute (h .writer , logMessageData {
145
+ Client : client ,
146
+ Host : req .Host ,
147
+ Protocol : req .Proto ,
148
+ RequestDuration : fmt .Sprintf ("%0.3f" , duration ),
149
+ RequestMethod : req .Method ,
150
+ RequestURI : fmt .Sprintf ("%q" , url .RequestURI ()),
151
+ ResponseSize : fmt .Sprintf ("%d" , size ),
152
+ StatusCode : fmt .Sprintf ("%d" , status ),
153
+ Timestamp : ts .Format ("02/Jan/2006:15:04:05 -0700" ),
154
+ Upstream : upstream ,
155
+ UserAgent : fmt .Sprintf ("%q" , req .UserAgent ()),
156
+ Username : username ,
157
+ })
158
+
159
+ h .writer .Write ([]byte ("\n " ))
132
160
}
0 commit comments