Skip to content
This repository was archived by the owner on Jan 24, 2019. It is now read-only.

Commit 9341dcb

Browse files
Paul Seifferttalam
Paul Seiffert
authored andcommitted
Make request logging format configurable
1 parent 3c51c91 commit 9341dcb

File tree

3 files changed

+73
-42
lines changed

3 files changed

+73
-42
lines changed

logging_handler.go

+51-23
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,14 @@ import (
99
"net"
1010
"net/http"
1111
"net/url"
12+
"text/template"
1213
"time"
1314
)
1415

16+
const (
17+
defaultRequestLoggingFormat = "{{.Client}} - {{.Username}} [{{.Timestamp}}] {{.Host}} {{.RequestMethod}} {{.Upstream}} {{.RequestURI}} {{.Protocol}} {{.UserAgent}} {{.StatusCode}} {{.ResponseSize}} {{.RequestDuration}}"
18+
)
19+
1520
// responseLogger is wrapper of http.ResponseWriter that keeps track of its HTTP status
1621
// code and body size
1722
type responseLogger struct {
@@ -64,15 +69,38 @@ func (l *responseLogger) Size() int {
6469
return l.size
6570
}
6671

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+
6789
// loggingHandler is the http.Handler implementation for LoggingHandlerTo and its friends
6890
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
7295
}
7396

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+
}
76104
}
77105

78106
func (h loggingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
@@ -83,14 +111,13 @@ func (h loggingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
83111
if !h.enabled {
84112
return
85113
}
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())
88115
}
89116

90117
// Log entry for req similar to Apache Common Log Format.
91118
// ts is the timestamp with which the entry should be logged.
92119
// 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) {
94121
if username == "" {
95122
username = "-"
96123
}
@@ -114,19 +141,20 @@ func buildLogLine(username, upstream string, req *http.Request, url url.URL, ts
114141

115142
duration := float64(time.Now().Sub(ts)) / float64(time.Second)
116143

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"))
132160
}

main.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ func main() {
6767
flagSet.Bool("cookie-httponly", true, "set HttpOnly cookie flag")
6868

6969
flagSet.Bool("request-logging", true, "Log requests to stdout")
70+
flagSet.String("request-logging-format", defaultRequestLoggingFormat, "Template for log lines")
7071

7172
flagSet.String("provider", "google", "OAuth provider")
7273
flagSet.String("login-url", "", "Authentication endpoint")
@@ -124,7 +125,7 @@ func main() {
124125
}
125126

126127
s := &Server{
127-
Handler: LoggingHandler(os.Stdout, oauthproxy, opts.RequestLogging),
128+
Handler: LoggingHandler(os.Stdout, oauthproxy, opts.RequestLogging, opts.RequestLoggingFormat),
128129
Opts: opts,
129130
}
130131
s.ListenAndServe()

options.go

+20-18
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ type Options struct {
7171
Scope string `flag:"scope" cfg:"scope"`
7272
ApprovalPrompt string `flag:"approval-prompt" cfg:"approval_prompt"`
7373

74-
RequestLogging bool `flag:"request-logging" cfg:"request_logging"`
74+
RequestLogging bool `flag:"request-logging" cfg:"request_logging"`
75+
RequestLoggingFormat string `flag:"request-logging-format" cfg:"request_logging_format"`
7576

7677
SignatureKey string `flag:"signature-key" cfg:"signature_key" env:"OAUTH2_PROXY_SIGNATURE_KEY"`
7778

@@ -90,23 +91,24 @@ type SignatureData struct {
9091

9192
func NewOptions() *Options {
9293
return &Options{
93-
ProxyPrefix: "/oauth2",
94-
HttpAddress: "127.0.0.1:4180",
95-
HttpsAddress: ":443",
96-
DisplayHtpasswdForm: true,
97-
CookieName: "_oauth2_proxy",
98-
CookieSecure: true,
99-
CookieHttpOnly: true,
100-
CookieExpire: time.Duration(168) * time.Hour,
101-
CookieRefresh: time.Duration(0),
102-
SetXAuthRequest: false,
103-
SkipAuthPreflight: false,
104-
PassBasicAuth: true,
105-
PassUserHeaders: true,
106-
PassAccessToken: false,
107-
PassHostHeader: true,
108-
ApprovalPrompt: "force",
109-
RequestLogging: true,
94+
ProxyPrefix: "/oauth2",
95+
HttpAddress: "127.0.0.1:4180",
96+
HttpsAddress: ":443",
97+
DisplayHtpasswdForm: true,
98+
CookieName: "_oauth2_proxy",
99+
CookieSecure: true,
100+
CookieHttpOnly: true,
101+
CookieExpire: time.Duration(168) * time.Hour,
102+
CookieRefresh: time.Duration(0),
103+
SetXAuthRequest: false,
104+
SkipAuthPreflight: false,
105+
PassBasicAuth: true,
106+
PassUserHeaders: true,
107+
PassAccessToken: false,
108+
PassHostHeader: true,
109+
ApprovalPrompt: "force",
110+
RequestLogging: true,
111+
RequestLoggingFormat: defaultRequestLoggingFormat,
110112
}
111113
}
112114

0 commit comments

Comments
 (0)