Skip to content

Thread specific summary counters #19

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ require (
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 // indirect
github.com/prometheus/client_golang v1.0.0
github.com/prometheus/common v0.5.0
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 // indirect
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 // indirect
)
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,18 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand Down
48 changes: 39 additions & 9 deletions unbound_exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,15 +273,22 @@ func newUnboundMetric(name string, description string, valueType prometheus.Valu
}
}

func CollectFromReader(file io.Reader, ch chan<- prometheus.Metric) error {
type threadHelper struct {
match []string
value float64
}

func CollectFromReader(file io.Reader, threads bool, ch chan<- prometheus.Metric) error {
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
histogramPattern := regexp.MustCompile("^histogram\\.\\d+\\.\\d+\\.to\\.(\\d+\\.\\d+)$")
histogramPattern := regexp.MustCompile(`^histogram\.\d+\.\d+\.to\.(\d+\.\d+)$`)

histogramCount := uint64(0)
histogramAvg := float64(0)
histogramBuckets := make(map[float64]uint64)

threadSummary := make(map[unboundMetric]threadHelper)

for scanner.Scan() {
fields := strings.Split(scanner.Text(), "=")
if len(fields) != 2 {
Expand All @@ -297,6 +304,15 @@ func CollectFromReader(file io.Reader, ch chan<- prometheus.Metric) error {
if err != nil {
return err
}

if !threads && strings.HasPrefix(matches[0], "thread") {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you guarantee that matches actually has this length?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I can. There is matches != nil check before ParseFloat(), so there should always be at least first entry. Assuming the first entry tells thread all of the expressions have three fields. That should make both the matches[1] assignment and matches[1:] reference safe.

update := threadSummary[*metric]
matches[1] = "sum"
update.match = matches[1:]
update.value += value
threadSummary[*metric] = update
break
}
ch <- prometheus.MustNewConstMetric(
metric.desc,
metric.valueType,
Expand Down Expand Up @@ -328,6 +344,16 @@ func CollectFromReader(file io.Reader, ch chan<- prometheus.Metric) error {
}
}

if !threads {
for metric, helper := range threadSummary {
ch <- prometheus.MustNewConstMetric(
metric.desc,
metric.valueType,
helper.value,
helper.match...)
}
}

// Convert the metrics to a cumulative Prometheus histogram.
// Reconstruct the sum of all samples from the average value
// provided by Unbound. Hopefully this does not break
Expand Down Expand Up @@ -356,10 +382,11 @@ func CollectFromFile(path string, ch chan<- prometheus.Metric) error {
if err != nil {
return err
}
return CollectFromReader(conn, ch)
return CollectFromReader(conn, true, ch)
}

func CollectFromSocket(socketFamily string, host string, tlsConfig *tls.Config, ch chan<- prometheus.Metric) error {
func CollectFromSocket(socketFamily string, host string, tlsConfig *tls.Config,
threads bool, ch chan<- prometheus.Metric) error {
var (
conn net.Conn
err error
Expand All @@ -377,16 +404,17 @@ func CollectFromSocket(socketFamily string, host string, tlsConfig *tls.Config,
if err != nil {
return err
}
return CollectFromReader(conn, ch)
return CollectFromReader(conn, threads, ch)
}

type UnboundExporter struct {
socketFamily string
host string
tlsConfig *tls.Config
threads bool
}

func NewUnboundExporter(host string, ca string, cert string, key string) (*UnboundExporter, error) {
func NewUnboundExporter(host string, ca string, cert string, key string, threads bool) (*UnboundExporter, error) {
u, err := url.Parse(host)
if err != nil {
return &UnboundExporter{}, err
Expand Down Expand Up @@ -438,6 +466,7 @@ func NewUnboundExporter(host string, ca string, cert string, key string) (*Unbou
RootCAs: roots,
ServerName: "unbound",
},
threads: threads,
}, nil
}

Expand All @@ -449,14 +478,14 @@ func (e *UnboundExporter) Describe(ch chan<- *prometheus.Desc) {
}

func (e *UnboundExporter) Collect(ch chan<- prometheus.Metric) {
err := CollectFromSocket(e.socketFamily, e.host, e.tlsConfig, ch)
err := CollectFromSocket(e.socketFamily, e.host, e.tlsConfig, e.threads, ch)
if err == nil {
ch <- prometheus.MustNewConstMetric(
unboundUpDesc,
prometheus.GaugeValue,
1.0)
} else {
log.Error("Failed to scrape socket: %s", err)
log.Errorf("Failed to scrape socket: %s", err)
ch <- prometheus.MustNewConstMetric(
unboundUpDesc,
prometheus.GaugeValue,
Expand All @@ -472,11 +501,12 @@ func main() {
unboundCa = flag.String("unbound.ca", "/etc/unbound/unbound_server.pem", "Unbound server certificate.")
unboundCert = flag.String("unbound.cert", "/etc/unbound/unbound_control.pem", "Unbound client certificate.")
unboundKey = flag.String("unbound.key", "/etc/unbound/unbound_control.key", "Unbound client key.")
threads = flag.Bool("threads", true, "Export per thread metrics.")
)
flag.Parse()

log.Info("Starting unbound_exporter")
exporter, err := NewUnboundExporter(*unboundHost, *unboundCa, *unboundCert, *unboundKey)
exporter, err := NewUnboundExporter(*unboundHost, *unboundCa, *unboundCert, *unboundKey, *threads)
if err != nil {
panic(err)
}
Expand Down