author | Alberto Bertogli
<albertito@blitiri.com.ar> 2016-05-28 12:13:19 UTC |
committer | Alberto Bertogli
<albertito@blitiri.com.ar> 2016-05-28 12:59:56 UTC |
parent | 9aee35b8d42c4a688bfd1703bf5428c345579cbe |
dnss.go | +73 | -4 |
monitoring_test.go | +48 | -0 |
diff --git a/dnss.go b/dnss.go index 58d9c5c..900579d 100644 --- a/dnss.go +++ b/dnss.go @@ -2,6 +2,7 @@ package main import ( "flag" + "fmt" "net/http" "strings" "sync" @@ -82,10 +83,7 @@ func main() { grpc.EnableTracing = false if *monitoringListenAddr != "" { - glog.Infof("Monitoring HTTP server listening on %s", - *monitoringListenAddr) - grpc.EnableTracing = true - go http.ListenAndServe(*monitoringListenAddr, nil) + launchMonitoringServer(*monitoringListenAddr) } if !*enableDNStoGRPC && !*enableGRPCtoDNS && !*enableDNStoHTTPS { @@ -149,3 +147,74 @@ func main() { wg.Wait() } + +func launchMonitoringServer(addr string) { + glog.Infof("Monitoring HTTP server listening on %s", addr) + grpc.EnableTracing = true + + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/" { + http.NotFound(w, r) + return + } + w.Write([]byte(monitoringHTMLIndex)) + }) + + flags := dumpFlags() + http.HandleFunc("/debug/flags", func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(flags)) + }) + + go http.ListenAndServe(addr, nil) +} + +// Static index for the monitoring website. +const monitoringHTMLIndex = `<!DOCTYPE html> +<html> + <head> + <title>dnss monitoring</title> + </head> + <body> + <h1>dnss monitoring</h1> + <ul> + <li><a href="/debug/requests">requests</a> + <small><a href="https://godoc.org/golang.org/x/net/trace"> + (ref)</a></small> + <ul> + <li><a href="/debug/requests?fam=dnstox&b=11">dnstox latency</a> + <li><a href="/debug/requests?fam=dnstox&b=0&exp=1">dnstox trace</a> + </ul> + <li><a href="/debug/dnstox/cache/dump">cache dump</a> + <li><a href="/debug/pprof">pprof</a> + <small><a href="https://golang.org/pkg/net/http/pprof/"> + (ref)</a></small> + <ul> + <li><a href="/debug/pprof/goroutine?debug=1">goroutines</a> + </ul> + <li><a href="/debug/flags">flags</a> + <li><a href="/debug/vars">public variables</a> + </ul> + </body> +</html> +` + +// dumpFlags to a string, for troubleshooting purposes. +func dumpFlags() string { + s := "" + visited := make(map[string]bool) + + // Print set flags first, then the rest. + flag.Visit(func(f *flag.Flag) { + s += fmt.Sprintf("-%s=%s\n", f.Name, f.Value.String()) + visited[f.Name] = true + }) + + s += "\n" + flag.VisitAll(func(f *flag.Flag) { + if !visited[f.Name] { + s += fmt.Sprintf("-%s=%s\n", f.Name, f.Value.String()) + } + }) + + return s +} diff --git a/monitoring_test.go b/monitoring_test.go new file mode 100644 index 0000000..e198e0b --- /dev/null +++ b/monitoring_test.go @@ -0,0 +1,48 @@ +package main + +// Tests for the monitoring server. +// +// Note that functional tests for dnss are in the testing/ directory, here we +// only test the monitoring server created in dnss.go. + +import ( + "net/http" + "testing" + + "google.golang.org/grpc" +) + +func TestMonitoringServer(t *testing.T) { + // TODO: Don't hard-code this. + const addr = "localhost:19395" + launchMonitoringServer(addr) + + if !grpc.EnableTracing { + t.Errorf("grpc tracing is disabled") + } + + checkGet(t, "http://"+addr+"/") + checkGet(t, "http://"+addr+"/debug/requests") + checkGet(t, "http://"+addr+"/debug/pprof/goroutine") + checkGet(t, "http://"+addr+"/debug/flags") + checkGet(t, "http://"+addr+"/debug/vars") + + // Check that we emit 404 for non-existing paths. + r, _ := http.Get("http://" + addr + "/doesnotexist") + if r.StatusCode != 404 { + t.Errorf("expected 404, got %s", r.Status) + } +} + +func checkGet(t *testing.T, url string) { + r, err := http.Get(url) + if err != nil { + t.Error(err) + return + } + + if r.StatusCode != 200 { + t.Errorf("%q - invalid status: %s", url, r.Status) + } + +}