From 10815eca8eaaf2c12c698c6943127bb99b176a53 Mon Sep 17 00:00:00 2001 From: David Tootill Date: Tue, 19 Apr 2016 16:45:59 -0700 Subject: [PATCH 1/6] Initial update - manage access log --- examples/accessLog/.gitignore | 2 + examples/accessLog/exampleHandler.go | 46 +++++++ examples/accessLog/runAb.sh | 122 +++++++++++++++++ examples/accessLog/runExample.sh | 40 ++++++ examples/accessLog/traefik.ab.toml | 37 ++++++ examples/accessLog/traefik.example.toml | 42 ++++++ middlewares/logger.go | 168 +++++++++++++++++++++++- middlewares/logger_test.go | 116 ++++++++++++++++ middlewares/saveBackend.go | 24 ++++ server.go | 18 ++- 10 files changed, 604 insertions(+), 11 deletions(-) create mode 100644 examples/accessLog/.gitignore create mode 100644 examples/accessLog/exampleHandler.go create mode 100644 examples/accessLog/runAb.sh create mode 100644 examples/accessLog/runExample.sh create mode 100644 examples/accessLog/traefik.ab.toml create mode 100644 examples/accessLog/traefik.example.toml create mode 100644 middlewares/logger_test.go create mode 100644 middlewares/saveBackend.go diff --git a/examples/accessLog/.gitignore b/examples/accessLog/.gitignore new file mode 100644 index 000000000..47939b405 --- /dev/null +++ b/examples/accessLog/.gitignore @@ -0,0 +1,2 @@ +exampleHandler +exampleHandler.exe diff --git a/examples/accessLog/exampleHandler.go b/examples/accessLog/exampleHandler.go new file mode 100644 index 000000000..2a8fb3d61 --- /dev/null +++ b/examples/accessLog/exampleHandler.go @@ -0,0 +1,46 @@ +/* +Simple program to start a web server on a specified port +*/ +package main + +import ( + "flag" + "fmt" + "net/http" + "os" +) + +var ( + name string + port int + help *bool +) + +func init() { + flag.StringVar(&name, "n", "", "Name of handler for messages") + flag.IntVar(&port, "p", 0, "Port number to listen") + help = flag.Bool("h", false, "Displays help message") +} + +func usage() { + fmt.Printf("Usage: example -n name -p port \n") + os.Exit(2) +} + +func handler(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "%s: Received query %s!\n", name, r.URL.Path[1:]) +} + +func main() { + flag.Parse() + if *help || len(name) == 0 || port <= 0 { + usage() + } + http.HandleFunc("/", handler) + fmt.Printf("%s: Listening on :%d...\n", name, port) + if er := http.ListenAndServe(fmt.Sprintf(":%d", port), nil); er != nil { + fmt.Printf("%s: Error from ListenAndServe: %s", name, er.Error()) + os.Exit(1) + } + fmt.Printf("%s: How'd we get past listen and serve???\n", name) +} diff --git a/examples/accessLog/runAb.sh b/examples/accessLog/runAb.sh new file mode 100644 index 000000000..db7d9366c --- /dev/null +++ b/examples/accessLog/runAb.sh @@ -0,0 +1,122 @@ +#!/bin/bash +usage() +{ + echo 'runAb.sh - Run Apache Benchmark to test access log' + echo ' Usage: runAb.sh [--conn nnn] [--log xxx] [--num nnn] [--time nnn] [--wait nn]' + echo ' -c|--conn - number of simultaneous connections (default 100)' + echo ' -l|--log - name of logfile (default benchmark.log)' + echo ' -n|--num - number of requests (default 50000); ignored when -t specified' + echo ' -t|--time - time in seconds for benchmark (default no limit)' + echo ' -w|--wait - number of seconds to wait for Traefik to initialize (default 15)' + echo ' ' + exit +} + +# Parse options + +conn=100 +num=50000 +wait=15 +time=0 +logfile="" +while [[ $1 =~ ^- ]] +do + case $1 in + -c|--conn) + conn=$2 + shift + ;; + -h|--help) + usage + ;; + -l|--log|--logfile) + logfile=$2 + shift + ;; + -n|--num) + num=$2 + shift + ;; + -t|--time) + time=$2 + shift + ;; + -w|--wait) + wait=$2 + shift + ;; + *) + echo Unknown option "$1" + usage + esac + shift +done +if [ -z "$logfile" ] ; then + logfile="benchmark.log" +fi + +# Change to accessLog examples directory + +[ -d examples/accessLog ] && cd examples/accessLog +if [ ! -r exampleHandler.go ] ; then + echo Please run this script either from the traefik repo root or from the examples/accessLog directory + exit +fi + +# Kill traefik and any running example processes + +sudo pkill -f traefik +pkill -f exampleHandler +[ ! -d log ] && mkdir log + +# Start new example processes + +go build exampleHandler.go +[ $? -ne 0 ] && exit $? +./exampleHandler -n Handler1 -p 8081 & +[ $? -ne 0 ] && exit $? +./exampleHandler -n Handler2 -p 8082 & +[ $? -ne 0 ] && exit $? +./exampleHandler -n Handler3 -p 8083 & +[ $? -ne 0 ] && exit $? + +# Wait a couple of seconds for handlers to initialize and start Traefik + +cd ../.. +sleep 2s +echo Starting Traefik... +sudo ./traefik -c examples/accessLog/traefik.ab.toml & +[ $? -ne 0 ] && exit $? + +# Wait for Traefik to initialize and run ab + +echo Waiting $wait seconds before starting ab benchmark +sleep ${wait}s +echo +stime=`date '+%s'` +if [ $time -eq 0 ] ; then + echo Benchmark starting `date` with $conn connections until $num requests processed | tee $logfile + echo | tee -a $logfile + echo ab -k -c $conn -n $num http://127.0.0.1/test | tee -a $logfile + echo | tee -a $logfile + ab -k -c $conn -n $num http://127.0.0.1/test 2>&1 | tee -a $logfile +else + if [ $num -ne 50000 ] ; then + echo Request count ignored when --time specified + fi + echo Benchmark starting `date` with $conn connections for $time seconds | tee $logfile + echo | tee -a $logfile + echo ab -k -c $conn -t $time -n 100000000 http://127.0.0.1/test | tee -a $logfile + echo | tee -a $logfile + ab -k -c $conn -t $time -n 100000000 http://127.0.0.1/test 2>&1 | tee -a $logfile +fi + +etime=`date '+%s'` +let "dt=$etime - $stime" +let "ds=$dt % 60" +let "dm=($dt / 60) % 60" +let "dh=$dt / 3600" +echo | tee -a $logfile +printf "Benchmark ended `date` after %d:%02d:%02d\n" $dh $dm $ds | tee -a $logfile +echo Results available in $logfile + diff --git a/examples/accessLog/runExample.sh b/examples/accessLog/runExample.sh new file mode 100644 index 000000000..69186b4df --- /dev/null +++ b/examples/accessLog/runExample.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# Script to run a three-server example. This script runs the three servers and restarts Traefik +# Once it is running, use the command: +# +# curl http://127.0.0.1:80/test{1,2,2} +# +# to send requests to send test requests to the servers. You should see a response like: +# +# Handler1: received query test1! +# Handler2: received query test2! +# Handler3: received query test2! +# +# and can then inspect log/access.log to see frontend, backend, and timing + +# Kill traefik and any running example processes +sudo pkill -f traefik +pkill -f exampleHandler +[ ! -d log ] && mkdir log + +# Start new example processes +cd examples/accessLog +go build exampleHandler.go +[ $? -ne 0 ] && exit $? +./exampleHandler -n Handler1 -p 8081 & +[ $? -ne 0 ] && exit $? +./exampleHandler -n Handler2 -p 8082 & +[ $? -ne 0 ] && exit $? +./exampleHandler -n Handler3 -p 8083 & +[ $? -ne 0 ] && exit $? + +# Wait a couple of seconds for handlers to initialize and start Traefik +cd ../.. +sleep 2s +echo Starting Traefik... +sudo ./traefik -c examples/accessLog/traefik.example.toml & +[ $? -ne 0 ] && exit $? + +echo Sample handlers and traefik started successfully! +echo 'Use command curl http://127.0.0.1:80/test{1,2,2} to drive test' +echo Then inspect log/access.log to verify it contains frontend, backend, and timing diff --git a/examples/accessLog/traefik.ab.toml b/examples/accessLog/traefik.ab.toml new file mode 100644 index 000000000..28fa15bbb --- /dev/null +++ b/examples/accessLog/traefik.ab.toml @@ -0,0 +1,37 @@ +################################################################ +# Global configuration +################################################################ +traefikLogsFile = "log/traefik.log" +accessLogsFile = "log/access.log" +logLevel = "DEBUG" + +################################################################ +# Web configuration backend +################################################################ +[web] +address = ":7888" + +################################################################ +# File configuration backend +################################################################ +[file] + +################################################################ +# rules +################################################################ + [backends] + [backends.backend] + [backends.backend.LoadBalancer] + method = "drr" + [backends.backend.servers.server1] + url = "http://127.0.0.1:8081" + [backends.backend.servers.server2] + url = "http://127.0.0.1:8082" + [backends.backend.servers.server3] + url = "http://127.0.0.1:8083" + [frontends] + [frontends.frontend] + backend = "backend" + passHostHeader = true + [frontends.frontend.routes.test] + rule = "Path: /test" diff --git a/examples/accessLog/traefik.example.toml b/examples/accessLog/traefik.example.toml new file mode 100644 index 000000000..0e425210d --- /dev/null +++ b/examples/accessLog/traefik.example.toml @@ -0,0 +1,42 @@ +################################################################ +# Global configuration +################################################################ +traefikLogsFile = "log/traefik.log" +accessLogsFile = "log/access.log" +logLevel = "DEBUG" + +################################################################ +# Web configuration backend +################################################################ +[web] +address = ":7888" + +################################################################ +# File configuration backend +################################################################ +[file] + +################################################################ +# rules +################################################################ + [backends] + [backends.backend1] + [backends.backend1.servers.server1] + url = "http://127.0.0.1:8081" + [backends.backend2] + [backends.backend2.LoadBalancer] + method = "drr" + [backends.backend2.servers.server1] + url = "http://127.0.0.1:8082" + [backends.backend2.servers.server2] + url = "http://127.0.0.1:8083" + [frontends] + [frontends.frontend1] + backend = "backend1" + [frontends.frontend1.routes.test_1] + rule = "Path: /test1" + [frontends.frontend2] + backend = "backend2" + passHostHeader = true + [frontends.frontend2.routes.test_2] + rule = "Path: /test2" \ No newline at end of file diff --git a/middlewares/logger.go b/middlewares/logger.go index 34baf6f9f..236e27ac3 100644 --- a/middlewares/logger.go +++ b/middlewares/logger.go @@ -1,18 +1,57 @@ package middlewares +/* +Middleware Logger writes each request and its response to the access log. +It gets some information from the logInfoResponseWriter set up by previous middleware. +*/ + import ( - "log" + "fmt" + log "github.com/Sirupsen/logrus" + "github.com/streamrail/concurrent-map" + "io" + "net" "net/http" "os" - - "github.com/gorilla/handlers" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" ) -// Logger is a middleware handler that logs the request as it goes in and the response as it goes out. +const ( + loggerReqidHeader = "X-Traefik-Reqid" +) + +// Logger holds the File defining the access log type Logger struct { file *os.File } +// Logging handler to log frontend name, backend name, and elapsed time +type frontendBackendLoggingHandler struct { + reqid string + writer io.Writer + handlerFunc http.HandlerFunc +} + +var ( + reqidCounter uint64 // Request ID + infoRwMap = cmap.New() // Map of reqid to response writer + backend2FrontendMap map[string]string +) + +// logInfoResponseWriter is a wrapper of type http.ResponseWriter +// that tracks frontend and backend names and request status and size +type logInfoResponseWriter struct { + rw http.ResponseWriter + backend string + frontend string + status int + size int +} + // NewLogger returns a new Logger instance. func NewLogger(file string) *Logger { if len(file) > 0 { @@ -25,17 +64,134 @@ func NewLogger(file string) *Logger { return &Logger{nil} } +// SetBackend2FrontendMap is called by server.go to set up frontend translation +func SetBackend2FrontendMap(newMap *map[string]string) { + backend2FrontendMap = *newMap +} + func (l *Logger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { if l.file == nil { next(rw, r) } else { - handlers.CombinedLoggingHandler(l.file, next).ServeHTTP(rw, r) + reqid := strconv.FormatUint(atomic.AddUint64(&reqidCounter, 1), 10) + log.Debugf("Starting request %s: %s %s %s %s %s", reqid, r.Method, r.URL.RequestURI(), r.Proto, r.Referer(), r.UserAgent()) + r.Header[loggerReqidHeader] = []string{reqid} + defer deleteReqid(r, reqid) + frontendBackendLoggingHandler{reqid, l.file, next}.ServeHTTP(rw, r) } } -// Close closes the logger (i.e. the file). +// Delete a reqid from the map and the request's headers +func deleteReqid(r *http.Request, reqid string) { + log.Debugf("Ending request %s", reqid) + infoRwMap.Remove(reqid) + delete(r.Header, loggerReqidHeader) +} + +// Save the backend name for the Logger +func saveBackendNameForLogger(r *http.Request, backendName string) { + if reqidHdr := r.Header[loggerReqidHeader]; len(reqidHdr) == 1 { + reqid := reqidHdr[0] + if infoRw, ok := infoRwMap.get(reqid); ok { + infoRw.SetBackend(backendName) + infoRw.SetFrontend(backend2FrontendMap[backendName]) + } + } +} + +// Close closes the Logger (i.e. the file). func (l *Logger) Close() { if l.file != nil { l.file.Close() } } + +// Logging handler to log frontend name, backend name, and elapsed time +func (fblh frontendBackendLoggingHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { + startTime := time.Now() + infoRw := &logInfoResponseWriter{rw: rw} + infoRwMap.Set(fblh.reqid, infoRw) + fblh.handlerFunc(infoRw, req) + + username := "-" + url := *req.URL + if url.User != nil { + if name := url.User.Username(); name != "" { + username = name + } + } + + host, _, err := net.SplitHostPort(req.RemoteAddr) + if err != nil { + host = req.RemoteAddr + } + + ts := startTime.Format("02/Jan/2006:15:04:05 -0700") + method := req.Method + uri := url.RequestURI() + if qmIndex := strings.Index(uri, "?"); qmIndex > 0 { + uri = uri[0:qmIndex] + } + proto := req.Proto + referer := req.Referer() + agent := req.UserAgent() + + frontend := strings.TrimPrefix(infoRw.GetFrontend(), "frontend-") + backend := infoRw.GetBackend() + status := infoRw.GetStatus() + size := infoRw.GetSize() + + elapsed := time.Now().UTC().Sub(startTime.UTC()) + fmt.Fprintf(fblh.writer, `%s - %s [%s] "%s %s %s" %d %d "%s" "%s" %s "%s" "%s" %s%s`, + host, username, ts, method, uri, proto, status, size, referer, agent, fblh.reqid, frontend, backend, elapsed, "\n") + +} + +func (lirw *logInfoResponseWriter) Header() http.Header { + return lirw.rw.Header() +} + +func (lirw *logInfoResponseWriter) Write(b []byte) (int, error) { + if lirw.status == 0 { + lirw.status = http.StatusOK + } + size, err := lirw.rw.Write(b) + lirw.size += size + return size, err +} + +func (lirw *logInfoResponseWriter) WriteHeader(s int) { + lirw.rw.WriteHeader(s) + lirw.status = s +} + +func (lirw *logInfoResponseWriter) Flush() { + f, ok := lirw.rw.(http.Flusher) + if ok { + f.Flush() + } +} + +func (lirw *logInfoResponseWriter) GetStatus() int { + return lirw.status +} + +func (lirw *logInfoResponseWriter) GetSize() int { + return lirw.size +} + +func (lirw *logInfoResponseWriter) GetBackend() string { + return lirw.backend +} + +func (lirw *logInfoResponseWriter) GetFrontend() string { + return lirw.frontend +} + +func (lirw *logInfoResponseWriter) SetBackend(backend string) { + lirw.backend = backend +} + +func (lirw *logInfoResponseWriter) SetFrontend(frontend string) { + lirw.frontend = frontend +} diff --git a/middlewares/logger_test.go b/middlewares/logger_test.go new file mode 100644 index 000000000..72ea4704e --- /dev/null +++ b/middlewares/logger_test.go @@ -0,0 +1,116 @@ +package middlewares + +import ( + "fmt" + shellwords "github.com/mattn/go-shellwords" + "github.com/stretchr/testify/assert" + "io/ioutil" + "net/http" + "net/url" + "os" + "path/filepath" + "runtime" + "testing" +) + +type logtestResponseWriter struct{} + +var ( + logger *Logger + logfileName = "traefikTestLogger.log" + logfilePath string + helloWorld = "Hello, World" + testBackendName = "http://127.0.0.1/testBackend" + testFrontendName = "testFrontend" + testStatus = 123 + testHostname = "TestHost" + testUsername = "TestUser" + testPath = "http://testpath" + testPort = 8181 + testProto = "HTTP/0.0" + testMethod = "POST" + testReferer = "testReferer" + testUserAgent = "testUserAgent" + testBackend2FrontendMap = map[string]string{ + testBackendName: testFrontendName, + } + printedLogdata bool +) + +func TestLogger(t *testing.T) { + if runtime.GOOS == "windows" { + logfilePath = filepath.Join(os.Getenv("TEMP"), logfileName) + } else { + logfilePath = filepath.Join("/tmp", logfileName) + } + + logger = NewLogger(logfilePath) + defer cleanup() + SetBackend2FrontendMap(&testBackend2FrontendMap) + + r := &http.Request{ + Header: map[string][]string{ + "User-Agent": {testUserAgent}, + "Referer": {testReferer}, + }, + Proto: testProto, + Host: testHostname, + Method: testMethod, + RemoteAddr: fmt.Sprintf("%s:%d", testHostname, testPort), + URL: &url.URL{ + User: url.UserPassword(testUsername, ""), + Path: testPath, + }, + } + + logger.ServeHTTP(&logtestResponseWriter{}, r, LogWriterTestHandlerFunc) + + if logdata, err := ioutil.ReadFile(logfilePath); err != nil { + fmt.Printf("%s\n%s\n", string(logdata), err.Error()) + assert.Nil(t, err) + } else if tokens, err := shellwords.Parse(string(logdata)); err != nil { + fmt.Printf("%s\n", err.Error()) + assert.Nil(t, err) + } else if assert.Equal(t, 14, len(tokens), printLogdata(logdata)) { + assert.Equal(t, testHostname, tokens[0], printLogdata(logdata)) + assert.Equal(t, testUsername, tokens[2], printLogdata(logdata)) + assert.Equal(t, fmt.Sprintf("%s %s %s", testMethod, testPath, testProto), tokens[5], printLogdata(logdata)) + assert.Equal(t, fmt.Sprintf("%d", testStatus), tokens[6], printLogdata(logdata)) + assert.Equal(t, fmt.Sprintf("%d", len(helloWorld)), tokens[7], printLogdata(logdata)) + assert.Equal(t, testReferer, tokens[8], printLogdata(logdata)) + assert.Equal(t, testUserAgent, tokens[9], printLogdata(logdata)) + assert.Equal(t, "1", tokens[10], printLogdata(logdata)) + assert.Equal(t, testFrontendName, tokens[11], printLogdata(logdata)) + assert.Equal(t, testBackendName, tokens[12], printLogdata(logdata)) + } +} + +func cleanup() { + logger.Close() + os.Remove(logfilePath) +} + +func printLogdata(logdata []byte) string { + return fmt.Sprintf( + "\nExpected: %s\n"+ + "Actual: %s", + "TestHost - TestUser [13/Apr/2016:07:14:19 -0700] \"POST http://testpath HTTP/0.0\" 123 12 \"testReferer\" \"testUserAgent\" 1 \"testFrontend\" \"http://127.0.0.1/testBackend\" 1ms", + string(logdata)) +} + +func LogWriterTestHandlerFunc(rw http.ResponseWriter, r *http.Request) { + rw.Write([]byte(helloWorld)) + rw.WriteHeader(testStatus) + saveBackendNameForLogger(r, testBackendName) +} + +func (lrw *logtestResponseWriter) Header() http.Header { + return map[string][]string{} +} + +func (lrw *logtestResponseWriter) Write(b []byte) (int, error) { + return len(b), nil +} + +func (lrw *logtestResponseWriter) WriteHeader(s int) { +} diff --git a/middlewares/saveBackend.go b/middlewares/saveBackend.go new file mode 100644 index 000000000..459c8d184 --- /dev/null +++ b/middlewares/saveBackend.go @@ -0,0 +1,24 @@ +package middlewares + +/* +Middleware saveBackend sends the backend name to the logger. +*/ + +import ( + "net/http" +) + +// SaveBackend holds the next handler +type SaveBackend struct { + next http.Handler +} + +// NewSaveBackend creates a SaveBackend +func NewSaveBackend(next http.Handler) *SaveBackend { + return &SaveBackend{next} +} + +func (sb *SaveBackend) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + saveBackendNameForLogger(r, (*r.URL).String()) + sb.next.ServeHTTP(rw, r) +} diff --git a/server.go b/server.go index fc948c462..4a29df5fd 100644 --- a/server.go +++ b/server.go @@ -35,7 +35,10 @@ import ( "github.com/streamrail/concurrent-map" ) -var oxyLogger = &OxyLogger{} +var ( + oxyLogger = &OxyLogger{} + backend2FrontendMap map[string]string +) // Server is the reverse-proxy/load-balancer engine type Server struct { @@ -180,9 +183,9 @@ func (server *Server) listenConfigurations(stop chan bool) { } currentConfigurations := server.currentConfigurations.Get().(configs) if configMsg.Configuration == nil { - log.Info("Skipping empty Configuration") - } else if reflect.DeepEqual(currentConfigurations[configMsg.ProviderName], configMsg.Configuration) { - log.Info("Skipping same configuration") + log.Infof("Skipping empty Configuration for provider %s", configMsg.ProviderName) + } else if reflect.DeepEqual(server.currentConfigurations[configMsg.ProviderName], configMsg.Configuration) { + log.Infof("Skipping same configuration for provider %s", configMsg.ProviderName) } else { // Copy configurations to new map so we don't change current if LoadConfig fails newConfigurations := make(configs) @@ -369,6 +372,7 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo redirectHandlers := make(map[string]http.Handler) backends := map[string]http.Handler{} + backend2FrontendMap := map[string]string{} for _, configuration := range configurations { frontendNames := sortedFrontendNamesForConfig(configuration) for _, frontendName := range frontendNames { @@ -376,6 +380,7 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo log.Debugf("Creating frontend %s", frontendName) fwd, _ := forward.New(forward.Logger(oxyLogger), forward.PassHostHeader(frontend.PassHostHeader)) + saveBackend := middlewares.NewSaveBackend(fwd) // default endpoints if not defined in frontends if len(frontend.EntryPoints) == 0 { frontend.EntryPoints = globalConfiguration.DefaultEntryPoints @@ -411,7 +416,7 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo if backends[frontend.Backend] == nil { log.Debugf("Creating backend %s", frontend.Backend) var lb http.Handler - rr, _ := roundrobin.New(fwd) + rr, _ := roundrobin.New(saveBackend) if configuration.Backends[frontend.Backend] == nil { return nil, errors.New("Undefined backend: " + frontend.Backend) } @@ -429,6 +434,7 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo if err != nil { return nil, err } + backend2FrontendMap[url.String()] = frontendName log.Debugf("Creating server %s at %s with weight %d", serverName, url.String(), server.Weight) if err := rebalancer.UpsertServer(url, roundrobin.Weight(server.Weight)); err != nil { return nil, err @@ -442,6 +448,7 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo if err != nil { return nil, err } + backend2FrontendMap[url.String()] = frontendName log.Debugf("Creating server %s at %s with weight %d", serverName, url.String(), server.Weight) if err := rr.UpsertServer(url, roundrobin.Weight(server.Weight)); err != nil { return nil, err @@ -503,6 +510,7 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo } } } + middlewares.SetBackend2FrontendMap(&backend2FrontendMap) return serverEntryPoints, nil } From 04dd41ac3b53cd4e6285f15245417051eebec7c7 Mon Sep 17 00:00:00 2001 From: David Tootill Date: Wed, 20 Apr 2016 01:25:22 +0000 Subject: [PATCH 2/6] Minor corrections --- .gitignore | 4 +++- examples/accessLog/runAb.sh | 0 examples/accessLog/runExample.sh | 0 middlewares/logger.go | 7 +++---- server.go | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) mode change 100644 => 100755 examples/accessLog/runAb.sh mode change 100644 => 100755 examples/accessLog/runExample.sh diff --git a/.gitignore b/.gitignore index 866aca26c..a63c731ec 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,6 @@ traefik.toml vendor/ static/ .vscode/ -site/ \ No newline at end of file +site/ +*.log +*.exe diff --git a/examples/accessLog/runAb.sh b/examples/accessLog/runAb.sh old mode 100644 new mode 100755 diff --git a/examples/accessLog/runExample.sh b/examples/accessLog/runExample.sh old mode 100644 new mode 100755 diff --git a/middlewares/logger.go b/middlewares/logger.go index 236e27ac3..1a876b82f 100644 --- a/middlewares/logger.go +++ b/middlewares/logger.go @@ -15,7 +15,6 @@ import ( "os" "strconv" "strings" - "sync" "sync/atomic" "time" ) @@ -92,9 +91,9 @@ func deleteReqid(r *http.Request, reqid string) { func saveBackendNameForLogger(r *http.Request, backendName string) { if reqidHdr := r.Header[loggerReqidHeader]; len(reqidHdr) == 1 { reqid := reqidHdr[0] - if infoRw, ok := infoRwMap.get(reqid); ok { - infoRw.SetBackend(backendName) - infoRw.SetFrontend(backend2FrontendMap[backendName]) + if infoRw, ok := infoRwMap.Get(reqid); ok { + infoRw.(*logInfoResponseWriter).SetBackend(backendName) + infoRw.(*logInfoResponseWriter).SetFrontend(backend2FrontendMap[backendName]) } } } diff --git a/server.go b/server.go index 4a29df5fd..c4a14f14c 100644 --- a/server.go +++ b/server.go @@ -184,7 +184,7 @@ func (server *Server) listenConfigurations(stop chan bool) { currentConfigurations := server.currentConfigurations.Get().(configs) if configMsg.Configuration == nil { log.Infof("Skipping empty Configuration for provider %s", configMsg.ProviderName) - } else if reflect.DeepEqual(server.currentConfigurations[configMsg.ProviderName], configMsg.Configuration) { + } else if reflect.DeepEqual(currentConfigurations[configMsg.ProviderName], configMsg.Configuration) { log.Infof("Skipping same configuration for provider %s", configMsg.ProviderName) } else { // Copy configurations to new map so we don't change current if LoadConfig fails From c8c0d208bee4a1e56ad6849aacd85cd4adb5a09e Mon Sep 17 00:00:00 2001 From: David Tootill Date: Wed, 20 Apr 2016 01:36:51 +0000 Subject: [PATCH 3/6] Update glide files for mattn/shellwords --- glide.lock | 10 +- glide.yaml | 357 +++++++++++++++++++++++++++-------------------------- 2 files changed, 187 insertions(+), 180 deletions(-) diff --git a/glide.lock b/glide.lock index 48df05ac2..220892855 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: fffa87220825895f7e3a6ceed3b13ecbf6bc934ab072fc9be3d00e3eef411ecb -updated: 2016-04-13T14:05:41.300658168+02:00 +hash: 284404132ac4c657a3b5447c1e3fbac8e0573cf32838c85ecfca1d422120ae73 +updated: 2016-04-20T01:35:47.509571682Z imports: - name: github.com/alecthomas/template version: b867cc6ab45cece8143cfcc6fc9c77cf3f2c23c0 @@ -29,6 +29,7 @@ imports: - memmetrics - roundrobin - utils + - connlimit - stream - name: github.com/coreos/go-etcd version: cc90c7b091275e606ad0ca7102a23fb2072f3f5e @@ -42,7 +43,6 @@ imports: version: ff6f38ccb69afa96214c7ee955359465d1fc767a subpackages: - reference - - digest - name: github.com/docker/docker version: f39987afe8d611407887b3094c03d6ba6a766a67 subpackages: @@ -94,10 +94,8 @@ imports: - client/transport - client/transport/cancellable - types/network - - types/reference - types/registry - types/time - - types/versions - types/blkiodev - name: github.com/docker/go-connections version: f549a9393d05688dff0992ef3efd8bbe6c628aeb @@ -174,6 +172,8 @@ imports: version: 565402cd71fbd9c12aa7e295324ea357e970a61e - name: github.com/mailgun/timetools version: fd192d755b00c968d312d23f521eb0cdc6f66bd0 +- name: github.com/mattn/go-shellwords + version: 525bedee691b5a8df547cb5cf9f86b7fb1883e24 - name: github.com/Microsoft/go-winio version: 862b6557927a5c5c81e411c12aa6de7e566cbb7a - name: github.com/miekg/dns diff --git a/glide.yaml b/glide.yaml index 1cd5b5719..874031d0e 100644 --- a/glide.yaml +++ b/glide.yaml @@ -1,177 +1,184 @@ package: main import: - - package: github.com/coreos/go-etcd - ref: cc90c7b091275e606ad0ca7102a23fb2072f3f5e - subpackages: - - etcd - - package: github.com/mailgun/log - ref: 44874009257d4d47ba9806f1b7f72a32a015e4d8 - - package: github.com/containous/oxy - ref: 021f82bd8260ba15f5862a9fe62018437720dff5 - subpackages: - - cbreaker - - forward - - memmetrics - - roundrobin - - utils - - package: github.com/hashicorp/consul - ref: de080672fee9e6104572eeea89eccdca135bb918 - subpackages: - - api - - package: github.com/samuel/go-zookeeper - ref: fa6674abf3f4580b946a01bf7a1ce4ba8766205b - subpackages: - - zk - - package: github.com/docker/libtrust - ref: 9cbd2a1374f46905c68a4eb3694a130610adc62a - - package: github.com/go-check/check - ref: 11d3bc7aa68e238947792f30573146a3231fc0f1 - - package: golang.org/x/net - ref: d9558e5c97f85372afee28cf2b6059d7d3818919 - subpackages: - - context - - package: github.com/gorilla/handlers - ref: 40694b40f4a928c062f56849989d3e9cd0570e5f - - package: github.com/docker/libkv - ref: 3732f7ff1b56057c3158f10bceb1e79133025373 - - package: github.com/alecthomas/template - ref: b867cc6ab45cece8143cfcc6fc9c77cf3f2c23c0 - - package: github.com/vdemeester/shakers - ref: 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3 - - package: github.com/alecthomas/units - ref: 6b4e7dc5e3143b85ea77909c72caf89416fc2915 - - package: github.com/gambol99/go-marathon - ref: ade11d1dc2884ee1f387078fc28509559b6235d1 - - package: github.com/vulcand/predicate - ref: cb0bff91a7ab7cf7571e661ff883fc997bc554a3 - - package: github.com/thoas/stats - ref: 54ed61c2b47e263ae2f01b86837b0c4bd1da28e8 - - package: github.com/Sirupsen/logrus - ref: 418b41d23a1bf978c06faea5313ba194650ac088 - - package: github.com/unrolled/render - ref: 26b4e3aac686940fe29521545afad9966ddfc80c - - package: github.com/flynn/go-shlex - ref: 3f9db97f856818214da2e1057f8ad84803971cff - - package: github.com/boltdb/bolt - ref: 51f99c862475898df9773747d3accd05a7ca33c1 - - package: gopkg.in/mgo.v2 - ref: 22287bab4379e1fbf6002fb4eb769888f3fb224c - subpackages: - - bson - - package: github.com/docker/docker - ref: f39987afe8d611407887b3094c03d6ba6a766a67 - subpackages: - - autogen - - api - - cliconfig - - daemon/network - - graph/tags - - image - - opts - - pkg/archive - - pkg/fileutils - - pkg/homedir - - pkg/httputils - - pkg/ioutils - - pkg/jsonmessage - - pkg/mflag - - pkg/nat - - pkg/parsers - - pkg/pools - - pkg/promise - - pkg/random - - pkg/stdcopy - - pkg/stringid - - pkg/symlink - - pkg/system - - pkg/tarsum - - pkg/term - - pkg/timeutils - - pkg/tlsconfig - - pkg/ulimit - - pkg/units - - pkg/urlutil - - pkg/useragent - - pkg/version - - registry - - runconfig - - utils - - volume - - package: github.com/mailgun/timetools - ref: fd192d755b00c968d312d23f521eb0cdc6f66bd0 - - package: github.com/codegangsta/negroni - ref: c7477ad8e330bef55bf1ebe300cf8aa67c492d1b - - package: gopkg.in/yaml.v2 - ref: 7ad95dd0798a40da1ccdff6dff35fd177b5edf40 - - package: github.com/opencontainers/runc - ref: 4ab132458fc3e9dbeea624153e0331952dc4c8d5 - subpackages: - - libcontainer/user - - package: github.com/gorilla/mux - ref: f15e0c49460fd49eebe2bcc8486b05d1bef68d3a - - package: github.com/BurntSushi/ty - ref: 6add9cd6ad42d389d6ead1dde60b4ad71e46fd74 - - package: github.com/elazarl/go-bindata-assetfs - ref: d5cac425555ca5cf00694df246e04f05e6a55150 - - package: github.com/BurntSushi/toml - ref: bd2bdf7f18f849530ef7a1c29a4290217cab32a1 - - package: gopkg.in/alecthomas/kingpin.v2 - ref: 639879d6110b1b0409410c7b737ef0bb18325038 - - package: github.com/cenkalti/backoff - ref: 4dc77674aceaabba2c7e3da25d4c823edfb73f99 - - package: gopkg.in/fsnotify.v1 - ref: 96c060f6a6b7e0d6f75fddd10efeaca3e5d1bcb0 - - package: github.com/mailgun/manners - ref: fada45142db3f93097ca917da107aa3fad0ffcb5 - - package: github.com/gorilla/context - ref: 215affda49addc4c8ef7e2534915df2c8c35c6cd - - package: github.com/codahale/hdrhistogram - ref: 954f16e8b9ef0e5d5189456aa4c1202758e04f17 - - package: github.com/gorilla/websocket - - package: github.com/donovanhide/eventsource - ref: d8a3071799b98cacd30b6da92f536050ccfe6da4 - - package: github.com/golang/glog - ref: fca8c8854093a154ff1eb580aae10276ad6b1b5f - - package: github.com/spf13/cast - ref: ee7b3e0353166ab1f3a605294ac8cd2b77953778 - - package: github.com/mitchellh/mapstructure - - package: github.com/spf13/jwalterweatherman - - package: github.com/spf13/pflag - - package: github.com/wendal/errors - - package: github.com/hashicorp/hcl - - package: github.com/kr/pretty - - package: github.com/magiconair/properties - - package: github.com/kr/text - - package: github.com/spf13/viper - ref: a212099cbe6fbe8d07476bfda8d2d39b6ff8f325 - - package: github.com/spf13/cobra - subpackages: - - /cobra - - package: github.com/google/go-querystring/query - - package: github.com/vulcand/vulcand/plugin/rewrite - - package: github.com/stretchr/testify/mock - - package: github.com/xenolf/lego - - package: github.com/vdemeester/libkermit - ref: 7e4e689a6fa9281e0fb9b7b9c297e22d5342a5ec - - package: github.com/docker/libcompose - version: e290a513ba909ca3afefd5cd611f3a3fe56f6a3a - - package: github.com/docker/distribution - version: ff6f38ccb69afa96214c7ee955359465d1fc767a - subpackages: - - reference - - package: github.com/docker/engine-api - subpackages: - - client - - types - - types/container - - types/filters - - types/strslice - - package: github.com/vdemeester/docker-events - - package: github.com/docker/go-connections - subpackages: - - nat - - sockets - - tlsconfig - - package: github.com/docker/go-units - - package: github.com/mailgun/multibuf - - package: github.com/streamrail/concurrent-map +- package: github.com/coreos/go-etcd + version: cc90c7b091275e606ad0ca7102a23fb2072f3f5e + subpackages: + - etcd +- package: github.com/mailgun/log + version: 44874009257d4d47ba9806f1b7f72a32a015e4d8 +- package: github.com/containous/oxy + version: 021f82bd8260ba15f5862a9fe62018437720dff5 + subpackages: + - cbreaker + - forward + - memmetrics + - roundrobin + - utils +- package: github.com/hashicorp/consul + version: de080672fee9e6104572eeea89eccdca135bb918 + subpackages: + - api +- package: github.com/samuel/go-zookeeper + version: fa6674abf3f4580b946a01bf7a1ce4ba8766205b + subpackages: + - zk +- package: github.com/docker/libtrust + version: 9cbd2a1374f46905c68a4eb3694a130610adc62a +- package: github.com/go-check/check + version: 11d3bc7aa68e238947792f30573146a3231fc0f1 +- package: golang.org/x/net + version: d9558e5c97f85372afee28cf2b6059d7d3818919 + subpackages: + - context +- package: github.com/gorilla/handlers + version: 40694b40f4a928c062f56849989d3e9cd0570e5f +- package: github.com/docker/libkv + version: 3732f7ff1b56057c3158f10bceb1e79133025373 +- package: github.com/alecthomas/template + version: b867cc6ab45cece8143cfcc6fc9c77cf3f2c23c0 +- package: github.com/vdemeester/shakers + version: 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3 +- package: github.com/alecthomas/units + version: 6b4e7dc5e3143b85ea77909c72caf89416fc2915 +- package: github.com/gambol99/go-marathon + version: ade11d1dc2884ee1f387078fc28509559b6235d1 +- package: github.com/vulcand/predicate + version: cb0bff91a7ab7cf7571e661ff883fc997bc554a3 +- package: github.com/thoas/stats + version: 54ed61c2b47e263ae2f01b86837b0c4bd1da28e8 +- package: github.com/Sirupsen/logrus + version: 418b41d23a1bf978c06faea5313ba194650ac088 +- package: github.com/unrolled/render + version: 26b4e3aac686940fe29521545afad9966ddfc80c +- package: github.com/flynn/go-shlex + version: 3f9db97f856818214da2e1057f8ad84803971cff +- package: github.com/boltdb/bolt + version: 51f99c862475898df9773747d3accd05a7ca33c1 +- package: gopkg.in/mgo.v2 + version: 22287bab4379e1fbf6002fb4eb769888f3fb224c + subpackages: + - bson +- package: github.com/docker/docker + version: f39987afe8d611407887b3094c03d6ba6a766a67 + subpackages: + - autogen + - api + - cliconfig + - daemon/network + - graph/tags + - image + - opts + - pkg/archive + - pkg/fileutils + - pkg/homedir + - pkg/httputils + - pkg/ioutils + - pkg/jsonmessage + - pkg/mflag + - pkg/nat + - pkg/parsers + - pkg/pools + - pkg/promise + - pkg/random + - pkg/stdcopy + - pkg/stringid + - pkg/symlink + - pkg/system + - pkg/tarsum + - pkg/term + - pkg/timeutils + - pkg/tlsconfig + - pkg/ulimit + - pkg/units + - pkg/urlutil + - pkg/useragent + - pkg/version + - registry + - runconfig + - utils + - volume +- package: github.com/mailgun/timetools + version: fd192d755b00c968d312d23f521eb0cdc6f66bd0 +- package: github.com/codegangsta/negroni + version: c7477ad8e330bef55bf1ebe300cf8aa67c492d1b +- package: gopkg.in/yaml.v2 + version: 7ad95dd0798a40da1ccdff6dff35fd177b5edf40 +- package: github.com/opencontainers/runc + version: 4ab132458fc3e9dbeea624153e0331952dc4c8d5 + subpackages: + - libcontainer/user +- package: github.com/gorilla/mux + version: f15e0c49460fd49eebe2bcc8486b05d1bef68d3a +- package: github.com/BurntSushi/ty + version: 6add9cd6ad42d389d6ead1dde60b4ad71e46fd74 +- package: github.com/elazarl/go-bindata-assetfs + version: d5cac425555ca5cf00694df246e04f05e6a55150 +- package: github.com/BurntSushi/toml + version: bd2bdf7f18f849530ef7a1c29a4290217cab32a1 +- package: gopkg.in/alecthomas/kingpin.v2 + version: 639879d6110b1b0409410c7b737ef0bb18325038 +- package: github.com/cenkalti/backoff + version: 4dc77674aceaabba2c7e3da25d4c823edfb73f99 +- package: gopkg.in/fsnotify.v1 + version: 96c060f6a6b7e0d6f75fddd10efeaca3e5d1bcb0 +- package: github.com/mailgun/manners + version: fada45142db3f93097ca917da107aa3fad0ffcb5 +- package: github.com/gorilla/context + version: 215affda49addc4c8ef7e2534915df2c8c35c6cd +- package: github.com/codahale/hdrhistogram + version: 954f16e8b9ef0e5d5189456aa4c1202758e04f17 +- package: github.com/gorilla/websocket +- package: github.com/donovanhide/eventsource + version: d8a3071799b98cacd30b6da92f536050ccfe6da4 +- package: github.com/golang/glog + version: fca8c8854093a154ff1eb580aae10276ad6b1b5f +- package: github.com/spf13/cast + version: ee7b3e0353166ab1f3a605294ac8cd2b77953778 +- package: github.com/mitchellh/mapstructure +- package: github.com/spf13/jwalterweatherman +- package: github.com/spf13/pflag +- package: github.com/wendal/errors +- package: github.com/hashicorp/hcl +- package: github.com/kr/pretty +- package: github.com/magiconair/properties +- package: github.com/kr/text +- package: github.com/spf13/viper + version: a212099cbe6fbe8d07476bfda8d2d39b6ff8f325 +- package: github.com/spf13/cobra + subpackages: + - cobra +- package: github.com/google/go-querystring + subpackages: + - query +- package: github.com/vulcand/vulcand + subpackages: + - plugin/rewrite +- package: github.com/stretchr/testify + subpackages: + - mock +- package: github.com/xenolf/lego +- package: github.com/vdemeester/libkermit + version: 7e4e689a6fa9281e0fb9b7b9c297e22d5342a5ec +- package: github.com/docker/libcompose + version: e290a513ba909ca3afefd5cd611f3a3fe56f6a3a +- package: github.com/docker/distribution + version: ff6f38ccb69afa96214c7ee955359465d1fc767a + subpackages: + - reference +- package: github.com/docker/engine-api + subpackages: + - client + - types + - types/container + - types/filters + - types/strslice +- package: github.com/vdemeester/docker-events +- package: github.com/docker/go-connections + subpackages: + - nat + - sockets + - tlsconfig +- package: github.com/docker/go-units +- package: github.com/mailgun/multibuf +- package: github.com/streamrail/concurrent-map +- package: github.com/mattn/go-shellwords From 2a76a717e6644082ec24cf634c33bdf3522a819e Mon Sep 17 00:00:00 2001 From: David Tootill Date: Wed, 20 Apr 2016 11:54:57 -0700 Subject: [PATCH 4/6] Add access log integration test --- integration/access_log_test.go | 110 ++++++++++++++++++++ integration/fixtures/access_log_config.toml | 46 ++++++++ integration/integration_test.go | 1 + middlewares/logger.go | 6 +- server.go | 5 +- 5 files changed, 161 insertions(+), 7 deletions(-) create mode 100644 integration/access_log_test.go create mode 100644 integration/fixtures/access_log_config.toml diff --git a/integration/access_log_test.go b/integration/access_log_test.go new file mode 100644 index 000000000..b48705134 --- /dev/null +++ b/integration/access_log_test.go @@ -0,0 +1,110 @@ +package main + +import ( + "fmt" + "io/ioutil" + "net" + "net/http" + "net/http/httptest" + "os" + "os/exec" + "regexp" + "strings" + "time" + + "github.com/go-check/check" + shellwords "github.com/mattn/go-shellwords" + + checker "github.com/vdemeester/shakers" +) + +// AccessLogSuite +type AccessLogSuite struct{ BaseSuite } + +func (s *AccessLogSuite) TestAccessLog(c *check.C) { + // Ensure working directory is clean + os.Remove("access.log") + os.Remove("traefik.log") + + // Start Traefik + cmd := exec.Command(traefikBinary, "--configFile=fixtures/access_log_config.toml") + err := cmd.Start() + c.Assert(err, checker.IsNil) + defer cmd.Process.Kill() + defer os.Remove("access.log") + defer os.Remove("traefik.log") + + time.Sleep(500 * time.Millisecond) + + // Verify Traefik started OK + if traefikLog, err := ioutil.ReadFile("traefik.log"); err != nil { + c.Assert(err.Error(), checker.Equals, "") + } else if len(traefikLog) > 0 { + fmt.Printf("%s\n", string(traefikLog)) + c.Assert(len(traefikLog), checker.Equals, 0) + } + + // Start test servers + ts1 := startAccessLogServer(8081) + defer ts1.Close() + ts2 := startAccessLogServer(8082) + defer ts2.Close() + ts3 := startAccessLogServer(8083) + defer ts3.Close() + + // Make some requests + _, err = http.Get("http://127.0.0.1:8000/test1") + c.Assert(err, checker.IsNil) + _, err = http.Get("http://127.0.0.1:8000/test2") + c.Assert(err, checker.IsNil) + _, err = http.Get("http://127.0.0.1:8000/test2") + c.Assert(err, checker.IsNil) + + // Verify access.log output as expected + if accessLog, err := ioutil.ReadFile("access.log"); err != nil { + c.Assert(err.Error(), checker.Equals, "") + } else { + lines := strings.Split(string(accessLog), "\n") + count := 0 + for i, line := range lines { + if len(line) > 0 { + count++ + if tokens, err := shellwords.Parse(line); err != nil { + c.Assert(err.Error(), checker.Equals, "") + } else { + c.Assert(len(tokens), checker.Equals, 13) + c.Assert(tokens[6], checker.Equals, "200") + c.Assert(tokens[9], checker.Equals, fmt.Sprintf("%d", i+1)) + c.Assert(strings.HasPrefix(tokens[10], "frontend"), checker.True) + c.Assert(strings.HasPrefix(tokens[11], "http://127.0.0.1:808"), checker.True) + c.Assert(regexp.MustCompile("^\\d+\\.\\d+.*s$").MatchString(tokens[12]), checker.True) + } + } + } + c.Assert(count, checker.Equals, 3) + } + + // Verify no other Trarfik problems + if traefikLog, err := ioutil.ReadFile("traefik.log"); err != nil { + c.Assert(err.Error(), checker.Equals, "") + } else if len(traefikLog) > 0 { + fmt.Printf("%s\n", string(traefikLog)) + c.Assert(len(traefikLog), checker.Equals, 0) + } +} + +func startAccessLogServer(port int) (ts *httptest.Server) { + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Received query %s!\n", r.URL.Path[1:]) + }) + if listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port)); err != nil { + panic(err) + } else { + ts = &httptest.Server{ + Listener: listener, + Config: &http.Server{Handler: handler}, + } + ts.Start() + } + return +} diff --git a/integration/fixtures/access_log_config.toml b/integration/fixtures/access_log_config.toml new file mode 100644 index 000000000..2a3e0ed08 --- /dev/null +++ b/integration/fixtures/access_log_config.toml @@ -0,0 +1,46 @@ +################################################################ +# Global configuration +################################################################ +traefikLogsFile = "traefik.log" +accessLogsFile = "access.log" +logLevel = "ERROR" +defaultEntryPoints = ["http"] +[entryPoints] + [entryPoints.http] + address = ":8000" + +################################################################ +# Web configuration backend +################################################################ +[web] +address = ":7888" + +################################################################ +# File configuration backend +################################################################ +[file] + +################################################################ +# rules +################################################################ + [backends] + [backends.backend1] + [backends.backend1.servers.server1] + url = "http://127.0.0.1:8081" + [backends.backend2] + [backends.backend2.LoadBalancer] + method = "drr" + [backends.backend2.servers.server1] + url = "http://127.0.0.1:8082" + [backends.backend2.servers.server2] + url = "http://127.0.0.1:8083" + [frontends] + [frontends.frontend1] + backend = "backend1" + [frontends.frontend1.routes.test_1] + rule = "Path: /test1" + [frontends.frontend2] + backend = "backend2" + passHostHeader = true + [frontends.frontend2.routes.test_2] + rule = "Path: /test2" \ No newline at end of file diff --git a/integration/integration_test.go b/integration/integration_test.go index 7178bb070..d472f7d23 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -23,6 +23,7 @@ func Test(t *testing.T) { func init() { check.Suite(&SimpleSuite{}) + check.Suite(&AccessLogSuite{}) check.Suite(&HTTPSSuite{}) check.Suite(&FileSuite{}) check.Suite(&DockerSuite{}) diff --git a/middlewares/logger.go b/middlewares/logger.go index 1a876b82f..f73f16965 100644 --- a/middlewares/logger.go +++ b/middlewares/logger.go @@ -38,7 +38,7 @@ type frontendBackendLoggingHandler struct { var ( reqidCounter uint64 // Request ID infoRwMap = cmap.New() // Map of reqid to response writer - backend2FrontendMap map[string]string + backend2FrontendMap *map[string]string ) // logInfoResponseWriter is a wrapper of type http.ResponseWriter @@ -65,7 +65,7 @@ func NewLogger(file string) *Logger { // SetBackend2FrontendMap is called by server.go to set up frontend translation func SetBackend2FrontendMap(newMap *map[string]string) { - backend2FrontendMap = *newMap + backend2FrontendMap = newMap } func (l *Logger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { @@ -93,7 +93,7 @@ func saveBackendNameForLogger(r *http.Request, backendName string) { reqid := reqidHdr[0] if infoRw, ok := infoRwMap.Get(reqid); ok { infoRw.(*logInfoResponseWriter).SetBackend(backendName) - infoRw.(*logInfoResponseWriter).SetFrontend(backend2FrontendMap[backendName]) + infoRw.(*logInfoResponseWriter).SetFrontend((*backend2FrontendMap)[backendName]) } } } diff --git a/server.go b/server.go index c4a14f14c..a3d29bba4 100644 --- a/server.go +++ b/server.go @@ -35,10 +35,7 @@ import ( "github.com/streamrail/concurrent-map" ) -var ( - oxyLogger = &OxyLogger{} - backend2FrontendMap map[string]string -) +var oxyLogger = &OxyLogger{} // Server is the reverse-proxy/load-balancer engine type Server struct { From 64b78461f6f4f1db4c07f5bf111495d1566d81aa Mon Sep 17 00:00:00 2001 From: David Tootill Date: Wed, 27 Apr 2016 09:25:13 -0700 Subject: [PATCH 5/6] Remove some debug logs (requested in review) --- integration/access_log_test.go | 2 +- middlewares/logger.go | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/integration/access_log_test.go b/integration/access_log_test.go index b48705134..ffa2b0ae8 100644 --- a/integration/access_log_test.go +++ b/integration/access_log_test.go @@ -84,7 +84,7 @@ func (s *AccessLogSuite) TestAccessLog(c *check.C) { c.Assert(count, checker.Equals, 3) } - // Verify no other Trarfik problems + // Verify no other Traefik problems if traefikLog, err := ioutil.ReadFile("traefik.log"); err != nil { c.Assert(err.Error(), checker.Equals, "") } else if len(traefikLog) > 0 { diff --git a/middlewares/logger.go b/middlewares/logger.go index f73f16965..ea2d228f7 100644 --- a/middlewares/logger.go +++ b/middlewares/logger.go @@ -73,7 +73,6 @@ func (l *Logger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.Ha next(rw, r) } else { reqid := strconv.FormatUint(atomic.AddUint64(&reqidCounter, 1), 10) - log.Debugf("Starting request %s: %s %s %s %s %s", reqid, r.Method, r.URL.RequestURI(), r.Proto, r.Referer(), r.UserAgent()) r.Header[loggerReqidHeader] = []string{reqid} defer deleteReqid(r, reqid) frontendBackendLoggingHandler{reqid, l.file, next}.ServeHTTP(rw, r) @@ -82,7 +81,6 @@ func (l *Logger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.Ha // Delete a reqid from the map and the request's headers func deleteReqid(r *http.Request, reqid string) { - log.Debugf("Ending request %s", reqid) infoRwMap.Remove(reqid) delete(r.Header, loggerReqidHeader) } From 53c99f746950fc11c55f7389ca30c2713e1e5aaa Mon Sep 17 00:00:00 2001 From: David Tootill Date: Wed, 27 Apr 2016 10:24:00 -0700 Subject: [PATCH 6/6] Add moul/http2curl to glide.yaml --- glide.lock | 6 ++++-- glide.yaml | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/glide.lock b/glide.lock index feba8bf8e..02fbf138d 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 301b972874166647c9a136a3b1a48fee9ce012b2dff1d1a7180be1c975074025 -updated: 2016-04-27T16:34:49.150609578Z +hash: a9f41b9fe89ac3028da27ac9cbe31db9a79ae89082f42507d4d0c58290517ee2 +updated: 2016-04-27T17:14:45.61228359Z imports: - name: github.com/alecthomas/template version: b867cc6ab45cece8143cfcc6fc9c77cf3f2c23c0 @@ -192,6 +192,8 @@ imports: version: dd83d5cbcfd986f334b2747feeb907e281318fdf - name: github.com/mitchellh/mapstructure version: d2dd0262208475919e1a362f675cfc0e7c10e905 +- name: github.com/moul/http2curl + version: 1812aee76a1ce98d604a44200c6a23c689b17a89 - name: github.com/opencontainers/runc version: 4ab132458fc3e9dbeea624153e0331952dc4c8d5 subpackages: diff --git a/glide.yaml b/glide.yaml index 0daf189cc..fbaa1e75d 100644 --- a/glide.yaml +++ b/glide.yaml @@ -184,3 +184,4 @@ import: - package: github.com/streamrail/concurrent-map - package: github.com/parnurzeal/gorequest - package: github.com/mattn/go-shellwords +- package: github.com/moul/http2curl