Refactored the unbound histogram metrics from gauge metrics into

Prometheus cumulative histogram metrics.

Fixes: #4
This commit is contained in:
Bart Vercoulen 2017-10-19 16:08:41 +02:00
parent f538243789
commit 11f53c8612
2 changed files with 41 additions and 8 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
unbound_exporter unbound_exporter
.idea/

View File

@ -29,6 +29,7 @@ import (
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/log" "github.com/prometheus/common/log"
"sort"
) )
var ( var (
@ -37,6 +38,11 @@ var (
"Whether scraping Unbound's metrics was successful.", "Whether scraping Unbound's metrics was successful.",
nil, nil) nil, nil)
unboundHistogram = prometheus.NewDesc(
prometheus.BuildFQName("unbound", "", "response_time_seconds"),
"Query response time in seconds.",
nil, nil)
unboundMetrics = []*unboundMetric{ unboundMetrics = []*unboundMetric{
newUnboundMetric( newUnboundMetric(
"answer_rcodes_total", "answer_rcodes_total",
@ -176,12 +182,6 @@ var (
prometheus.CounterValue, prometheus.CounterValue,
[]string{"thread"}, []string{"thread"},
"^thread(\\d+)\\.num\\.recursivereplies$"), "^thread(\\d+)\\.num\\.recursivereplies$"),
newUnboundMetric(
"response_time_seconds_bucket",
"Histogram buckets for query response time in seconds.",
prometheus.CounterValue,
[]string{"le"},
"^histogram\\.\\d+\\.\\d+\\.to\\.0*(\\d+\\.\\d+?)0*$"),
newUnboundMetric( newUnboundMetric(
"rrset_bogus_total", "rrset_bogus_total",
"Total number of rrsets marked bogus by the validator.", "Total number of rrsets marked bogus by the validator.",
@ -242,6 +242,11 @@ func newUnboundMetric(name string, description string, valueType prometheus.Valu
func CollectFromReader(file io.Reader, ch chan<- prometheus.Metric) error { func CollectFromReader(file io.Reader, ch chan<- prometheus.Metric) error {
scanner := bufio.NewScanner(file) scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines) scanner.Split(bufio.ScanLines)
histogramPattern := regexp.MustCompile("^histogram\\.(\\d+\\.\\d+)\\.to\\.(\\d+\\.\\d+)$")
histogramCount := uint64(0)
histogramSum := float64(0)
histogramBuckets := make(map[float64]uint64)
for scanner.Scan() { for scanner.Scan() {
fields := strings.Split(scanner.Text(), "=") fields := strings.Split(scanner.Text(), "=")
@ -252,8 +257,7 @@ func CollectFromReader(file io.Reader, ch chan<- prometheus.Metric) error {
} }
for _, metric := range unboundMetrics { for _, metric := range unboundMetrics {
matches := metric.pattern.FindStringSubmatch(fields[0]) if matches := metric.pattern.FindStringSubmatch(fields[0]); matches != nil {
if matches != nil {
value, err := strconv.ParseFloat(fields[1], 64) value, err := strconv.ParseFloat(fields[1], 64)
if err != nil { if err != nil {
return err return err
@ -267,7 +271,35 @@ func CollectFromReader(file io.Reader, ch chan<- prometheus.Metric) error {
break break
} }
} }
if matches := histogramPattern.FindStringSubmatch(fields[0]); matches != nil {
begin, _ := strconv.ParseFloat(matches[1], 64)
end, _ := strconv.ParseFloat(matches[2], 64)
value, err := strconv.ParseUint(fields[1], 10, 64)
if err != nil {
return err
}
histogramBuckets[end] = value
histogramCount += value
// There are no real data points to calculate the sum in the unbound stats
// Therefore the mean latency times the amount of samples is calculated and summed
histogramSum += (end - begin) * float64(value)
}
} }
// Convert the metrics to a cumulative prometheus histogram
keys := []float64{}
for k := range histogramBuckets {
keys = append(keys, k)
}
sort.Float64s(keys)
prev := uint64(0)
for _, i := range keys {
histogramBuckets[i] += prev
prev = histogramBuckets[i]
}
ch <- prometheus.MustNewConstHistogram(unboundHistogram, histogramCount, histogramSum, histogramBuckets)
return scanner.Err() return scanner.Err()
} }