Skip to content
Snippets Groups Projects
Commit 2b0e1fd1 authored by ale's avatar ale
Browse files

add debug page for lbv2

parent 292e4e71
No related branches found
No related tags found
No related merge requests found
......@@ -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).
......
......@@ -2,10 +2,10 @@ package fe
import (
"fmt"
"html/template"
"net/http"
"sort"
"sync"
"text/template"
"time"
)
......
......@@ -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
......
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())
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment