grim/hgkeeper

Add access logging
draft
5 months ago, Gary Kramlich
32762318fbdd
Parents 4fc4d4c7aac6
Children f3e037634b20
Add access logging
--- a/hgweb/hgweb.go Wed Apr 15 00:53:36 2020 -0500
+++ b/hgweb/hgweb.go Wed Apr 15 01:05:27 2020 -0500
@@ -70,7 +70,11 @@
return err
}
- s.server.Handler = cache.middleware(&cgi.Handler{Path: s.cgiPath})
+ s.server.Handler = Logger(
+ cache.middleware(
+ &cgi.Handler{Path: s.cgiPath},
+ ),
+ )
log.Infof("http listening on %s", s.listenAddr)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hgweb/logger.go Wed Apr 15 01:05:27 2020 -0500
@@ -0,0 +1,119 @@
+package hgweb
+
+import (
+ "net/http"
+ "strings"
+ "time"
+
+ log "github.com/sirupsen/logrus"
+)
+
+type loggerResponseWriter struct {
+ w http.ResponseWriter
+ wroteHeader bool
+ statusCode int
+ written int64
+}
+
+var _ http.ResponseWriter = (*loggerResponseWriter)(nil)
+
+func (w *loggerResponseWriter) Header() http.Header {
+ return w.w.Header()
+}
+
+func (w *loggerResponseWriter) Write(data []byte) (int, error) {
+ if !w.wroteHeader {
+ w.WriteHeader(http.StatusOK)
+ }
+
+ n, err := w.w.Write(data)
+ w.written += int64(n)
+
+ return n, err
+}
+
+func (w *loggerResponseWriter) WriteHeader(statusCode int) {
+ if !w.wroteHeader {
+ w.statusCode = statusCode
+ w.wroteHeader = true
+ }
+
+ w.w.WriteHeader(w.statusCode)
+}
+
+func (w *loggerResponseWriter) StatusCode() int {
+ return w.statusCode
+}
+
+func (w *loggerResponseWriter) Written() int64 {
+ return w.written
+}
+
+func getAddr(r *http.Request) string {
+ // check for the X-Forwarded-For header and use if it we have it
+ if fwd := r.Header.Get("X-Forwarded-For"); fwd != "" {
+ return fwd
+ }
+
+ // Request.RemoteAddr is ipv4:port or [ipv6]:port so we have to trim off
+ // the extra bits.
+ addr := r.RemoteAddr
+
+ // we use LastIndex so we can parse IPv6 addresses
+ if idx := strings.LastIndex(addr, ":"); idx != -1 {
+ addr = addr[:idx]
+ }
+
+ // if the ipv6 was wrapped in [] we need to unwrap it
+ if idx := strings.Index(addr, "]"); idx != -1 {
+ addr = addr[1:idx]
+ }
+
+ return addr
+}
+
+func Logger(h http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ rw := &loggerResponseWriter{
+ w: w,
+ }
+
+ defer func() {
+ // implement the NCSA Combined Log Format
+ // http://publib.boulder.ibm.com/tividd/td/ITWSA/ITWSA_info45/en_US/HTML/guide/c-logs.html#combined
+
+ addr := getAddr(r)
+
+ username := "-"
+ if user, _, ok := r.BasicAuth(); ok && username != "" {
+ username = user
+ }
+
+ referer := r.Referer()
+ if referer == "" {
+ referer = "-"
+ }
+
+ userAgent := r.UserAgent()
+ if userAgent == "" {
+ userAgent = "-"
+ }
+
+ log.Infof(
+ "%s - %s [%s] \"%s %s %s\" %d %d %q %q\n",
+ addr,
+ username,
+ time.Now().Format("02/Jan/2006:15:04:05 -0700"),
+ r.Method,
+ r.URL.Path,
+ r.Proto,
+ rw.StatusCode(),
+ rw.Written(),
+ referer,
+ userAgent,
+ )
+ }()
+
+ h.ServeHTTP(rw, r)
+ })
+}