You've already forked bind_exporter
mirror of
https://github.com/prometheus-community/bind_exporter.git
synced 2025-07-30 10:23:05 +03:00
Extract bind statistics parsing in sub-packages
This prepares the addition of statistics v3 parsing.
This commit is contained in:
0
CHANGELOG.md
Normal file
0
CHANGELOG.md
Normal file
60
bind/client.go
Normal file
60
bind/client.go
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package bind
|
||||||
|
|
||||||
|
// Client queries the BIND API, parses the response and returns stats in a
|
||||||
|
// generic format.
|
||||||
|
type Client interface {
|
||||||
|
Stats() (Statistics, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Common bind field types.
|
||||||
|
const (
|
||||||
|
QryRTT = "QryRTT"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Statistics is a generic representation of BIND statistics.
|
||||||
|
type Statistics struct {
|
||||||
|
Server struct {
|
||||||
|
IncomingQueries []Stat
|
||||||
|
IncomingRequests []Stat
|
||||||
|
NSStats []Stat
|
||||||
|
}
|
||||||
|
Views []View
|
||||||
|
TaskManager TaskManager
|
||||||
|
}
|
||||||
|
|
||||||
|
// View represents a statistics for a single BIND view.
|
||||||
|
type View struct {
|
||||||
|
Name string
|
||||||
|
Cache []Stat
|
||||||
|
ResolverStats []Stat
|
||||||
|
ResolverQueries []Stat
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stat represents a single counter value.
|
||||||
|
type Stat struct {
|
||||||
|
Name string
|
||||||
|
Counter uint
|
||||||
|
}
|
||||||
|
|
||||||
|
// Task represents a single running task.
|
||||||
|
type Task struct {
|
||||||
|
ID string `xml:"id"`
|
||||||
|
Name string `xml:"name"`
|
||||||
|
Quantum uint `xml:"quantum"`
|
||||||
|
References uint `xml:"references"`
|
||||||
|
State string `xml:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TaskManager contains information about all running tasks.
|
||||||
|
type TaskManager struct {
|
||||||
|
Tasks []Task `xml:"tasks>task"`
|
||||||
|
ThreadModel ThreadModel `xml:"thread-model"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ThreadModel contains task and worker information.
|
||||||
|
type ThreadModel struct {
|
||||||
|
Type string `xml:"type"`
|
||||||
|
WorkerThreads uint `xml:"worker-threads"`
|
||||||
|
DefaultQuantum uint `xml:"default-quantum"`
|
||||||
|
TasksRunning uint `xml:"tasks-running"`
|
||||||
|
}
|
@ -1,19 +1,15 @@
|
|||||||
package main
|
package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
"github.com/digitalocean/bind_exporter/bind"
|
||||||
qryRTT = "QryRTT"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Zone struct {
|
type Zone struct {
|
||||||
Name string `xml:"name"`
|
Name string `xml:"name"`
|
||||||
Rdataclass string `xml:"rdataclass"`
|
Rdataclass string `xml:"rdataclass"`
|
||||||
Serial string `xml:"serial"`
|
Serial string `xml:"serial"`
|
||||||
//TODO a zone can also have a huge number of counters
|
|
||||||
// <counters>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Stat struct {
|
type Stat struct {
|
||||||
@ -42,26 +38,6 @@ type Socketmgr struct {
|
|||||||
Sockets []Socket `xml:"sockets>socket"`
|
Sockets []Socket `xml:"sockets>socket"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Task struct {
|
|
||||||
ID string `xml:"id"`
|
|
||||||
Name string `xml:"name"`
|
|
||||||
Quantum uint `xml:"quantum"`
|
|
||||||
References uint `xml:"references"`
|
|
||||||
State string `xml:"state"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ThreadModel struct {
|
|
||||||
Type string `xml:"type"`
|
|
||||||
WorkerThreads uint `xml:"worker-threads"`
|
|
||||||
DefaultQuantum uint `xml:"default-quantum"`
|
|
||||||
TasksRunning uint `xml:"tasks-running"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Taskmgr struct {
|
|
||||||
Tasks []Task `xml:"tasks>task"`
|
|
||||||
ThreadModel ThreadModel `xml:"thread-model"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type QueriesIn struct {
|
type QueriesIn struct {
|
||||||
Rdtype []Stat `xml:"rdtype"`
|
Rdtype []Stat `xml:"rdtype"`
|
||||||
}
|
}
|
||||||
@ -71,24 +47,20 @@ type Requests struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
Requests Requests `xml:"requests"` //Most important stats
|
Requests Requests `xml:"requests"`
|
||||||
QueriesIn QueriesIn `xml:"queries-in"` //Most important stats
|
QueriesIn QueriesIn `xml:"queries-in"`
|
||||||
|
|
||||||
NsStats []Stat `xml:"nsstat"`
|
NsStats []Stat `xml:"nsstat"`
|
||||||
SocketStats []Stat `xml:"socketstat"`
|
SocketStats []Stat `xml:"socketstat"`
|
||||||
ZoneStats []Stat `xml:"zonestats"`
|
ZoneStats []Stat `xml:"zonestats"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Memory struct {
|
|
||||||
//TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
type Statistics struct {
|
type Statistics struct {
|
||||||
Views []View `xml:"views>view"`
|
Views []View `xml:"views>view"`
|
||||||
Socketmgr Socketmgr `xml:"socketmgr"`
|
Socketmgr Socketmgr `xml:"socketmgr"`
|
||||||
Taskmgr Taskmgr `xml:"taskmgr"`
|
Taskmgr bind.TaskManager `xml:"taskmgr"`
|
||||||
Server Server `xml:"server"`
|
Server Server `xml:"server"`
|
||||||
Memory Memory `xml:"memory"`
|
Memory struct{} `xml:"memory"`
|
||||||
}
|
}
|
||||||
type Bind struct {
|
type Bind struct {
|
||||||
Statistics Statistics `xml:"statistics"`
|
Statistics Statistics `xml:"statistics"`
|
79
bind/v2/v2.go
Normal file
79
bind/v2/v2.go
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
package v2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/xml"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/digitalocean/bind_exporter/bind"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Client implements bind.Client and can be used to query a BIND v2 API.
|
||||||
|
type Client struct {
|
||||||
|
url string
|
||||||
|
http *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient returns an initialized Client.
|
||||||
|
func NewClient(url string, c *http.Client) *Client {
|
||||||
|
return &Client{
|
||||||
|
url: url,
|
||||||
|
http: c,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stats implements bind.Stats.
|
||||||
|
func (c *Client) Stats() (bind.Statistics, error) {
|
||||||
|
s := bind.Statistics{}
|
||||||
|
|
||||||
|
resp, err := c.http.Get(c.url)
|
||||||
|
if err != nil {
|
||||||
|
return s, fmt.Errorf("error querying stats: %s", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return s, fmt.Errorf("failed to read response: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
root := Isc{}
|
||||||
|
if err := xml.Unmarshal([]byte(body), &root); err != nil {
|
||||||
|
return s, fmt.Errorf("Failed to unmarshal XML response: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stats := root.Bind.Statistics
|
||||||
|
for _, t := range stats.Server.QueriesIn.Rdtype {
|
||||||
|
s.Server.IncomingQueries = append(s.Server.IncomingQueries, stat(t))
|
||||||
|
}
|
||||||
|
for _, t := range stats.Server.Requests.Opcode {
|
||||||
|
s.Server.IncomingRequests = append(s.Server.IncomingRequests, stat(t))
|
||||||
|
}
|
||||||
|
for _, t := range stats.Server.NsStats {
|
||||||
|
s.Server.NSStats = append(s.Server.NSStats, stat(t))
|
||||||
|
}
|
||||||
|
for _, view := range stats.Views {
|
||||||
|
v := bind.View{Name: view.Name}
|
||||||
|
for _, t := range view.Cache {
|
||||||
|
v.Cache = append(v.Cache, stat(t))
|
||||||
|
}
|
||||||
|
for _, t := range view.Rdtype {
|
||||||
|
v.ResolverQueries = append(v.ResolverQueries, stat(t))
|
||||||
|
}
|
||||||
|
for _, t := range view.Resstat {
|
||||||
|
v.ResolverStats = append(v.ResolverStats, stat(t))
|
||||||
|
}
|
||||||
|
s.Views = append(s.Views, v)
|
||||||
|
}
|
||||||
|
s.TaskManager = stats.Taskmgr
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func stat(s Stat) bind.Stat {
|
||||||
|
return bind.Stat{
|
||||||
|
Name: s.Name,
|
||||||
|
Counter: s.Counter,
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,10 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/xml"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math"
|
"math"
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
_ "net/http/pprof"
|
_ "net/http/pprof"
|
||||||
"os"
|
"os"
|
||||||
@ -14,6 +12,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/digitalocean/bind_exporter/bind"
|
||||||
|
"github.com/digitalocean/bind_exporter/bind/v2"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/common/log"
|
"github.com/prometheus/common/log"
|
||||||
"github.com/prometheus/common/version"
|
"github.com/prometheus/common/version"
|
||||||
@ -38,7 +39,7 @@ var (
|
|||||||
incomingRequests = prometheus.NewDesc(
|
incomingRequests = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(namespace, "", "incoming_requests_total"),
|
prometheus.BuildFQName(namespace, "", "incoming_requests_total"),
|
||||||
"Number of incomming DNS requests.",
|
"Number of incomming DNS requests.",
|
||||||
[]string{"name"}, nil,
|
[]string{"opcode"}, nil,
|
||||||
)
|
)
|
||||||
resolverCache = prometheus.NewDesc(
|
resolverCache = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(namespace, resolver, "cache_rrsets"),
|
prometheus.BuildFQName(namespace, resolver, "cache_rrsets"),
|
||||||
@ -146,36 +147,21 @@ var (
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Exporter collects Binds stats from the given server and exports
|
// Exporter collects Binds stats from the given server and exports them using
|
||||||
// them using the prometheus metrics package.
|
// the prometheus metrics package.
|
||||||
type Exporter struct {
|
type Exporter struct {
|
||||||
URI string
|
client bind.Client
|
||||||
client *http.Client
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewExporter returns an initialized Exporter.
|
// NewExporter returns an initialized Exporter.
|
||||||
func NewExporter(uri string, timeout time.Duration) *Exporter {
|
func NewExporter(url string, timeout time.Duration) *Exporter {
|
||||||
return &Exporter{
|
return &Exporter{
|
||||||
URI: uri,
|
client: v2.NewClient(url, &http.Client{Timeout: timeout}),
|
||||||
client: &http.Client{
|
|
||||||
Transport: &http.Transport{
|
|
||||||
Dial: func(netw, addr string) (net.Conn, error) {
|
|
||||||
c, err := net.DialTimeout(netw, addr, timeout)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := c.SetDeadline(time.Now().Add(timeout)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return c, nil
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describe describes all the metrics ever exported by the bind
|
// Describe describes all the metrics ever exported by the bind exporter. It
|
||||||
// exporter. It implements prometheus.Collector.
|
// implements prometheus.Collector.
|
||||||
func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
|
func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
|
||||||
ch <- up
|
ch <- up
|
||||||
ch <- incomingQueries
|
ch <- incomingQueries
|
||||||
@ -193,48 +179,29 @@ func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
|
|||||||
ch <- workerThreads
|
ch <- workerThreads
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect fetches the stats from configured bind location and
|
// Collect fetches the stats from configured bind location and delivers them as
|
||||||
// delivers them as Prometheus metrics. It implements prometheus.Collector.
|
// Prometheus metrics. It implements prometheus.Collector.
|
||||||
func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
|
func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
|
||||||
var status float64
|
stats, err := e.client.Stats()
|
||||||
defer func() {
|
|
||||||
ch <- prometheus.MustNewConstMetric(up, prometheus.GaugeValue, status)
|
|
||||||
}()
|
|
||||||
|
|
||||||
resp, err := e.client.Get(e.URI)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Error while querying Bind: ", err)
|
ch <- prometheus.MustNewConstMetric(up, prometheus.GaugeValue, 0)
|
||||||
|
log.Error("Couldn't retrieve BIND stats: ", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
ch <- prometheus.MustNewConstMetric(up, prometheus.GaugeValue, 1)
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
// Server statistics.
|
||||||
if err != nil {
|
for _, s := range stats.Server.IncomingQueries {
|
||||||
log.Error("Failed to read XML response body: ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
status = 1
|
|
||||||
|
|
||||||
root := Isc{}
|
|
||||||
if err := xml.Unmarshal([]byte(body), &root); err != nil {
|
|
||||||
log.Error("Failed to unmarshal XML response: ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
stats := root.Bind.Statistics
|
|
||||||
for _, s := range stats.Server.QueriesIn.Rdtype {
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
incomingQueries, prometheus.CounterValue, float64(s.Counter), s.Name,
|
incomingQueries, prometheus.CounterValue, float64(s.Counter), s.Name,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
for _, s := range stats.Server.Requests.Opcode {
|
for _, s := range stats.Server.IncomingRequests {
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
incomingRequests, prometheus.CounterValue, float64(s.Counter), s.Name,
|
incomingRequests, prometheus.CounterValue, float64(s.Counter), s.Name,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
for _, s := range stats.Server.NSStats {
|
||||||
for _, s := range stats.Server.NsStats {
|
|
||||||
if desc, ok := serverLabelStats[s.Name]; ok {
|
if desc, ok := serverLabelStats[s.Name]; ok {
|
||||||
r := strings.TrimPrefix(s.Name, "Qry")
|
r := strings.TrimPrefix(s.Name, "Qry")
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
@ -243,20 +210,19 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// View statistics.
|
||||||
for _, v := range stats.Views {
|
for _, v := range stats.Views {
|
||||||
for _, s := range v.Cache {
|
for _, s := range v.Cache {
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
resolverCache, prometheus.GaugeValue, float64(s.Counter), v.Name, s.Name,
|
resolverCache, prometheus.GaugeValue, float64(s.Counter), v.Name, s.Name,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
for _, s := range v.ResolverQueries {
|
||||||
for _, s := range v.Rdtype {
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
resolverQueries, prometheus.CounterValue, float64(s.Counter), v.Name, s.Name,
|
resolverQueries, prometheus.CounterValue, float64(s.Counter), v.Name, s.Name,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
for _, s := range v.ResolverStats {
|
||||||
for _, s := range v.Resstat {
|
|
||||||
if desc, ok := resolverMetricStats[s.Name]; ok {
|
if desc, ok := resolverMetricStats[s.Name]; ok {
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
desc, prometheus.CounterValue, float64(s.Counter), v.Name,
|
desc, prometheus.CounterValue, float64(s.Counter), v.Name,
|
||||||
@ -268,8 +234,7 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if buckets, count, err := histogram(v.ResolverStats); err == nil {
|
||||||
if buckets, count, err := histogram(v.Resstat); err == nil {
|
|
||||||
ch <- prometheus.MustNewConstHistogram(
|
ch <- prometheus.MustNewConstHistogram(
|
||||||
resolverQueryDuration, count, math.NaN(), buckets, v.Name,
|
resolverQueryDuration, count, math.NaN(), buckets, v.Name,
|
||||||
)
|
)
|
||||||
@ -277,26 +242,27 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
|
|||||||
log.Warn("Error parsing RTT:", err)
|
log.Warn("Error parsing RTT:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
threadModel := stats.Taskmgr.ThreadModel
|
|
||||||
|
// TaskManager statistics.
|
||||||
|
threadModel := stats.TaskManager.ThreadModel
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
tasksRunning, prometheus.GaugeValue, float64(threadModel.TasksRunning),
|
tasksRunning, prometheus.GaugeValue, float64(threadModel.TasksRunning),
|
||||||
)
|
)
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
workerThreads, prometheus.GaugeValue, float64(threadModel.WorkerThreads),
|
workerThreads, prometheus.GaugeValue, float64(threadModel.WorkerThreads),
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func histogram(stats []Stat) (map[float64]uint64, uint64, error) {
|
func histogram(stats []bind.Stat) (map[float64]uint64, uint64, error) {
|
||||||
buckets := map[float64]uint64{}
|
buckets := map[float64]uint64{}
|
||||||
var count uint64
|
var count uint64
|
||||||
|
|
||||||
for _, s := range stats {
|
for _, s := range stats {
|
||||||
if strings.HasPrefix(s.Name, qryRTT) {
|
if strings.HasPrefix(s.Name, bind.QryRTT) {
|
||||||
b := math.Inf(0)
|
b := math.Inf(0)
|
||||||
if !strings.HasSuffix(s.Name, "+") {
|
if !strings.HasSuffix(s.Name, "+") {
|
||||||
var err error
|
var err error
|
||||||
rrt := strings.TrimPrefix(s.Name, qryRTT)
|
rrt := strings.TrimPrefix(s.Name, bind.QryRTT)
|
||||||
b, err = strconv.ParseFloat(rrt, 32)
|
b, err = strconv.ParseFloat(rrt, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return buckets, 0, fmt.Errorf("could not parse RTT: %s", rrt)
|
return buckets, 0, fmt.Errorf("could not parse RTT: %s", rrt)
|
||||||
|
@ -14,17 +14,31 @@ import (
|
|||||||
func TestBindExporter(t *testing.T) {
|
func TestBindExporter(t *testing.T) {
|
||||||
tests := []string{
|
tests := []string{
|
||||||
`bind_up 1`,
|
`bind_up 1`,
|
||||||
`bind_incoming_queries_total{type="A"} 100`,
|
`bind_incoming_queries_total{type="A"} 128417`,
|
||||||
`bind_incoming_requests_total{name="QUERY"} 100`,
|
`bind_incoming_requests_total{opcode="QUERY"} 37634`,
|
||||||
`bind_responses_total{result="Success"} 100`,
|
`bind_responses_total{result="Success"} 29313`,
|
||||||
|
`bind_query_errors_total{error="Dropped"} 237`,
|
||||||
|
`bind_query_errors_total{error="Duplicate"} 216`,
|
||||||
|
`bind_query_errors_total{error="Failure"} 2950`,
|
||||||
|
`bind_resolver_cache_rrsets{type="A",view="_default"} 34324`,
|
||||||
|
`bind_resolver_queries_total{type="CNAME",view="_default"} 28`,
|
||||||
`bind_resolver_response_errors_total{error="FORMERR",view="_bind"} 0`,
|
`bind_resolver_response_errors_total{error="FORMERR",view="_bind"} 0`,
|
||||||
`bind_resolver_response_errors_total{error="FORMERR",view="_default"} 0`,
|
`bind_resolver_response_errors_total{error="FORMERR",view="_default"} 42906`,
|
||||||
`bind_resolver_response_errors_total{error="NXDOMAIN",view="_bind"} 0`,
|
`bind_resolver_response_errors_total{error="NXDOMAIN",view="_bind"} 0`,
|
||||||
`bind_resolver_response_errors_total{error="NXDOMAIN",view="_default"} 0`,
|
`bind_resolver_response_errors_total{error="NXDOMAIN",view="_default"} 16707`,
|
||||||
`bind_resolver_response_errors_total{error="OtherError",view="_bind"} 0`,
|
`bind_resolver_response_errors_total{error="OtherError",view="_bind"} 0`,
|
||||||
`bind_resolver_response_errors_total{error="OtherError",view="_default"} 0`,
|
`bind_resolver_response_errors_total{error="OtherError",view="_default"} 20660`,
|
||||||
`bind_resolver_response_errors_total{error="SERVFAIL",view="_bind"} 0`,
|
`bind_resolver_response_errors_total{error="SERVFAIL",view="_bind"} 0`,
|
||||||
`bind_resolver_response_errors_total{error="SERVFAIL",view="_default"} 0`,
|
`bind_resolver_response_errors_total{error="SERVFAIL",view="_default"} 7596`,
|
||||||
|
`bind_resolver_response_lame_total{view="_default"} 9108`,
|
||||||
|
`bind_resolver_query_duration_seconds_bucket{view="_default",le="0.01"} 38334`,
|
||||||
|
`bind_resolver_query_duration_seconds_bucket{view="_default",le="0.1"} 113122`,
|
||||||
|
`bind_resolver_query_duration_seconds_bucket{view="_default",le="0.5"} 182658`,
|
||||||
|
`bind_resolver_query_duration_seconds_bucket{view="_default",le="0.8"} 187375`,
|
||||||
|
`bind_resolver_query_duration_seconds_bucket{view="_default",le="1.6"} 188409`,
|
||||||
|
`bind_resolver_query_duration_seconds_bucket{view="_default",le="+Inf"} 227755`,
|
||||||
|
`bind_tasks_running 8`,
|
||||||
|
`bind_worker_threads 16`,
|
||||||
}
|
}
|
||||||
|
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -39,7 +53,7 @@ func TestBindExporter(t *testing.T) {
|
|||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
if !bytes.Contains(o, []byte(test)) {
|
if !bytes.Contains(o, []byte(test)) {
|
||||||
t.Errorf("expected to find %q", string(test))
|
t.Errorf("expected to find %q in output:\n%s", string(test), string(o))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
6217
fixtures/v2.xml
6217
fixtures/v2.xml
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user