mirror of
https://github.com/prometheus/node_exporter.git
synced 2024-12-31 16:37:31 -08:00
Merge pull request #24 from brian-brazil/master
Collect at every scrape, rather than at regular intervals.
This commit is contained in:
commit
83dee5a211
|
@ -29,7 +29,7 @@ func NewAttributesCollector(config Config) (Collector, error) {
|
||||||
for l := range c.config.Attributes {
|
for l := range c.config.Attributes {
|
||||||
labelNames = append(labelNames, l)
|
labelNames = append(labelNames, l)
|
||||||
}
|
}
|
||||||
gv := prometheus.NewGaugeVec(
|
attributes = prometheus.NewGaugeVec(
|
||||||
prometheus.GaugeOpts{
|
prometheus.GaugeOpts{
|
||||||
Namespace: Namespace,
|
Namespace: Namespace,
|
||||||
Name: "attributes",
|
Name: "attributes",
|
||||||
|
@ -37,17 +37,13 @@ func NewAttributesCollector(config Config) (Collector, error) {
|
||||||
},
|
},
|
||||||
labelNames,
|
labelNames,
|
||||||
)
|
)
|
||||||
collector, err := prometheus.RegisterOrGet(gv)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
attributes = collector.(*prometheus.GaugeVec)
|
|
||||||
return &c, nil
|
return &c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *attributesCollector) Update() (updates int, err error) {
|
func (c *attributesCollector) Update(ch chan<- prometheus.Metric) (err error) {
|
||||||
glog.V(1).Info("Set node_attributes{%v}: 1", c.config.Attributes)
|
glog.V(1).Info("Set node_attributes{%v}: 1", c.config.Attributes)
|
||||||
attributes.Reset()
|
attributes.Reset()
|
||||||
attributes.With(c.config.Attributes).Set(1)
|
attributes.With(c.config.Attributes).Set(1)
|
||||||
return updates, err
|
attributes.Collect(ch)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,29 +41,22 @@ func init() {
|
||||||
// It exposes the number of configured and active slave of linux bonding interfaces.
|
// It exposes the number of configured and active slave of linux bonding interfaces.
|
||||||
func NewBondingCollector(config Config) (Collector, error) {
|
func NewBondingCollector(config Config) (Collector, error) {
|
||||||
c := bondingCollector{}
|
c := bondingCollector{}
|
||||||
if _, err := prometheus.RegisterOrGet(bondingSlaves); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if _, err := prometheus.RegisterOrGet(bondingSlavesActive); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &c, nil
|
return &c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update reads and exposes bonding states, implements Collector interface. Caution: This works only on linux.
|
// Update reads and exposes bonding states, implements Collector interface. Caution: This works only on linux.
|
||||||
func (c *bondingCollector) Update() (int, error) {
|
func (c *bondingCollector) Update(ch chan<- prometheus.Metric) (err error) {
|
||||||
bondingStats, err := readBondingStats(sysfsNet)
|
bondingStats, err := readBondingStats(sysfsNet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return err
|
||||||
}
|
}
|
||||||
updates := 0
|
|
||||||
for master, status := range bondingStats {
|
for master, status := range bondingStats {
|
||||||
bondingSlaves.WithLabelValues(master).Set(float64(status[0]))
|
bondingSlaves.WithLabelValues(master).Set(float64(status[0]))
|
||||||
updates++
|
|
||||||
bondingSlavesActive.WithLabelValues(master).Set(float64(status[1]))
|
bondingSlavesActive.WithLabelValues(master).Set(float64(status[1]))
|
||||||
updates++
|
|
||||||
}
|
}
|
||||||
return updates, nil
|
bondingSlaves.Collect(ch)
|
||||||
|
bondingSlavesActive.Collect(ch)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readBondingStats(root string) (status map[string][2]int, err error) {
|
func readBondingStats(root string) (status map[string][2]int, err error) {
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
// Exporter is a prometheus exporter using multiple Factories to collect and export system metrics.
|
// Exporter is a prometheus exporter using multiple Factories to collect and export system metrics.
|
||||||
package collector
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
const Namespace = "node"
|
const Namespace = "node"
|
||||||
|
|
||||||
var Factories = make(map[string]func(Config) (Collector, error))
|
var Factories = make(map[string]func(Config) (Collector, error))
|
||||||
|
@ -8,7 +12,7 @@ var Factories = make(map[string]func(Config) (Collector, error))
|
||||||
// Interface a collector has to implement.
|
// Interface a collector has to implement.
|
||||||
type Collector interface {
|
type Collector interface {
|
||||||
// Get new metrics and expose them via prometheus registry.
|
// Get new metrics and expose them via prometheus registry.
|
||||||
Update() (n int, err error)
|
Update(ch chan<- prometheus.Metric) (err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Instead of periodically call Update, a Collector could be implemented
|
// TODO: Instead of periodically call Update, a Collector could be implemented
|
||||||
|
|
|
@ -146,19 +146,13 @@ func NewDiskstatsCollector(config Config) (Collector, error) {
|
||||||
config: config,
|
config: config,
|
||||||
ignoredDevicesPattern: regexp.MustCompile(*ignoredDevices),
|
ignoredDevicesPattern: regexp.MustCompile(*ignoredDevices),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range diskStatsMetrics {
|
|
||||||
if _, err := prometheus.RegisterOrGet(c); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &c, nil
|
return &c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *diskstatsCollector) Update() (updates int, err error) {
|
func (c *diskstatsCollector) Update(ch chan<- prometheus.Metric) (err error) {
|
||||||
diskStats, err := getDiskStats()
|
diskStats, err := getDiskStats()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, fmt.Errorf("Couldn't get diskstats: %s", err)
|
return fmt.Errorf("Couldn't get diskstats: %s", err)
|
||||||
}
|
}
|
||||||
for dev, stats := range diskStats {
|
for dev, stats := range diskStats {
|
||||||
if c.ignoredDevicesPattern.MatchString(dev) {
|
if c.ignoredDevicesPattern.MatchString(dev) {
|
||||||
|
@ -166,10 +160,9 @@ func (c *diskstatsCollector) Update() (updates int, err error) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for k, value := range stats {
|
for k, value := range stats {
|
||||||
updates++
|
|
||||||
v, err := strconv.ParseFloat(value, 64)
|
v, err := strconv.ParseFloat(value, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, fmt.Errorf("Invalid value %s in diskstats: %s", value, err)
|
return fmt.Errorf("Invalid value %s in diskstats: %s", value, err)
|
||||||
}
|
}
|
||||||
counter, ok := diskStatsMetrics[k].(*prometheus.CounterVec)
|
counter, ok := diskStatsMetrics[k].(*prometheus.CounterVec)
|
||||||
if ok {
|
if ok {
|
||||||
|
@ -180,7 +173,10 @@ func (c *diskstatsCollector) Update() (updates int, err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return updates, err
|
for _, c := range diskStatsMetrics {
|
||||||
|
c.Collect(ch)
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDiskStats() (map[string]map[int]string, error) {
|
func getDiskStats() (map[string]map[int]string, error) {
|
||||||
|
|
|
@ -88,29 +88,14 @@ func NewFilesystemCollector(config Config) (Collector, error) {
|
||||||
config: config,
|
config: config,
|
||||||
ignoredMountPointsPattern: regexp.MustCompile(*ignoredMountPoints),
|
ignoredMountPointsPattern: regexp.MustCompile(*ignoredMountPoints),
|
||||||
}
|
}
|
||||||
if _, err := prometheus.RegisterOrGet(fsSizeMetric); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if _, err := prometheus.RegisterOrGet(fsFreeMetric); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if _, err := prometheus.RegisterOrGet(fsAvailMetric); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if _, err := prometheus.RegisterOrGet(fsFilesMetric); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if _, err := prometheus.RegisterOrGet(fsFilesFreeMetric); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &c, nil
|
return &c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expose filesystem fullness.
|
// Expose filesystem fullness.
|
||||||
func (c *filesystemCollector) Update() (updates int, err error) {
|
func (c *filesystemCollector) Update(ch chan<- prometheus.Metric) (err error) {
|
||||||
mps, err := mountPoints()
|
mps, err := mountPoints()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, err
|
return err
|
||||||
}
|
}
|
||||||
for _, mp := range mps {
|
for _, mp := range mps {
|
||||||
if c.ignoredMountPointsPattern.MatchString(mp) {
|
if c.ignoredMountPointsPattern.MatchString(mp) {
|
||||||
|
@ -120,16 +105,20 @@ func (c *filesystemCollector) Update() (updates int, err error) {
|
||||||
buf := new(syscall.Statfs_t)
|
buf := new(syscall.Statfs_t)
|
||||||
err := syscall.Statfs(mp, buf)
|
err := syscall.Statfs(mp, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, fmt.Errorf("Statfs on %s returned %s", mp, err)
|
return fmt.Errorf("Statfs on %s returned %s", mp, err)
|
||||||
}
|
}
|
||||||
fsSizeMetric.WithLabelValues(mp).Set(float64(buf.Blocks) * float64(buf.Bsize))
|
fsSizeMetric.WithLabelValues(mp).Set(float64(buf.Blocks) * float64(buf.Bsize))
|
||||||
fsFreeMetric.WithLabelValues(mp).Set(float64(buf.Bfree) * float64(buf.Bsize))
|
fsFreeMetric.WithLabelValues(mp).Set(float64(buf.Bfree) * float64(buf.Bsize))
|
||||||
fsAvailMetric.WithLabelValues(mp).Set(float64(buf.Bavail) * float64(buf.Bsize))
|
fsAvailMetric.WithLabelValues(mp).Set(float64(buf.Bavail) * float64(buf.Bsize))
|
||||||
fsFilesMetric.WithLabelValues(mp).Set(float64(buf.Files))
|
fsFilesMetric.WithLabelValues(mp).Set(float64(buf.Files))
|
||||||
fsFilesFreeMetric.WithLabelValues(mp).Set(float64(buf.Ffree))
|
fsFilesFreeMetric.WithLabelValues(mp).Set(float64(buf.Ffree))
|
||||||
updates++
|
|
||||||
}
|
}
|
||||||
return updates, err
|
fsSizeMetric.Collect(ch)
|
||||||
|
fsFreeMetric.Collect(ch)
|
||||||
|
fsAvailMetric.Collect(ch)
|
||||||
|
fsFilesMetric.Collect(ch)
|
||||||
|
fsFilesFreeMetric.Collect(ch)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func mountPoints() ([]string, error) {
|
func mountPoints() ([]string, error) {
|
||||||
|
|
|
@ -68,17 +68,16 @@ func (c *gmondCollector) setMetric(name, cluster string, metric ganglia.Metric)
|
||||||
},
|
},
|
||||||
[]string{"cluster"},
|
[]string{"cluster"},
|
||||||
)
|
)
|
||||||
c.Metrics[name] = prometheus.MustRegisterOrGet(gv).(*prometheus.GaugeVec)
|
|
||||||
}
|
}
|
||||||
glog.V(1).Infof("Set %s{cluster=%q}: %f", name, cluster, metric.Value)
|
glog.V(1).Infof("Set %s{cluster=%q}: %f", name, cluster, metric.Value)
|
||||||
c.Metrics[name].WithLabelValues(cluster).Set(metric.Value)
|
c.Metrics[name].WithLabelValues(cluster).Set(metric.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *gmondCollector) Update() (updates int, err error) {
|
func (c *gmondCollector) Update(ch chan<- prometheus.Metric) (err error) {
|
||||||
conn, err := net.Dial(gangliaProto, gangliaAddress)
|
conn, err := net.Dial(gangliaProto, gangliaAddress)
|
||||||
glog.V(1).Infof("gmondCollector Update")
|
glog.V(1).Infof("gmondCollector Update")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, fmt.Errorf("Can't connect to gmond: %s", err)
|
return fmt.Errorf("Can't connect to gmond: %s", err)
|
||||||
}
|
}
|
||||||
conn.SetDeadline(time.Now().Add(gangliaTimeout))
|
conn.SetDeadline(time.Now().Add(gangliaTimeout))
|
||||||
|
|
||||||
|
@ -88,7 +87,7 @@ func (c *gmondCollector) Update() (updates int, err error) {
|
||||||
|
|
||||||
err = decoder.Decode(&ganglia)
|
err = decoder.Decode(&ganglia)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, fmt.Errorf("Couldn't parse xml: %s", err)
|
return fmt.Errorf("Couldn't parse xml: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, cluster := range ganglia.Clusters {
|
for _, cluster := range ganglia.Clusters {
|
||||||
|
@ -98,11 +97,13 @@ func (c *gmondCollector) Update() (updates int, err error) {
|
||||||
name := illegalCharsRE.ReplaceAllString(metric.Name, "_")
|
name := illegalCharsRE.ReplaceAllString(metric.Name, "_")
|
||||||
|
|
||||||
c.setMetric(name, cluster.Name, metric)
|
c.setMetric(name, cluster.Name, metric)
|
||||||
updates++
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return updates, err
|
for _, m := range c.Metrics {
|
||||||
|
m.Collect(ch)
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func toUtf8(charset string, input io.Reader) (io.Reader, error) {
|
func toUtf8(charset string, input io.Reader) (io.Reader, error) {
|
||||||
|
|
|
@ -42,23 +42,19 @@ func NewInterruptsCollector(config Config) (Collector, error) {
|
||||||
c := interruptsCollector{
|
c := interruptsCollector{
|
||||||
config: config,
|
config: config,
|
||||||
}
|
}
|
||||||
if _, err := prometheus.RegisterOrGet(interruptsMetric); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &c, nil
|
return &c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *interruptsCollector) Update() (updates int, err error) {
|
func (c *interruptsCollector) Update(ch chan<- prometheus.Metric) (err error) {
|
||||||
interrupts, err := getInterrupts()
|
interrupts, err := getInterrupts()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, fmt.Errorf("Couldn't get interrupts: %s", err)
|
return fmt.Errorf("Couldn't get interrupts: %s", err)
|
||||||
}
|
}
|
||||||
for name, interrupt := range interrupts {
|
for name, interrupt := range interrupts {
|
||||||
for cpuNo, value := range interrupt.values {
|
for cpuNo, value := range interrupt.values {
|
||||||
updates++
|
|
||||||
fv, err := strconv.ParseFloat(value, 64)
|
fv, err := strconv.ParseFloat(value, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, fmt.Errorf("Invalid value %s in interrupts: %s", value, err)
|
return fmt.Errorf("Invalid value %s in interrupts: %s", value, err)
|
||||||
}
|
}
|
||||||
labels := prometheus.Labels{
|
labels := prometheus.Labels{
|
||||||
"CPU": strconv.Itoa(cpuNo),
|
"CPU": strconv.Itoa(cpuNo),
|
||||||
|
@ -69,7 +65,8 @@ func (c *interruptsCollector) Update() (updates int, err error) {
|
||||||
interruptsMetric.With(labels).Set(fv)
|
interruptsMetric.With(labels).Set(fv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return updates, err
|
interruptsMetric.Collect(ch)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
type interrupt struct {
|
type interrupt struct {
|
||||||
|
|
|
@ -39,21 +39,18 @@ func NewLastLoginCollector(config Config) (Collector, error) {
|
||||||
c := lastLoginCollector{
|
c := lastLoginCollector{
|
||||||
config: config,
|
config: config,
|
||||||
}
|
}
|
||||||
if _, err := prometheus.RegisterOrGet(lastSeen); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &c, nil
|
return &c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *lastLoginCollector) Update() (updates int, err error) {
|
func (c *lastLoginCollector) Update(ch chan<- prometheus.Metric) (err error) {
|
||||||
last, err := getLastLoginTime()
|
last, err := getLastLoginTime()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, fmt.Errorf("Couldn't get last seen: %s", err)
|
return fmt.Errorf("Couldn't get last seen: %s", err)
|
||||||
}
|
}
|
||||||
updates++
|
|
||||||
glog.V(1).Infof("Set node_last_login_time: %f", last)
|
glog.V(1).Infof("Set node_last_login_time: %f", last)
|
||||||
lastSeen.Set(last)
|
lastSeen.Set(last)
|
||||||
return updates, err
|
lastSeen.Collect(ch)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLastLoginTime() (float64, error) {
|
func getLastLoginTime() (float64, error) {
|
||||||
|
|
|
@ -38,23 +38,18 @@ func NewLoadavgCollector(config Config) (Collector, error) {
|
||||||
c := loadavgCollector{
|
c := loadavgCollector{
|
||||||
config: config,
|
config: config,
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := prometheus.RegisterOrGet(load1); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &c, nil
|
return &c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *loadavgCollector) Update() (updates int, err error) {
|
func (c *loadavgCollector) Update(ch chan<- prometheus.Metric) (err error) {
|
||||||
load, err := getLoad1()
|
load, err := getLoad1()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, fmt.Errorf("Couldn't get load: %s", err)
|
return fmt.Errorf("Couldn't get load: %s", err)
|
||||||
}
|
}
|
||||||
updates++
|
|
||||||
glog.V(1).Infof("Set node_load: %f", load)
|
glog.V(1).Infof("Set node_load: %f", load)
|
||||||
load1.Set(load)
|
load1.Set(load)
|
||||||
|
load1.Collect(ch)
|
||||||
return updates, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLoad1() (float64, error) {
|
func getLoad1() (float64, error) {
|
||||||
|
|
|
@ -130,104 +130,92 @@ func NewMegaCliCollector(config Config) (Collector, error) {
|
||||||
config: config,
|
config: config,
|
||||||
cli: cli,
|
cli: cli,
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := prometheus.RegisterOrGet(driveTemperature); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if _, err := prometheus.RegisterOrGet(driveCounters); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if _, err := prometheus.RegisterOrGet(drivePresence); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &c, nil
|
return &c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *megaCliCollector) Update() (updates int, err error) {
|
func (c *megaCliCollector) Update(ch chan<- prometheus.Metric) (err error) {
|
||||||
au, err := c.updateAdapter()
|
err = c.updateAdapter()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return au, err
|
return err
|
||||||
}
|
}
|
||||||
du, err := c.updateDisks()
|
err = c.updateDisks()
|
||||||
return au + du, err
|
driveTemperature.Collect(ch)
|
||||||
|
driveCounters.Collect(ch)
|
||||||
|
drivePresence.Collect(ch)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *megaCliCollector) updateAdapter() (int, error) {
|
func (c *megaCliCollector) updateAdapter() error {
|
||||||
cmd := exec.Command(c.cli, "-AdpAllInfo", "-aALL")
|
cmd := exec.Command(c.cli, "-AdpAllInfo", "-aALL")
|
||||||
pipe, err := cmd.StdoutPipe()
|
pipe, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cmd.Start(); err != nil {
|
if err := cmd.Start(); err != nil {
|
||||||
return 0, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
stats, err := parseMegaCliAdapter(pipe)
|
stats, err := parseMegaCliAdapter(pipe)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return err
|
||||||
}
|
}
|
||||||
if err := cmd.Wait(); err != nil {
|
if err := cmd.Wait(); err != nil {
|
||||||
return 0, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
updates := 0
|
|
||||||
for k, v := range stats["Device Present"] {
|
for k, v := range stats["Device Present"] {
|
||||||
value, err := strconv.ParseFloat(v, 64)
|
value, err := strconv.ParseFloat(v, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, err
|
return err
|
||||||
}
|
}
|
||||||
drivePresence.WithLabelValues(k).Set(value)
|
drivePresence.WithLabelValues(k).Set(value)
|
||||||
updates++
|
|
||||||
}
|
}
|
||||||
return updates, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *megaCliCollector) updateDisks() (int, error) {
|
func (c *megaCliCollector) updateDisks() error {
|
||||||
cmd := exec.Command(c.cli, "-PDList", "-aALL")
|
cmd := exec.Command(c.cli, "-PDList", "-aALL")
|
||||||
pipe, err := cmd.StdoutPipe()
|
pipe, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cmd.Start(); err != nil {
|
if err := cmd.Start(); err != nil {
|
||||||
return 0, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
stats, err := parseMegaCliDisks(pipe)
|
stats, err := parseMegaCliDisks(pipe)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return err
|
||||||
}
|
}
|
||||||
if err := cmd.Wait(); err != nil {
|
if err := cmd.Wait(); err != nil {
|
||||||
return 0, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
updates := 0
|
|
||||||
for enc, encStats := range stats {
|
for enc, encStats := range stats {
|
||||||
for slot, slotStats := range encStats {
|
for slot, slotStats := range encStats {
|
||||||
tStr := slotStats["Drive Temperature"]
|
tStr := slotStats["Drive Temperature"]
|
||||||
tStr = tStr[:strings.Index(tStr, "C")]
|
tStr = tStr[:strings.Index(tStr, "C")]
|
||||||
t, err := strconv.ParseFloat(tStr, 64)
|
t, err := strconv.ParseFloat(tStr, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
encStr := strconv.Itoa(enc)
|
encStr := strconv.Itoa(enc)
|
||||||
slotStr := strconv.Itoa(slot)
|
slotStr := strconv.Itoa(slot)
|
||||||
|
|
||||||
driveTemperature.WithLabelValues(encStr, slotStr).Set(t)
|
driveTemperature.WithLabelValues(encStr, slotStr).Set(t)
|
||||||
updates++
|
|
||||||
|
|
||||||
for _, c := range counters {
|
for _, c := range counters {
|
||||||
counter, err := strconv.ParseFloat(slotStats[c], 64)
|
counter, err := strconv.ParseFloat(slotStats[c], 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
driveCounters.WithLabelValues(encStr, slotStr, c).Set(counter)
|
driveCounters.WithLabelValues(encStr, slotStr, c).Set(counter)
|
||||||
updates++
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return updates, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,26 +41,25 @@ func NewMeminfoCollector(config Config) (Collector, error) {
|
||||||
return &c, nil
|
return &c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *meminfoCollector) Update() (updates int, err error) {
|
func (c *meminfoCollector) Update(ch chan<- prometheus.Metric) (err error) {
|
||||||
memInfo, err := getMemInfo()
|
memInfo, err := getMemInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, fmt.Errorf("Couldn't get meminfo: %s", err)
|
return fmt.Errorf("Couldn't get meminfo: %s", err)
|
||||||
}
|
}
|
||||||
glog.V(1).Infof("Set node_mem: %#v", memInfo)
|
glog.V(1).Infof("Set node_mem: %#v", memInfo)
|
||||||
for k, v := range memInfo {
|
for k, v := range memInfo {
|
||||||
if _, ok := memInfoMetrics[k]; !ok {
|
if _, ok := memInfoMetrics[k]; !ok {
|
||||||
gauge := prometheus.NewGauge(prometheus.GaugeOpts{
|
memInfoMetrics[k] = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
Namespace: Namespace,
|
Namespace: Namespace,
|
||||||
Subsystem: memInfoSubsystem,
|
Subsystem: memInfoSubsystem,
|
||||||
Name: k,
|
Name: k,
|
||||||
Help: k + " from /proc/meminfo.",
|
Help: k + " from /proc/meminfo.",
|
||||||
})
|
})
|
||||||
memInfoMetrics[k] = prometheus.MustRegisterOrGet(gauge).(prometheus.Gauge)
|
|
||||||
}
|
}
|
||||||
updates++
|
|
||||||
memInfoMetrics[k].Set(v)
|
memInfoMetrics[k].Set(v)
|
||||||
|
memInfoMetrics[k].Collect(ch)
|
||||||
}
|
}
|
||||||
return updates, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMemInfo() (map[string]float64, error) {
|
func getMemInfo() (map[string]float64, error) {
|
||||||
|
|
|
@ -39,17 +39,17 @@ func NewNetDevCollector(config Config) (Collector, error) {
|
||||||
return &c, nil
|
return &c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *netDevCollector) Update() (updates int, err error) {
|
func (c *netDevCollector) Update(ch chan<- prometheus.Metric) (err error) {
|
||||||
netStats, err := getNetStats()
|
netStats, err := getNetStats()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, fmt.Errorf("Couldn't get netstats: %s", err)
|
return fmt.Errorf("Couldn't get netstats: %s", err)
|
||||||
}
|
}
|
||||||
for direction, devStats := range netStats {
|
for direction, devStats := range netStats {
|
||||||
for dev, stats := range devStats {
|
for dev, stats := range devStats {
|
||||||
for t, value := range stats {
|
for t, value := range stats {
|
||||||
key := direction + "_" + t
|
key := direction + "_" + t
|
||||||
if _, ok := netStatsMetrics[key]; !ok {
|
if _, ok := netStatsMetrics[key]; !ok {
|
||||||
gv := prometheus.NewGaugeVec(
|
netStatsMetrics[key] = prometheus.NewGaugeVec(
|
||||||
prometheus.GaugeOpts{
|
prometheus.GaugeOpts{
|
||||||
Namespace: Namespace,
|
Namespace: Namespace,
|
||||||
Subsystem: netStatsSubsystem,
|
Subsystem: netStatsSubsystem,
|
||||||
|
@ -58,18 +58,19 @@ func (c *netDevCollector) Update() (updates int, err error) {
|
||||||
},
|
},
|
||||||
[]string{"device"},
|
[]string{"device"},
|
||||||
)
|
)
|
||||||
netStatsMetrics[key] = prometheus.MustRegisterOrGet(gv).(*prometheus.GaugeVec)
|
|
||||||
}
|
}
|
||||||
updates++
|
|
||||||
v, err := strconv.ParseFloat(value, 64)
|
v, err := strconv.ParseFloat(value, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, fmt.Errorf("Invalid value %s in netstats: %s", value, err)
|
return fmt.Errorf("Invalid value %s in netstats: %s", value, err)
|
||||||
}
|
}
|
||||||
netStatsMetrics[key].WithLabelValues(dev).Set(v)
|
netStatsMetrics[key].WithLabelValues(dev).Set(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return updates, err
|
for _, m := range netStatsMetrics {
|
||||||
|
m.Collect(ch)
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNetStats() (map[string]map[string]map[string]string, error) {
|
func getNetStats() (map[string]map[string]map[string]string, error) {
|
||||||
|
|
|
@ -36,21 +36,17 @@ func NewNtpCollector(config Config) (Collector, error) {
|
||||||
}
|
}
|
||||||
c := ntpCollector{}
|
c := ntpCollector{}
|
||||||
|
|
||||||
if _, err := prometheus.RegisterOrGet(ntpDrift); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &c, nil
|
return &c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ntpCollector) Update() (updates int, err error) {
|
func (c *ntpCollector) Update(ch chan<- prometheus.Metric) (err error) {
|
||||||
t, err := ntp.Time(*ntpServer)
|
t, err := ntp.Time(*ntpServer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, fmt.Errorf("Couldn't get ntp drift: %s", err)
|
return fmt.Errorf("Couldn't get ntp drift: %s", err)
|
||||||
}
|
}
|
||||||
drift := t.Sub(time.Now())
|
drift := t.Sub(time.Now())
|
||||||
updates++
|
|
||||||
glog.V(1).Infof("Set ntp_drift_seconds: %f", drift.Seconds())
|
glog.V(1).Infof("Set ntp_drift_seconds: %f", drift.Seconds())
|
||||||
ntpDrift.Set(drift.Seconds())
|
ntpDrift.Set(drift.Seconds())
|
||||||
|
ntpDrift.Collect(ch)
|
||||||
return updates, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,23 +50,13 @@ func NewRunitCollector(config Config) (Collector, error) {
|
||||||
config: config,
|
config: config,
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
return &c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *runitCollector) Update() (updates int, err error) {
|
func (c *runitCollector) Update(ch chan<- prometheus.Metric) (err error) {
|
||||||
services, err := runit.GetServices("/etc/service")
|
services, err := runit.GetServices("/etc/service")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, service := range services {
|
for _, service := range services {
|
||||||
|
@ -84,8 +74,9 @@ func (c *runitCollector) Update() (updates int, err error) {
|
||||||
} else {
|
} else {
|
||||||
runitStateNormal.WithLabelValues(service.Name).Set(1)
|
runitStateNormal.WithLabelValues(service.Name).Set(1)
|
||||||
}
|
}
|
||||||
updates += 3
|
|
||||||
}
|
}
|
||||||
|
runitState.Collect(ch)
|
||||||
return updates, err
|
runitStateDesired.Collect(ch)
|
||||||
|
runitStateNormal.Collect(ch)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,35 +73,14 @@ func NewStatCollector(config Config) (Collector, error) {
|
||||||
c := statCollector{
|
c := statCollector{
|
||||||
config: config,
|
config: config,
|
||||||
}
|
}
|
||||||
if _, err := prometheus.RegisterOrGet(cpuMetrics); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if _, err := prometheus.RegisterOrGet(intrMetric); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if _, err := prometheus.RegisterOrGet(ctxtMetric); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if _, err := prometheus.RegisterOrGet(forksMetric); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if _, err := prometheus.RegisterOrGet(btimeMetric); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if _, err := prometheus.RegisterOrGet(procsRunningMetric); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if _, err := prometheus.RegisterOrGet(procsBlockedMetric); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &c, nil
|
return &c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expose a variety of stats from /proc/stats.
|
// Expose a variety of stats from /proc/stats.
|
||||||
func (c *statCollector) Update() (updates int, err error) {
|
func (c *statCollector) Update(ch chan<- prometheus.Metric) (err error) {
|
||||||
file, err := os.Open(procStat)
|
file, err := os.Open(procStat)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, err
|
return err
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
|
@ -119,7 +98,7 @@ func (c *statCollector) Update() (updates int, err error) {
|
||||||
for i, v := range parts[1 : len(cpuFields)+1] {
|
for i, v := range parts[1 : len(cpuFields)+1] {
|
||||||
value, err := strconv.ParseFloat(v, 64)
|
value, err := strconv.ParseFloat(v, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, err
|
return err
|
||||||
}
|
}
|
||||||
// Convert from ticks to seconds
|
// Convert from ticks to seconds
|
||||||
value /= float64(C.sysconf(C._SC_CLK_TCK))
|
value /= float64(C.sysconf(C._SC_CLK_TCK))
|
||||||
|
@ -129,40 +108,47 @@ func (c *statCollector) Update() (updates int, err error) {
|
||||||
// Only expose the overall number, use the 'interrupts' collector for more detail.
|
// Only expose the overall number, use the 'interrupts' collector for more detail.
|
||||||
value, err := strconv.ParseFloat(parts[1], 64)
|
value, err := strconv.ParseFloat(parts[1], 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, err
|
return err
|
||||||
}
|
}
|
||||||
intrMetric.Set(value)
|
intrMetric.Set(value)
|
||||||
case parts[0] == "ctxt":
|
case parts[0] == "ctxt":
|
||||||
value, err := strconv.ParseFloat(parts[1], 64)
|
value, err := strconv.ParseFloat(parts[1], 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, err
|
return err
|
||||||
}
|
}
|
||||||
ctxtMetric.Set(value)
|
ctxtMetric.Set(value)
|
||||||
case parts[0] == "processes":
|
case parts[0] == "processes":
|
||||||
value, err := strconv.ParseFloat(parts[1], 64)
|
value, err := strconv.ParseFloat(parts[1], 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, err
|
return err
|
||||||
}
|
}
|
||||||
forksMetric.Set(value)
|
forksMetric.Set(value)
|
||||||
case parts[0] == "btime":
|
case parts[0] == "btime":
|
||||||
value, err := strconv.ParseFloat(parts[1], 64)
|
value, err := strconv.ParseFloat(parts[1], 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, err
|
return err
|
||||||
}
|
}
|
||||||
btimeMetric.Set(value)
|
btimeMetric.Set(value)
|
||||||
case parts[0] == "procs_running":
|
case parts[0] == "procs_running":
|
||||||
value, err := strconv.ParseFloat(parts[1], 64)
|
value, err := strconv.ParseFloat(parts[1], 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, err
|
return err
|
||||||
}
|
}
|
||||||
procsRunningMetric.Set(value)
|
procsRunningMetric.Set(value)
|
||||||
case parts[0] == "procs_blocked":
|
case parts[0] == "procs_blocked":
|
||||||
value, err := strconv.ParseFloat(parts[1], 64)
|
value, err := strconv.ParseFloat(parts[1], 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return updates, err
|
return err
|
||||||
}
|
}
|
||||||
procsBlockedMetric.Set(value)
|
procsBlockedMetric.Set(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return updates, err
|
cpuMetrics.Collect(ch)
|
||||||
|
ctxtMetric.Collect(ch)
|
||||||
|
intrMetric.Collect(ch)
|
||||||
|
forksMetric.Collect(ch)
|
||||||
|
btimeMetric.Collect(ch)
|
||||||
|
procsRunningMetric.Collect(ch)
|
||||||
|
procsBlockedMetric.Collect(ch)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,16 +32,13 @@ func NewTimeCollector(config Config) (Collector, error) {
|
||||||
config: config,
|
config: config,
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := prometheus.RegisterOrGet(systemTime); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &c, nil
|
return &c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *timeCollector) Update() (updates int, err error) {
|
func (c *timeCollector) Update(ch chan<- prometheus.Metric) (err error) {
|
||||||
updates++
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
glog.V(1).Infof("Set time: %f", now.Unix())
|
glog.V(1).Infof("Set time: %f", now.Unix())
|
||||||
systemTime.Set(float64(now.Unix()))
|
systemTime.Set(float64(now.Unix()))
|
||||||
return updates, err
|
systemTime.Collect(ch)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
183
node_exporter.go
183
node_exporter.go
|
@ -28,7 +28,6 @@ var (
|
||||||
listeningAddress = flag.String("listen", ":8080", "address to listen on")
|
listeningAddress = flag.String("listen", ":8080", "address to listen on")
|
||||||
enabledCollectors = flag.String("enabledCollectors", "attributes,diskstats,filesystem,loadavg,meminfo,stat,time,netdev", "comma-seperated list of collectors to use")
|
enabledCollectors = flag.String("enabledCollectors", "attributes,diskstats,filesystem,loadavg,meminfo,stat,time,netdev", "comma-seperated list of collectors to use")
|
||||||
printCollectors = flag.Bool("printCollectors", false, "If true, print available collectors and exit")
|
printCollectors = flag.Bool("printCollectors", false, "If true, print available collectors and exit")
|
||||||
interval = flag.Duration("interval", 60*time.Second, "refresh interval")
|
|
||||||
|
|
||||||
collectorLabelNames = []string{"collector", "result"}
|
collectorLabelNames = []string{"collector", "result"}
|
||||||
|
|
||||||
|
@ -41,78 +40,56 @@ var (
|
||||||
},
|
},
|
||||||
collectorLabelNames,
|
collectorLabelNames,
|
||||||
)
|
)
|
||||||
metricsUpdated = prometheus.NewGaugeVec(
|
|
||||||
prometheus.GaugeOpts{
|
|
||||||
Namespace: collector.Namespace,
|
|
||||||
Subsystem: subsystem,
|
|
||||||
Name: "metrics_updated",
|
|
||||||
Help: "node_exporter: Number of metrics updated.",
|
|
||||||
},
|
|
||||||
collectorLabelNames,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
// Implements Collector.
|
||||||
flag.Parse()
|
type NodeCollector struct {
|
||||||
if *printCollectors {
|
collectors map[string]collector.Collector
|
||||||
fmt.Printf("Available collectors:\n")
|
}
|
||||||
for n, _ := range collector.Factories {
|
|
||||||
fmt.Printf(" - %s\n", n)
|
// Implements Collector.
|
||||||
}
|
func (n NodeCollector) Describe(ch chan<- *prometheus.Desc) {
|
||||||
return
|
scrapeDurations.Describe(ch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements Collector.
|
||||||
|
func (n NodeCollector) Collect(ch chan<- prometheus.Metric) {
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
wg.Add(len(n.collectors))
|
||||||
|
for name, c := range n.collectors {
|
||||||
|
go func(name string, c collector.Collector) {
|
||||||
|
Execute(name, c, ch)
|
||||||
|
wg.Done()
|
||||||
|
}(name, c)
|
||||||
}
|
}
|
||||||
collectors, err := loadCollectors(*configFile)
|
wg.Wait()
|
||||||
|
scrapeDurations.Collect(ch)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Execute(name string, c collector.Collector, ch chan<- prometheus.Metric) {
|
||||||
|
begin := time.Now()
|
||||||
|
err := c.Update(ch)
|
||||||
|
duration := time.Since(begin)
|
||||||
|
var result string
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Couldn't load config and collectors: %s", err)
|
glog.Infof("ERROR: %s failed after %fs: %s", name, duration.Seconds(), err)
|
||||||
|
result = "error"
|
||||||
|
} else {
|
||||||
|
glog.Infof("OK: %s success after %fs.", name, duration.Seconds())
|
||||||
|
result = "success"
|
||||||
}
|
}
|
||||||
|
scrapeDurations.WithLabelValues(name, result).Observe(duration.Seconds())
|
||||||
|
}
|
||||||
|
|
||||||
prometheus.MustRegister(scrapeDurations)
|
func getConfig(file string) (*collector.Config, error) {
|
||||||
prometheus.MustRegister(metricsUpdated)
|
config := &collector.Config{}
|
||||||
|
glog.Infof("Reading config %s", *configFile)
|
||||||
glog.Infof("Enabled collectors:")
|
bytes, err := ioutil.ReadFile(*configFile)
|
||||||
for n, _ := range collectors {
|
if err != nil {
|
||||||
glog.Infof(" - %s", n)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return config, json.Unmarshal(bytes, &config)
|
||||||
sigHup := make(chan os.Signal)
|
|
||||||
sigUsr1 := make(chan os.Signal)
|
|
||||||
signal.Notify(sigHup, syscall.SIGHUP)
|
|
||||||
signal.Notify(sigUsr1, syscall.SIGUSR1)
|
|
||||||
|
|
||||||
go serveStatus()
|
|
||||||
|
|
||||||
glog.Infof("Starting initial collection")
|
|
||||||
collect(collectors)
|
|
||||||
|
|
||||||
tick := time.Tick(*interval)
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-sigHup:
|
|
||||||
collectors, err = loadCollectors(*configFile)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Couldn't load config and collectors: %s", err)
|
|
||||||
}
|
|
||||||
glog.Infof("Reloaded collectors and config")
|
|
||||||
tick = time.Tick(*interval)
|
|
||||||
|
|
||||||
case <-tick:
|
|
||||||
glog.Infof("Starting new interval")
|
|
||||||
collect(collectors)
|
|
||||||
|
|
||||||
case <-sigUsr1:
|
|
||||||
glog.Infof("got signal")
|
|
||||||
if *memProfile != "" {
|
|
||||||
glog.Infof("Writing memory profile to %s", *memProfile)
|
|
||||||
f, err := os.Create(*memProfile)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
pprof.WriteHeapProfile(f)
|
|
||||||
f.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadCollectors(file string) (map[string]collector.Collector, error) {
|
func loadCollectors(file string) (map[string]collector.Collector, error) {
|
||||||
|
@ -135,46 +112,50 @@ func loadCollectors(file string) (map[string]collector.Collector, error) {
|
||||||
return collectors, nil
|
return collectors, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getConfig(file string) (*collector.Config, error) {
|
func main() {
|
||||||
config := &collector.Config{}
|
flag.Parse()
|
||||||
glog.Infof("Reading config %s", *configFile)
|
if *printCollectors {
|
||||||
bytes, err := ioutil.ReadFile(*configFile)
|
fmt.Printf("Available collectors:\n")
|
||||||
|
for n, _ := range collector.Factories {
|
||||||
|
fmt.Printf(" - %s\n", n)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
collectors, err := loadCollectors(*configFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
log.Fatalf("Couldn't load config and collectors: %s", err)
|
||||||
}
|
}
|
||||||
return config, json.Unmarshal(bytes, &config)
|
|
||||||
}
|
|
||||||
|
|
||||||
func serveStatus() {
|
glog.Infof("Enabled collectors:")
|
||||||
http.Handle("/metrics", prometheus.Handler())
|
for n, _ := range collectors {
|
||||||
http.ListenAndServe(*listeningAddress, nil)
|
glog.Infof(" - %s", n)
|
||||||
}
|
|
||||||
|
|
||||||
func collect(collectors map[string]collector.Collector) {
|
|
||||||
wg := sync.WaitGroup{}
|
|
||||||
wg.Add(len(collectors))
|
|
||||||
for n, c := range collectors {
|
|
||||||
go func(n string, c collector.Collector) {
|
|
||||||
Execute(n, c)
|
|
||||||
wg.Done()
|
|
||||||
}(n, c)
|
|
||||||
}
|
}
|
||||||
wg.Wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
func Execute(name string, c collector.Collector) {
|
nodeCollector := NodeCollector{collectors: collectors}
|
||||||
begin := time.Now()
|
prometheus.MustRegister(nodeCollector)
|
||||||
updates, err := c.Update()
|
|
||||||
duration := time.Since(begin)
|
|
||||||
var result string
|
|
||||||
|
|
||||||
if err != nil {
|
sigUsr1 := make(chan os.Signal)
|
||||||
glog.Infof("ERROR: %s failed after %fs: %s", name, duration.Seconds(), err)
|
signal.Notify(sigUsr1, syscall.SIGUSR1)
|
||||||
result = "error"
|
|
||||||
} else {
|
go func() {
|
||||||
glog.Infof("OK: %s success after %fs.", name, duration.Seconds())
|
http.Handle("/metrics", prometheus.Handler())
|
||||||
result = "success"
|
http.ListenAndServe(*listeningAddress, nil)
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-sigUsr1:
|
||||||
|
glog.Infof("got signal")
|
||||||
|
if *memProfile != "" {
|
||||||
|
glog.Infof("Writing memory profile to %s", *memProfile)
|
||||||
|
f, err := os.Create(*memProfile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
pprof.WriteHeapProfile(f)
|
||||||
|
f.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
scrapeDurations.WithLabelValues(name, result).Observe(duration.Seconds())
|
|
||||||
metricsUpdated.WithLabelValues(name, result).Set(float64(updates))
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue