Skip to content
Snippets Groups Projects
Commit 3d7f6b1c authored by Alexander Simmerl's avatar Alexander Simmerl
Browse files

Attempt on consul collector

parent 939d8506
No related branches found
No related tags found
No related merge requests found
// +build !noconsul
package collector
import (
"bufio"
"flag"
"fmt"
"io"
"os/exec"
"strconv"
"strings"
"github.com/prometheus/client_golang/prometheus"
)
const (
consulSubsystem = "consul"
)
var (
consulBinary = flag.String("consul.binary", "consul", "Location of the consul binary")
consulIgnoredFields = map[string]struct{}{
"arch": struct{}{},
"os": struct{}{},
"state": struct{}{},
"version": struct{}{},
}
consulIgnoredKeys = map[string]struct{}{
"build": struct{}{},
}
)
func init() {
Factories["consul"] = NewConsulCollector
}
type consulCollector struct {
metrics map[string]prometheus.Gauge
}
// NewConsulCollector returns the collector implementation to export Consul
// internals.
func NewConsulCollector(config Config) (Collector, error) {
return &consulCollector{
metrics: map[string]prometheus.Gauge{},
}, nil
}
func (c *consulCollector) Update(metricc chan<- prometheus.Metric) error {
stats, err := getConsulStats()
if err != nil {
return fmt.Errorf("consul info failed: %s", err)
}
for name, value := range stats {
if _, ok := c.metrics[name]; !ok {
c.metrics[name] = prometheus.NewGauge(
prometheus.GaugeOpts{
Namespace: consulSubsystem,
Name: name,
Help: fmt.Sprintf("%s from consul info", name),
},
)
}
c.metrics[name].Set(float64(value))
}
for _, m := range c.metrics {
m.Collect(metricc)
}
return nil
}
type consulStats map[string]int64
func getConsulStats() (consulStats, error) {
info := exec.Command(*consulBinary, "info")
outPipe, err := info.StdoutPipe()
if err != nil {
return nil, err
}
if err := info.Start(); err != nil {
return nil, err
}
stats, err := parseConsulStats(outPipe)
if err != nil {
return nil, err
}
if err := info.Wait(); err != nil {
return nil, err
}
return stats, nil
}
func parseConsulStats(r io.Reader) (consulStats, error) {
var (
s = bufio.NewScanner(r)
stats = consulStats{}
key string
)
for s.Scan() {
line := strings.TrimSpace(s.Text())
if strings.Contains(line, ":") {
key = strings.TrimSuffix(line, ":")
}
if _, ok := consulIgnoredKeys[key]; ok {
continue
}
if strings.Contains(line, "=") {
var (
parts = strings.SplitN(line, "=", 2)
field, value = strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1])
name = strings.Join([]string{key, field}, "_")
)
if _, ok := consulIgnoredFields[field]; ok {
continue
}
switch value {
case "true":
stats[name] = 1
case "false":
stats[name] = 0
default:
i, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return nil, err
}
stats[name] = i
}
}
}
if err := s.Err(); err != nil {
return nil, err
}
return stats, nil
}
package collector
import (
"bytes"
"testing"
)
func TestConsulAgentInput(t *testing.T) {
var (
output = `
agent:
check_monitors = 0
check_ttls = 0
checks = 0
services = 8
build:
prerelease =
revision = 461c1e18
version = 0.4.2.soundcloud4
consul:
known_servers = 3
server = false
runtime:
arch = amd64
cpu_count = 1
goroutines = 36
max_procs = 16
os = linux
version = go1.3
serf_lan:
event_queue = 0
event_time = 55
failed = 0
intent_queue = 0
left = 0
member_time = 116
members = 11
query_queue = 0
query_time = 1
`
r = bytes.NewBufferString(output)
)
stats, err := parseConsulStats(r)
if err != nil {
t.Fatalf("parse failed: %s", err)
}
if want, got := 18, len(stats); want != got {
t.Errorf("want %d, got %d", want, got)
}
}
func TestConsulServerInput(t *testing.T) {
var (
output = `
agent:
check_monitors = 0
check_ttls = 0
checks = 0
services = 4
build:
prerelease =
revision = 461c1e18
version = 0.4.2.soundcloud4
consul:
bootstrap = false
known_datacenters = 1
leader = true
server = true
raft:
applied_index = 1712470
commit_index = 1712470
fsm_pending = 0
last_contact = 0
last_log_index = 1712470
last_log_term = 131
last_snapshot_index = 1708783
last_snapshot_term = 131
num_peers = 2
state = Leader
term = 131
runtime:
arch = amd64
cpu_count = 1
goroutines = 81
max_procs = 16
os = linux
version = go1.3
serf_lan:
event_queue = 0
event_time = 55
failed = 0
intent_queue = 0
left = 0
member_time = 116
members = 11
query_queue = 0
query_time = 1
serf_wan:
event_queue = 0
event_time = 1
failed = 0
intent_queue = 0
left = 0
member_time = 1
members = 1
query_queue = 0
query_time = 1
`
r = bytes.NewBufferString(output)
)
stats, err := parseConsulStats(r)
if err != nil {
t.Fatalf("parse failed: %s", err)
}
if want, got := 39, len(stats); want != got {
t.Errorf("want %d, got %d", want, got)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment