Skip to content

Commit

Permalink
Added Prometheus support
Browse files Browse the repository at this point in the history
Removed old metrics / status endpoints and internal counters
  • Loading branch information
abh committed Apr 27, 2018
1 parent 7d058e4 commit 2c78478
Show file tree
Hide file tree
Showing 135 changed files with 22,540 additions and 5,327 deletions.
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

(dev branch; still in testing)

* Added Prometheus metrics support
* Removed /monitor websocket interface
* Removed /status and /status.json pages
* Support "closest" matching (instead of geo/asn labels) for A and AAAA records (Alex Bligh)
* Support for GeoIP2 databases (including IPv6 data and ASN databases)
* "Pluggable" targeting data support
Expand Down
59 changes: 53 additions & 6 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ docker-test: .PHONY
# test that we don't have missing dependencies
docker run --rm -v `pwd`:/go/src/github.com/abh/geodns \
-v /opt/local/share/GeoIP:/opt/local/share/GeoIP \
golang:1.10-alpine3.7 \
golang:1.10.1-alpine3.7 \
go test ./...

devel:
Expand All @@ -26,7 +26,9 @@ bench:
TARS=$(wildcard geodns-*-*.tar)

push: $(TARS) tmp-install.sh
rsync -avz tmp-install.sh $(TARS) x3.dev:webtmp/2018/02/
#rsync -avz tmp-install.sh $(TARS) x3.dev:webtmp/2018/04/
rsync tmp-install.sh $(TARS) $(DIST)/$(DISTSUB)/
$(DIST)/push

builds: linux-build linux-build-i386 freebsd-build push

Expand Down
5 changes: 1 addition & 4 deletions geodns.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ var (
flagLogFile = flag.String("logfile", "", "log to file")
flagPrivateDebug = flag.Bool("privatedebug", false, "Make debugging queries accepted only on loopback")

flagShowVersion = flag.Bool("version", false, "Show dnsconfig version")
flagShowVersion = flag.Bool("version", false, "Show GeoDNS version")

cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
memprofile = flag.String("memprofile", "", "write memory profile to this file")
Expand Down Expand Up @@ -215,9 +215,6 @@ func main() {
}
}

mon := monitor.NewMonitor(serverInfo)
go mon.Run()

srv := server.NewServer(serverInfo)

if qlc := Config.QueryLog; len(qlc.Path) > 0 {
Expand Down
159 changes: 3 additions & 156 deletions http.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
package main

import (
"encoding/json"
"fmt"
"html/template"
"io"
"log"
"net/http"
"runtime"
"sort"
"strconv"
"time"

"github.com/abh/geodns/monitor"
"github.com/abh/geodns/zones"
metrics "github.com/rcrowley/go-metrics"
"github.com/prometheus/client_golang/prometheus/promhttp"
)

type httpServer struct {
Expand Down Expand Up @@ -44,27 +39,6 @@ func (s ratesByCount) Less(i, j int) bool {
return ic > jc
}

type histogramData struct {
Max int64
Min int64
Mean float64
Pct90 float64
Pct99 float64
Pct999 float64
StdDev float64
}

func setupHistogramData(met metrics.Histogram, dat *histogramData) {
dat.Max = met.Max()
dat.Min = met.Min()
dat.Mean = met.Mean()
dat.StdDev = met.StdDev()
percentiles := met.Percentiles([]float64{0.90, 0.99, 0.999})
dat.Pct90 = percentiles[0]
dat.Pct99 = percentiles[1]
dat.Pct999 = percentiles[2]
}

func topParam(req *http.Request, def int) int {
req.ParseForm()

Expand All @@ -83,14 +57,14 @@ func topParam(req *http.Request, def int) int {
}

func NewHTTPServer(mm *zones.MuxManager, serverInfo *monitor.ServerInfo) *httpServer {

hs := &httpServer{
zones: mm,
mux: &http.ServeMux{},
serverInfo: serverInfo,
}
hs.mux.HandleFunc("/status", hs.StatusHandler())
hs.mux.HandleFunc("/status.json", hs.StatusJSONHandler())
hs.mux.HandleFunc("/", hs.mainServer)
hs.mux.Handle("/metrics", promhttp.Handler())

return hs
}
Expand All @@ -104,126 +78,6 @@ func (hs *httpServer) Run(listen string) {
log.Fatal(http.ListenAndServe(listen, &basicauth{h: hs.mux}))
}

func (hs *httpServer) StatusJSONHandler() func(http.ResponseWriter, *http.Request) {

info := serverInfo

return func(w http.ResponseWriter, req *http.Request) {

zonemetrics := make(map[string]metrics.Registry)

for name, zone := range hs.zones.Zones() {
zone.Lock()
zonemetrics[name] = zone.Metrics.Registry
zone.Unlock()
}

type statusData struct {
Version string
GoVersion string
Uptime int64
Platform string
Zones map[string]metrics.Registry
Global metrics.Registry
ID string
IP string
UUID string
Groups []string
}

uptime := int64(time.Since(info.Started).Seconds())

status := statusData{
Version: info.Version,
GoVersion: runtime.Version(),
Uptime: uptime,
Platform: runtime.GOARCH + "-" + runtime.GOOS,
Zones: zonemetrics,
Global: metrics.DefaultRegistry,
ID: hs.serverInfo.ID,
IP: hs.serverInfo.IP,
UUID: hs.serverInfo.UUID,
Groups: hs.serverInfo.Groups,
}

b, err := json.Marshal(status)
if err != nil {
http.Error(w, "Error encoding JSON", 500)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(b)
return
}
}

func (hs *httpServer) StatusHandler() func(http.ResponseWriter, *http.Request) {

type statusData struct {
Version string
Zones rates
Uptime DayDuration
Platform string
Global struct {
Queries metrics.Meter
Histogram histogramData
HistogramRecent histogramData
}
TopOption int
}

return func(w http.ResponseWriter, req *http.Request) {

topOption := topParam(req, 10)

rates := make(rates, 0)

for name, zone := range hs.zones.Zones() {
count := zone.Metrics.Queries.Count()
rates = append(rates, &rate{
Name: name,
Count: count,
Metrics: zone.Metrics,
})
}

sort.Sort(ratesByCount{rates})

uptime := DayDuration{time.Since(hs.serverInfo.Started)}

status := statusData{
Version: VERSION,
Zones: rates,
Uptime: uptime,
Platform: runtime.GOARCH + "-" + runtime.GOOS,
TopOption: topOption,
}

status.Global.Queries = metrics.Get("queries").(*metrics.StandardMeter).Snapshot()

setupHistogramData(metrics.Get("queries-histogram").(*metrics.StandardHistogram).Snapshot(), &status.Global.Histogram)

statusTemplate, err := FSString(development, "/templates/status.html")
if err != nil {
log.Println("Could not read template:", err)
w.WriteHeader(500)
return
}
tmpl, err := template.New("status_html").Parse(statusTemplate)

if err != nil {
str := fmt.Sprintf("Could not parse template: %s", err)
io.WriteString(w, str)
return
}

err = tmpl.Execute(w, status)
if err != nil {
log.Println("Status template error", err)
}
}
}

func (hs *httpServer) mainServer(w http.ResponseWriter, req *http.Request) {
if req.RequestURI != "/version" {
http.NotFound(w, req)
Expand All @@ -240,13 +94,6 @@ type basicauth struct {

func (b *basicauth) ServeHTTP(w http.ResponseWriter, r *http.Request) {

// don't request passwords for the websocket interface (for now)
// because 'wscat' doesn't support that.
if r.RequestURI == "/monitor" {
b.h.ServeHTTP(w, r)
return
}

cfgMutex.RLock()
user := Config.HTTP.User
password := Config.HTTP.Password
Expand Down
13 changes: 0 additions & 13 deletions http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (

"github.com/stretchr/testify/require"

"github.com/abh/geodns/server"
"github.com/abh/geodns/targeting"
"github.com/abh/geodns/targeting/geoip2"
"github.com/abh/geodns/zones"
Expand All @@ -22,9 +21,6 @@ func TestHTTP(t *testing.T) {
targeting.Setup(geoprovider)
}

// todo: less global metrics ...
server.NewMetrics()

mm, err := zones.NewMuxManager("dns", &zones.NilReg{})
if err != nil {
t.Fatalf("loading zones: %s", err)
Expand All @@ -48,13 +44,4 @@ func TestHTTP(t *testing.T) {
t.Fail()
}

res, err = http.Get(baseurl + "/status")
require.Nil(t, err)
page, _ = ioutil.ReadAll(res.Body)

// just check that template basically works
if !bytes.Contains(page, []byte("<html>")) {
t.Log("/status didn't include <html>")
t.Fail()
}
}
Loading

0 comments on commit 2c78478

Please sign in to comment.