git.iko.soy/typeable/oauth2-proxy
on master help sign in
Make request logging format configurable
commit9341dcbf79fe130bb06b8ba9cfbd3700080fac9e authorPaul Seiffert <paul.seiffert@jimdo.com> dateFri 14 Jul 2017, 13:08 (9 years ago) parent3c51c91
3 files changed+73−42
logging_handler.go+51−23 main.go+2−1 options.go+20−18
logging_handler.go+51−23
@@ -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
1722type 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
6890type 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
78106func (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
@@ -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
@@ -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
9192func 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