diff --git a/exporter/exporter.go b/exporter/exporter.go index 72de61ef..6c3f4292 100644 --- a/exporter/exporter.go +++ b/exporter/exporter.go @@ -85,12 +85,7 @@ func New(configFile string) (e exporter, err error) { log.Fatalf("Couldn't attach collector: %s", err) } - cm, err := NewMuninCollector(e.config, e.registry) - if err != nil { - log.Fatalf("Couldn't attach collector: %s", err) - } - - e.collectors = []Collector{&cn, &cg, &cm} + e.collectors = []Collector{&cn, &cg} if e.config.ListeningAddress != "" { e.listeningAddress = e.config.ListeningAddress diff --git a/exporter/munin_collector.go b/exporter/munin_collector.go deleted file mode 100644 index c3ea1edf..00000000 --- a/exporter/munin_collector.go +++ /dev/null @@ -1,236 +0,0 @@ -package exporter - -import ( - "bufio" - "fmt" - "github.com/prometheus/client_golang/prometheus" - "io" - "net" - "regexp" - "strconv" - "strings" -) - -const ( - muninAddress = "127.0.0.1:4949" - muninProto = "tcp" -) - -var muninBanner = regexp.MustCompile(`# munin node at (.*)`) - -type muninCollector struct { - name string - hostname string - graphs []string - gaugePerMetric map[string]prometheus.Gauge - config config - registry prometheus.Registry - connection net.Conn -} - -// Takes a config struct and prometheus registry and returns a new Collector scraping munin. -func NewMuninCollector(config config, registry prometheus.Registry) (c muninCollector, err error) { - c = muninCollector{ - name: "munin_collector", - config: config, - registry: registry, - gaugePerMetric: make(map[string]prometheus.Gauge), - } - - return c, err -} - -func (c *muninCollector) Name() string { return c.name } - -func (c *muninCollector) connect() (err error) { - c.connection, err = net.Dial(muninProto, muninAddress) - if err != nil { - return err - } - debug(c.Name(), "Connected.") - - reader := bufio.NewReader(c.connection) - head, err := reader.ReadString('\n') - if err != nil { - return err - } - - matches := muninBanner.FindStringSubmatch(head) - if len(matches) != 2 { // expect: # munin node at - return fmt.Errorf("Unexpected line: %s", head) - } - c.hostname = matches[1] - debug(c.Name(), "Found hostname: %s", c.hostname) - return err -} - -func (c *muninCollector) muninCommand(cmd string) (reader *bufio.Reader, err error) { - if c.connection == nil { - err := c.connect() - if err != nil { - return reader, fmt.Errorf("Couldn't connect to munin: %s", err) - } - } - reader = bufio.NewReader(c.connection) - - fmt.Fprintf(c.connection, cmd+"\n") - - _, err = reader.Peek(1) - switch err { - case io.EOF: - debug(c.Name(), "not connected anymore, closing connection and reconnect.") - c.connection.Close() - err = c.connect() - if err != nil { - return reader, fmt.Errorf("Couldn't connect to %s: %s", muninAddress) - } - return c.muninCommand(cmd) - case nil: //no error - break - default: - return reader, fmt.Errorf("Unexpected error: %s", err) - } - - return reader, err -} - -func (c *muninCollector) muninList() (items []string, err error) { - munin, err := c.muninCommand("list") - if err != nil { - return items, fmt.Errorf("Couldn't get list: %s", err) - } - - response, err := munin.ReadString('\n') // we are only interested in the first line - if err != nil { - return items, fmt.Errorf("Couldn't read response: %s", err) - } - - if response[0] == '#' { // # not expected here - return items, fmt.Errorf("Error getting items: %s", response) - } - items = strings.Fields(strings.TrimRight(response, "\n")) - return items, err -} - -func (c *muninCollector) muninConfig(name string) (config map[string]map[string]string, graphConfig map[string]string, err error) { - graphConfig = make(map[string]string) - config = make(map[string]map[string]string) - - resp, err := c.muninCommand("config " + name) - if err != nil { - return config, graphConfig, fmt.Errorf("Couldn't get config for %s: %s", name, err) - } - - for { - line, err := resp.ReadString('\n') - if err == io.EOF { - debug(c.Name(), "EOF, retrying") - return c.muninConfig(name) - } - if err != nil { - return nil, nil, err - } - if line == ".\n" { // munin end marker - break - } - if line[0] == '#' { // here it's just a comment, so ignore it - continue - } - parts := strings.Fields(line) - if len(parts) < 2 { - return nil, nil, fmt.Errorf("Line unexpected: %s", line) - } - key, value := parts[0], strings.TrimRight(strings.Join(parts[1:], " "), "\n") - - key_parts := strings.Split(key, ".") - if len(key_parts) > 1 { // it's a metric config (metric.label etc) - if _, ok := config[key_parts[0]]; !ok { - config[key_parts[0]] = make(map[string]string) - } - config[key_parts[0]][key_parts[1]] = value - } else { - graphConfig[key_parts[0]] = value - } - } - return config, graphConfig, err -} - - -func (c *muninCollector) registerMetric(name string) (err error) { - configs, graphConfig, err := c.muninConfig(name) - if err != nil { - return fmt.Errorf("Couldn't get config for graph %s: %s", name, err) - } - - for metric, config := range configs { - metricName := strings.Replace(name+"-"+metric, ".", "_", -1) - desc := graphConfig["graph_title"] + ": " + config["label"] - if config["info"] != "" { - desc = desc + ", " + config["info"] - } - gauge := prometheus.NewGauge() - debug(c.Name(), "Register %s: %s", metricName, desc) - c.gaugePerMetric[metricName] = gauge - c.registry.Register(metricName, desc, prometheus.NilLabels, gauge) - } - return nil -} - - -func (c *muninCollector) Update() (updates int, err error) { - items, err := c.muninList() - if err != nil { - return updates, fmt.Errorf("Couldn't get graph list: %s", err) - } - - for _, name := range items { - c.graphs = append(c.graphs, name) - } - - for _, graph := range c.graphs { - munin, err := c.muninCommand("fetch " + graph) - if err != nil { - return updates, err - } - - for { - line, err := munin.ReadString('\n') - line = strings.TrimRight(line, "\n") - if err == io.EOF { - debug(c.Name(), "unexpected EOF, retrying") - return c.Update() - } - if err != nil { - return updates, err - } - if len(line) == 1 && line[0] == '.' { - break // end of list - } - - parts := strings.Fields(line) - if len(parts) != 2 { - debug(c.Name(), "unexpected line: %s", line) - continue - } - key, value_s := strings.Split(parts[0], ".")[0], parts[1] - name := graph + "-" + key - if _, ok := c.gaugePerMetric[name]; !ok { - if err := c.registerMetric(name); err != nil { - return updates, err - } - } - value, err := strconv.ParseFloat(value_s, 64) - if err != nil { - debug(c.Name(), "Couldn't parse value in line %s, malformed?", line) - continue - } - labels := map[string]string{ - "hostname": c.hostname, - } - debug(c.Name(), "Set %s{%s}: %f\n", name, labels, value) - c.gaugePerMetric[name].Set(labels, value) - updates++ - } - } - return updates, err -}