aboutsummaryrefslogtreecommitdiffstats
path: root/http
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2020-06-24 18:58:36 +0200
committerMartin Polden <mpolden@mpolden.no>2020-06-24 19:21:28 +0200
commit4bff6d85a46fd18c210f6a7d4a60136eda43bc24 (patch)
tree13a4ef5925a9dc72052d2f989b03e8739f62e3ce /http
parent052fd5a399819081fb826b152bba13eb6faea705 (diff)
http: Add runtime metrics
Diffstat (limited to 'http')
-rw-r--r--http/http.go35
-rw-r--r--http/http_test.go16
-rw-r--r--http/prometheus.go19
3 files changed, 37 insertions, 33 deletions
diff --git a/http/http.go b/http/http.go
index e783319..5ff5fd3 100644
--- a/http/http.go
+++ b/http/http.go
@@ -1,11 +1,9 @@
package http
import (
- "bytes"
"context"
"encoding/json"
"fmt"
- "io"
"log"
"net"
"net/http"
@@ -22,7 +20,7 @@ const (
jsonMediaType = "application/json"
)
-// A Server defines paramaters for running an HTTP server. The HTTP server serves an API for inspecting cache contents
+// A Server defines parameters for running an HTTP server. The HTTP server serves an API for inspecting cache contents
// and request log.
type Server struct {
cache *cache.Cache
@@ -99,10 +97,10 @@ func newHTTPBadRequest(err error) *httpError {
func NewServer(cache *cache.Cache, logger *sql.Logger, sqlCache *sql.Cache, addr string) *Server {
server := &http.Server{Addr: addr}
s := &Server{
+ server: server,
cache: cache,
logger: logger,
sqlCache: sqlCache,
- server: server,
}
s.server.Handler = s.handler()
return s
@@ -111,9 +109,11 @@ func NewServer(cache *cache.Cache, logger *sql.Logger, sqlCache *sql.Cache, addr
func (s *Server) handler() http.Handler {
r := &router{}
r.route(http.MethodGet, "/cache/v1/", s.cacheHandler)
- r.route(http.MethodGet, "/log/v1/", s.logHandler)
- r.route(http.MethodGet, "/metric/v1/", s.metricHandler)
r.route(http.MethodDelete, "/cache/v1/", s.cacheResetHandler)
+ if s.logger != nil {
+ r.route(http.MethodGet, "/log/v1/", s.logHandler)
+ r.route(http.MethodGet, "/metric/v1/", s.metricHandler)
+ }
return r.handler()
}
@@ -148,21 +148,6 @@ func writeJSON(w http.ResponseWriter, data interface{}) {
w.Write(b)
}
-func writeMetric(w io.StringWriter, name, help string, value int64) {
- w.WriteString("# HELP ")
- w.WriteString(name)
- w.WriteString(" ")
- w.WriteString(help)
- w.WriteString("\n")
- w.WriteString("# TYPE ")
- w.WriteString(name)
- w.WriteString(" gauge\n")
- w.WriteString(name)
- w.WriteString(" ")
- w.WriteString(strconv.FormatInt(value, 10))
- w.WriteString("\n")
-}
-
func (s *Server) cacheHandler(w http.ResponseWriter, r *http.Request) *httpError {
count, err := countFrom(r)
if err != nil {
@@ -268,11 +253,9 @@ func (s *Server) prometheusMetricHandler(w http.ResponseWriter, r *http.Request)
if err != nil {
return newHTTPError(err)
}
- var buf bytes.Buffer
- writeMetric(&buf, "zdns_requests_total", "The total number of DNS requests.", lstats.Total)
- writeMetric(&buf, "zdns_requests_hijacked", "The number of hijacked DNS requests.", lstats.Hijacked)
- w.Header().Set("Content-Type", "text/plain; version=0.0.4")
- w.Write(buf.Bytes())
+ totalRequestsGauge.Set(float64(lstats.Total))
+ hijackedRequestsGauge.Set(float64(lstats.Hijacked))
+ prometheusHandler.ServeHTTP(w, r)
return nil
}
diff --git a/http/http_test.go b/http/http_test.go
index 905e338..ac95697 100644
--- a/http/http_test.go
+++ b/http/http_test.go
@@ -37,8 +37,8 @@ func testServer() (*httptest.Server, *Server) {
logger := sql.NewLogger(sqlClient, sql.LogAll, 0)
sqlCache := sql.NewCache(sqlClient)
cache := cache.New(10, nil)
- server := Server{logger: logger, cache: cache, sqlCache: sqlCache}
- return httptest.NewServer(server.handler()), &server
+ server := NewServer(cache, logger, sqlCache, "")
+ return httptest.NewServer(server.handler()), server
}
func httpGet(url string) (*http.Response, string, error) {
@@ -91,14 +91,15 @@ func TestRequests(t *testing.T) {
`{"time":"RFC3339","remote_addr":"127.0.0.42","hijacked":false,"type":"A","question":"example.com.","answers":["192.0.2.101","192.0.2.100"]}]`
lr2 := `[{"time":"RFC3339","remote_addr":"127.0.0.254","hijacked":true,"type":"AAAA","question":"example.com.","answers":["2001:db8::1"]}]`
mr1 := `{"summary":{"log":{"since":"RFC3339","total":2,"hijacked":1,"pending_tasks":0},"cache":{"size":2,"capacity":10,"pending_tasks":0,"backend":{"pending_tasks":0}}},"requests":[{"time":"RFC3339","count":2}]}`
- mr2 := `# HELP zdns_requests_total The total number of DNS requests.
-# TYPE zdns_requests_total gauge
-zdns_requests_total 2
+ mr2 := `
+<ANY>
# HELP zdns_requests_hijacked The number of hijacked DNS requests.
# TYPE zdns_requests_hijacked gauge
zdns_requests_hijacked 1
+# HELP zdns_requests_total The total number of DNS requests.
+# TYPE zdns_requests_total gauge
+zdns_requests_total 2
`
-
var tests = []struct {
method string
url string
@@ -115,7 +116,7 @@ zdns_requests_hijacked 1
{http.MethodGet, "/cache/v1/?n=1", cr2, 200, jsonMediaType},
{http.MethodGet, "/metric/v1/", mr1, 200, jsonMediaType},
{http.MethodGet, "/metric/v1/?format=basic", mr1, 200, jsonMediaType},
- {http.MethodGet, "/metric/v1/?format=prometheus", mr2, 200, "text/plain; version=0.0.4"},
+ {http.MethodGet, "/metric/v1/?format=prometheus", mr2, 200, "text/plain; version=0.0.4; charset=utf-8"},
{http.MethodGet, "/metric/v1/?resolution=1m", mr1, 200, jsonMediaType},
{http.MethodGet, "/metric/v1/?resolution=0", mr1, 200, jsonMediaType},
{http.MethodGet, "/metric/v1/?format=foo", `{"status":400,"message":"invalid metric format: foo"}`, 400, jsonMediaType},
@@ -151,6 +152,7 @@ zdns_requests_hijacked 1
got := string(data)
want := regexp.QuoteMeta(tt.response)
want = strings.ReplaceAll(want, "RFC3339", `\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z`)
+ want = strings.ReplaceAll(want, "<ANY>", ".*")
matched, err := regexp.MatchString(want, got)
if err != nil {
t.Fatal(err)
diff --git a/http/prometheus.go b/http/prometheus.go
new file mode 100644
index 0000000..7b78055
--- /dev/null
+++ b/http/prometheus.go
@@ -0,0 +1,19 @@
+package http
+
+import (
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/promauto"
+ "github.com/prometheus/client_golang/prometheus/promhttp"
+)
+
+var (
+ totalRequestsGauge = promauto.NewGauge(prometheus.GaugeOpts{
+ Name: "zdns_requests_total",
+ Help: "The total number of DNS requests.",
+ })
+ hijackedRequestsGauge = promauto.NewGauge(prometheus.GaugeOpts{
+ Name: "zdns_requests_hijacked",
+ Help: "The number of hijacked DNS requests.",
+ })
+ prometheusHandler = promhttp.Handler()
+)