diff --git a/collector/collector.go b/collector/collector.go index 6acf17f3..47deb2e9 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -11,6 +11,12 @@ type Collector interface { Update() (n int, err error) } +// TODO: Instead of periodically call Update, a Collector could be implemented +// as a real prometheus.Collector that only gathers metrics when +// scraped. (However, for metric gathering that takes very long, it might +// actually be better to do them proactively before scraping to minimize scrape +// time.) + type Config struct { Attributes map[string]string `json:"attributes"` } diff --git a/collector/gmond_collector.go b/collector/gmond_collector.go index 43cfd09d..f49bbdea 100644 --- a/collector/gmond_collector.go +++ b/collector/gmond_collector.go @@ -24,9 +24,8 @@ const ( ) type gmondCollector struct { - Metrics map[string]prometheus.Gauge - config Config - registry prometheus.Registry + Metrics map[string]*prometheus.GaugeVec + config Config } func init() { @@ -36,17 +35,16 @@ func init() { var illegalCharsRE = regexp.MustCompile(`[^a-zA-Z0-9_]`) // Takes a config struct and prometheus registry and returns a new Collector scraping ganglia. -func NewGmondCollector(config Config, registry prometheus.Registry) (Collector, error) { +func NewGmondCollector(config Config) (Collector, error) { c := gmondCollector{ - config: config, - Metrics: make(map[string]prometheus.Gauge), - registry: registry, + config: config, + Metrics: map[string]*prometheus.GaugeVec{}, } return &c, nil } -func (c *gmondCollector) setMetric(name string, labels map[string]string, metric ganglia.Metric) { +func (c *gmondCollector) setMetric(name, cluster string, metric ganglia.Metric) { if _, ok := c.Metrics[name]; !ok { var desc string var title string @@ -62,12 +60,18 @@ func (c *gmondCollector) setMetric(name string, labels map[string]string, metric } } glog.V(1).Infof("Register %s: %s", name, desc) - gauge := prometheus.NewGauge() - c.Metrics[name] = gauge - c.registry.Register(name, desc, prometheus.NilLabels, gauge) // one gauge per metric! + gv := prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Namespace: gangliaMetricsPrefix, + Name: name, + Help: desc, + }, + []string{"cluster"}, + ) + c.Metrics[name] = prometheus.MustRegisterOrGet(gv).(*prometheus.GaugeVec) } - glog.V(1).Infof("Set %s{%s}: %f", name, labels, metric.Value) - c.Metrics[name].Set(labels, metric.Value) + glog.V(1).Infof("Set %s{cluster=%q}: %f", name, cluster, metric.Value) + c.Metrics[name].WithLabelValues(cluster).Set(metric.Value) } func (c *gmondCollector) Update() (updates int, err error) { @@ -91,12 +95,9 @@ func (c *gmondCollector) Update() (updates int, err error) { for _, host := range cluster.Hosts { for _, metric := range host.Metrics { - name := gangliaMetricsPrefix + illegalCharsRE.ReplaceAllString(metric.Name, "_") + name := illegalCharsRE.ReplaceAllString(metric.Name, "_") - var labels = map[string]string{ - "cluster": cluster.Name, - } - c.setMetric(name, labels, metric) + c.setMetric(name, cluster.Name, metric) updates++ } } diff --git a/collector/runit_collector.go b/collector/runit_collector.go index 6e7c2096..e7375496 100644 --- a/collector/runit_collector.go +++ b/collector/runit_collector.go @@ -8,45 +8,57 @@ import ( "github.com/soundcloud/go-runit/runit" ) +var ( + runitLabelNames = []string{"service"} + + runitState = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Namespace: Namespace, + Name: "service_state", + Help: "node_exporter: state of runit service.", + }, + runitLabelNames, + ) + runitStateDesired = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Namespace: Namespace, + Name: "service_desired_state", + Help: "node_exporter: desired state of runit service.", + }, + runitLabelNames, + ) + runitStateNormal = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Namespace: Namespace, + Name: "service_normal_state", + Help: "node_exporter: normal state of runit service.", + }, + runitLabelNames, + ) +) + type runitCollector struct { - config Config - state prometheus.Gauge - stateDesired prometheus.Gauge - stateNormal prometheus.Gauge + config Config } func init() { Factories["runit"] = NewRunitCollector } -func NewRunitCollector(config Config, registry prometheus.Registry) (Collector, error) { +func NewRunitCollector(config Config) (Collector, error) { c := runitCollector{ - config: config, - state: prometheus.NewGauge(), - stateDesired: prometheus.NewGauge(), - stateNormal: prometheus.NewGauge(), + config: config, } - registry.Register( - "node_service_state", - "node_exporter: state of runit service.", - prometheus.NilLabels, - c.state, - ) - - registry.Register( - "node_service_desired_state", - "node_exporter: desired state of runit service.", - prometheus.NilLabels, - c.stateDesired, - ) - - registry.Register( - "node_service_normal_state", - "node_exporter: normal state of runit service.", - prometheus.NilLabels, - c.stateNormal, - ) + if _, err := prometheus.RegisterOrGet(runitState); err != nil { + return nil, err + } + if _, err := prometheus.RegisterOrGet(runitStateDesired); err != nil { + return nil, err + } + if _, err := prometheus.RegisterOrGet(runitStateNormal); err != nil { + return nil, err + } return &c, nil } @@ -65,16 +77,12 @@ func (c *runitCollector) Update() (updates int, err error) { } glog.V(1).Infof("%s is %d on pid %d for %d seconds", service.Name, status.State, status.Pid, status.Duration) - labels := map[string]string{ - "service": service.Name, - } - - c.state.Set(labels, float64(status.State)) - c.stateDesired.Set(labels, float64(status.Want)) + runitState.WithLabelValues(service.Name).Set(float64(status.State)) + runitStateDesired.WithLabelValues(service.Name).Set(float64(status.Want)) if status.NormallyUp { - c.stateNormal.Set(labels, 1) + runitStateNormal.WithLabelValues(service.Name).Set(1) } else { - c.stateNormal.Set(labels, 1) + runitStateNormal.WithLabelValues(service.Name).Set(1) } updates += 3 } diff --git a/node_exporter.conf b/node_exporter.conf index 6800bac1..8ce3c679 100644 --- a/node_exporter.conf +++ b/node_exporter.conf @@ -1,6 +1,6 @@ { "attributes" : { - "web-server" : "1", + "web_server" : "1", "zone" : "a", "default" : "1" }