aboutsummaryrefslogtreecommitdiffstats
path: root/http
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2020-01-11 23:31:16 +0100
committerMartin Polden <mpolden@mpolden.no>2020-01-11 23:37:01 +0100
commit6e9697ef071fceeae3fc9d1fe024034717fd47a2 (patch)
treea03c712b14eafbb13229805deb298d5ca586c86b /http
parent0281da919acf94402047fd2e185a82b52fad1c23 (diff)
Implement basic metrics
Diffstat (limited to 'http')
-rw-r--r--http/http.go56
-rw-r--r--http/http_test.go8
2 files changed, 54 insertions, 10 deletions
diff --git a/http/http.go b/http/http.go
index 053435f..3bf047c 100644
--- a/http/http.go
+++ b/http/http.go
@@ -33,12 +33,35 @@ type entry struct {
Rcode string `json:"rcode,omitempty"`
}
+type summary struct {
+ Since string `json:"since"`
+ Total int64 `json:"total"`
+ Hijacked int64 `json:"hijacked"`
+}
+
+type request struct {
+ Time string `json:"time"`
+ Count int64 `json:"count"`
+}
+
+type logStats struct {
+ Summary summary `json:"summary"`
+ Requests []request `json:"requests"`
+}
+
type httpError struct {
err error
Status int `json:"status"`
Message string `json:"message"`
}
+func newHTTPError(err error) *httpError {
+ return &httpError{
+ err: err,
+ Status: http.StatusInternalServerError,
+ }
+}
+
// NewServer creates a new HTTP server, serving logs from the given logger and listening on addr.
func NewServer(cache *cache.Cache, logger *sql.Logger, addr string) *Server {
server := &http.Server{Addr: addr}
@@ -55,6 +78,7 @@ func (s *Server) handler() http.Handler {
r := newRouter()
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)
return r.handler()
}
@@ -89,18 +113,13 @@ func (s *Server) cacheResetHandler(w http.ResponseWriter, r *http.Request) (inte
s.cache.Reset()
return struct {
Message string `json:"message"`
- }{
- "Cleared cache",
- }, nil
+ }{"Cleared cache."}, nil
}
func (s *Server) logHandler(w http.ResponseWriter, r *http.Request) (interface{}, *httpError) {
logEntries, err := s.logger.Read(listCountFrom(r))
if err != nil {
- return nil, &httpError{
- err: err,
- Status: http.StatusInternalServerError,
- }
+ return nil, newHTTPError(err)
}
entries := make([]entry, 0, len(logEntries))
for _, le := range logEntries {
@@ -117,6 +136,29 @@ func (s *Server) logHandler(w http.ResponseWriter, r *http.Request) (interface{}
return entries, nil
}
+func (s *Server) metricHandler(w http.ResponseWriter, r *http.Request) (interface{}, *httpError) {
+ stats, err := s.logger.Stats()
+ if err != nil {
+ return nil, newHTTPError(err)
+ }
+ requests := make([]request, 0, len(stats.Events))
+ for _, e := range stats.Events {
+ requests = append(requests, request{
+ Time: e.Time.Format(time.RFC3339),
+ Count: e.Count,
+ })
+ }
+ logStats := logStats{
+ Summary: summary{
+ Since: stats.Since.Format(time.RFC3339),
+ Total: stats.Total,
+ Hijacked: stats.Hijacked,
+ },
+ Requests: requests,
+ }
+ return logStats, nil
+}
+
// Close shuts down the HTTP server.
func (s *Server) Close() error { return s.server.Shutdown(context.TODO()) }
diff --git a/http/http_test.go b/http/http_test.go
index 7cd5a9c..901903f 100644
--- a/http/http_test.go
+++ b/http/http_test.go
@@ -30,11 +30,11 @@ func newA(name string, ttl uint32, ipAddr ...net.IP) *dns.Msg {
}
func testServer() (*httptest.Server, *Server) {
- db, err := sql.New(":memory:")
+ sqlClient, err := sql.New(":memory:")
if err != nil {
panic(err)
}
- logger := sql.NewLogger(db, sql.LogAll, 0)
+ logger := sql.NewLogger(sqlClient, sql.LogAll, 0)
cache := cache.New(10, nil)
server := Server{logger: logger, cache: cache}
return httptest.NewServer(server.handler()), &server
@@ -89,6 +89,7 @@ func TestRequests(t *testing.T) {
lr1 := `[{"time":"RFC3339","remote_addr":"127.0.0.254","hijacked":true,"type":"AAAA","question":"example.com.","answers":["2001:db8::1"]},` +
`{"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":{"since":"RFC3339","total":2,"hijacked":1},"requests":[{"time":"RFC3339","count":2}]}`
var tests = []struct {
method string
@@ -103,7 +104,8 @@ func TestRequests(t *testing.T) {
{http.MethodGet, "/cache/v1/", cr1, 200},
{http.MethodGet, "/cache/v1/?n=foo", cr1, 200},
{http.MethodGet, "/cache/v1/?n=1", cr2, 200},
- {http.MethodDelete, "/cache/v1/", `{"message":"Cleared cache"}`, 200},
+ {http.MethodDelete, "/cache/v1/", `{"message":"Cleared cache."}`, 200},
+ {http.MethodGet, "/metric/v1/", mr1, 200},
}
for i, tt := range tests {