git » debian:dnss » commit 0032ea8

dnss: Extend the monitoring server with an index and flag dump

author Alberto Bertogli
2016-05-28 12:13:19 UTC
committer Alberto Bertogli
2016-05-28 12:59:56 UTC
parent 9aee35b8d42c4a688bfd1703bf5428c345579cbe

dnss: Extend the monitoring server with an index and flag dump

This patch extends the monitoring server, adding a small index for
convenience, a handler to dump flags, and some tests.

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)
+	}
+
+}