From 2b0e1fd1705840f14eb1df5a4ed5a871045f996d Mon Sep 17 00:00:00 2001 From: ale <ale@incal.net> Date: Sun, 18 Jan 2015 07:28:47 +0000 Subject: [PATCH] add debug page for lbv2 --- fe/http.go | 10 +++--- fe/http_debug.go | 2 +- fe/http_test.go | 10 ++++++ fe/lbv2/debug.go | 80 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 fe/lbv2/debug.go diff --git a/fe/http.go b/fe/http.go index 73d8f392..89cd8fce 100644 --- a/fe/http.go +++ b/fe/http.go @@ -316,10 +316,12 @@ func (h *HttpRedirector) createHandler() http.Handler { nil)) // Pass /debug/ to the default ServeMux, all the default debug - // handlers are installed there. - mux.Handle( - "/debug/", - handlers.GZIPHandler(http.DefaultServeMux, nil)) + // handlers are installed there. Add a debug handler for the + // LoadBalancer data. Gzip the responses. + debugMux := http.NewServeMux() + debugMux.Handle("/debug/lbv2", h.lb) + debugMux.Handle("/", http.DefaultServeMux) + mux.Handle("/debug/", handlers.GZIPHandler(debugMux, nil)) // Optionally enable a reverse proxy to the local Icecast for // the direct stream URLs (below IcecastMountPrefix). diff --git a/fe/http_debug.go b/fe/http_debug.go index 4861be2a..cb656ef3 100644 --- a/fe/http_debug.go +++ b/fe/http_debug.go @@ -2,10 +2,10 @@ package fe import ( "fmt" + "html/template" "net/http" "sort" "sync" - "text/template" "time" ) diff --git a/fe/http_test.go b/fe/http_test.go index 531e5919..2b849fc6 100644 --- a/fe/http_test.go +++ b/fe/http_test.go @@ -103,6 +103,16 @@ func TestHttpRedirector_Static(t *testing.T) { } } +func TestHttpRedirector_LBDebugPage(t *testing.T) { + _, srv := createTestHttpServer(t) + defer srv.Close() + + data := doHttpRequest(t, "GET", srv.URL+"/debug/lbv2", 200) + if !strings.Contains(data, "node1") { + t.Errorf("Bad response:\n%s", data) + } +} + type httpTestContext struct { srv *httptest.Server targetSrv *httptest.Server diff --git a/fe/lbv2/debug.go b/fe/lbv2/debug.go new file mode 100644 index 00000000..6bf69cdd --- /dev/null +++ b/fe/lbv2/debug.go @@ -0,0 +1,80 @@ +package lbv2 + +import ( + "fmt" + "html/template" + "net/http" +) + +const debugText = `<html> + <body> + <title>Load Balancer</title> + + <h3>Query costs</h3> + <table> + <tr><th>Node</th><th>Requests</th><th>Utilization/Cost</th></tr> + {{$dimensions := .Dimensions}} + {{range .Nodes}} + <tr> + <td>{{.Name}}</td> + <td>{{.Requests}}</td> + {{range $d := $dimensions}} + {{$data := index .Data $d}} + <td> + {{$data.PredictedUtilization}}/{{$data.ReportedUtilization}}/{{$data.Cost}} + </td> + {{end}} + </tr> + {{end}} + </table> + </body> + </html>` + +var debugTmpl = template.Must(template.New("lbv2 debug").Parse(debugText)) + +type nodeDebugData struct { + Name string + Requests int + Data map[int]costAndUtil +} + +type costAndUtil struct { + ReportedUtilization float64 + PredictedUtilization float64 + Cost float64 +} + +func (l *LoadBalancer) ServeHTTP(w http.ResponseWriter, r *http.Request) { + // Build a view of the cost/utilization data. + l.lock.Lock() + var nodes []nodeDebugData + for _, n := range l.nodes { + ndata := nodeDebugData{Name: n.Name(), Data: make(map[int]costAndUtil)} + for dim, pred := range l.predictors { + util := n.Utilization(dim) + ndata.Requests = util.Requests + ndata.Data[dim] = costAndUtil{ + ReportedUtilization: util.Utilization, + PredictedUtilization: pred.Utilization(n), + Cost: float64(pred.cost[n.Name()]), + } + } + nodes = append(nodes, ndata) + } + var dimensions []int + for dim := range l.predictors { + dimensions = append(dimensions, dim) + } + l.lock.Unlock() + + ctx := struct { + Nodes []nodeDebugData + Dimensions []int + NumDimensions int + }{nodes, dimensions, len(dimensions)} + + err := debugTmpl.Execute(w, ctx) + if err != nil { + fmt.Fprintln(w, "debug: error executing template: ", err.Error()) + } +} -- GitLab