diff options
Diffstat (limited to 'middleware/prometheus')
-rw-r--r-- | middleware/prometheus/handler.go | 31 | ||||
-rw-r--r-- | middleware/prometheus/metrics.go | 80 |
2 files changed, 111 insertions, 0 deletions
diff --git a/middleware/prometheus/handler.go b/middleware/prometheus/handler.go new file mode 100644 index 000000000..eb82b8aff --- /dev/null +++ b/middleware/prometheus/handler.go @@ -0,0 +1,31 @@ +package metrics + +import ( + "strconv" + "time" + + "github.com/miekg/coredns/middleware" + "github.com/miekg/dns" +) + +func (m *Metrics) ServeDNS(w dns.ResponseWriter, r *dns.Msg) (int, error) { + context := middleware.Context{W: w, Req: r} + + qname := context.Name() + qtype := context.Type() + zone := middleware.Zones(m.ZoneNames).Matches(qname) + if zone == "" { + zone = "." + } + + // Record response to get status code and size of the reply. + rw := middleware.NewResponseRecorder(w) + status, err := m.Next.ServeDNS(rw, r) + + requestCount.WithLabelValues(zone, qtype).Inc() + requestDuration.WithLabelValues(zone).Observe(float64(time.Since(rw.Start()) / time.Second)) + responseSize.WithLabelValues(zone).Observe(float64(rw.Size())) + responseRcode.WithLabelValues(zone, strconv.Itoa(rw.Rcode())).Inc() + + return status, err +} diff --git a/middleware/prometheus/metrics.go b/middleware/prometheus/metrics.go new file mode 100644 index 000000000..4c989f640 --- /dev/null +++ b/middleware/prometheus/metrics.go @@ -0,0 +1,80 @@ +package metrics + +import ( + "fmt" + "net/http" + "sync" + + "github.com/miekg/coredns/middleware" + "github.com/prometheus/client_golang/prometheus" +) + +const namespace = "daddy" + +var ( + requestCount *prometheus.CounterVec + requestDuration *prometheus.HistogramVec + responseSize *prometheus.HistogramVec + responseRcode *prometheus.CounterVec +) + +const path = "/metrics" + +// Metrics holds the prometheus configuration. The metrics' path is fixed to be /metrics +type Metrics struct { + Next middleware.Handler + Addr string // where to we listen + Once sync.Once + ZoneNames []string +} + +func (m *Metrics) Start() error { + m.Once.Do(func() { + define("") + + prometheus.MustRegister(requestCount) + prometheus.MustRegister(requestDuration) + prometheus.MustRegister(responseSize) + prometheus.MustRegister(responseRcode) + + http.Handle(path, prometheus.Handler()) + go func() { + fmt.Errorf("%s", http.ListenAndServe(m.Addr, nil)) + }() + }) + return nil +} + +func define(subsystem string) { + if subsystem == "" { + subsystem = "dns" + } + requestCount = prometheus.NewCounterVec(prometheus.CounterOpts{ + Namespace: namespace, + Subsystem: subsystem, + Name: "request_count_total", + Help: "Counter of DNS requests made per zone and type.", + }, []string{"zone", "qtype"}) + + requestDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Namespace: namespace, + Subsystem: subsystem, + Name: "request_duration_seconds", + Help: "Histogram of the time (in seconds) each request took.", + }, []string{"zone"}) + + responseSize = prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Namespace: namespace, + Subsystem: subsystem, + Name: "response_size_bytes", + Help: "Size of the returns response in bytes.", + Buckets: []float64{0, 100, 200, 300, 400, 511, 1023, 2047, 4095, 8291, 16e3, 32e3, 48e3, 64e3}, + }, []string{"zone"}) + + responseRcode = prometheus.NewCounterVec(prometheus.CounterOpts{ + Namespace: namespace, + Subsystem: subsystem, + Name: "rcode_code_count_total", + Help: "Counter of response status codes.", + }, []string{"zone", "rcode"}) +} |