Reduce number of global variables used

This is the first step to make the exporter more testable.
This commit is contained in:
Tobias Schmidt 2014-11-24 21:00:17 -05:00
parent 974f6fc762
commit 872f921867
15 changed files with 472 additions and 481 deletions

View file

@ -7,12 +7,9 @@ import (
"github.com/prometheus/client_golang/prometheus"
)
var (
attributes *prometheus.GaugeVec
)
type attributesCollector struct {
config Config
metric *prometheus.GaugeVec
}
func init() {
@ -22,28 +19,28 @@ func init() {
// Takes a config struct and prometheus registry and returns a new Collector exposing
// labels from the config.
func NewAttributesCollector(config Config) (Collector, error) {
c := attributesCollector{
config: config,
}
labelNames := []string{}
for l := range c.config.Attributes {
for l := range config.Attributes {
labelNames = append(labelNames, l)
}
attributes = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Name: "attributes",
Help: "The node_exporter attributes.",
},
labelNames,
)
return &c, nil
return &attributesCollector{
config: config,
metric: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Name: "attributes",
Help: "The node_exporter attributes.",
},
labelNames,
),
}, nil
}
func (c *attributesCollector) Update(ch chan<- prometheus.Metric) (err error) {
glog.V(1).Info("Set node_attributes{%v}: 1", c.config.Attributes)
attributes.Reset()
attributes.With(c.config.Attributes).Set(1)
attributes.Collect(ch)
c.metric.Reset()
c.metric.With(c.config.Attributes).Set(1)
c.metric.Collect(ch)
return err
}

View file

@ -16,22 +16,9 @@ const (
sysfsNet = "/sys/class/net"
)
var (
bondingSlaves = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Name: "net_bonding_slaves",
Help: "Number of configured slaves per bonding interface.",
}, []string{"master"})
bondingSlavesActive = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Name: "net_bonding_slaves_active",
Help: "Number of active slaves per bonding interface.",
}, []string{"master"})
)
type bondingCollector struct{}
type bondingCollector struct {
slaves, active *prometheus.GaugeVec
}
func init() {
Factories["bonding"] = NewBondingCollector
@ -40,8 +27,24 @@ func init() {
// NewBondingCollector returns a newly allocated bondingCollector.
// It exposes the number of configured and active slave of linux bonding interfaces.
func NewBondingCollector(config Config) (Collector, error) {
c := bondingCollector{}
return &c, nil
return &bondingCollector{
slaves: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Name: "net_bonding_slaves",
Help: "Number of configured slaves per bonding interface.",
},
[]string{"master"},
),
active: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Name: "net_bonding_slaves_active",
Help: "Number of active slaves per bonding interface.",
},
[]string{"master"},
),
}, nil
}
// Update reads and exposes bonding states, implements Collector interface. Caution: This works only on linux.
@ -51,11 +54,11 @@ func (c *bondingCollector) Update(ch chan<- prometheus.Metric) (err error) {
return err
}
for master, status := range bondingStats {
bondingSlaves.WithLabelValues(master).Set(float64(status[0]))
bondingSlavesActive.WithLabelValues(master).Set(float64(status[1]))
c.slaves.WithLabelValues(master).Set(float64(status[0]))
c.active.WithLabelValues(master).Set(float64(status[1]))
}
bondingSlaves.Collect(ch)
bondingSlavesActive.Collect(ch)
c.slaves.Collect(ch)
c.active.Collect(ch)
return nil
}

View file

@ -23,116 +23,12 @@ const (
var (
ignoredDevices = flag.String("diskstatsIgnoredDevices", "^(ram|loop|(h|s|xv)d[a-z])\\d+$", "Regexp of devices to ignore for diskstats.")
diskLabelNames = []string{"device"}
// Docs from https://www.kernel.org/doc/Documentation/iostats.txt
diskStatsMetrics = []prometheus.Collector{
prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: diskSubsystem,
Name: "reads_completed",
Help: "The total number of reads completed successfully.",
},
diskLabelNames,
),
prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: diskSubsystem,
Name: "reads_merged",
Help: "The number of reads merged. See https://www.kernel.org/doc/Documentation/iostats.txt.",
},
diskLabelNames,
),
prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: diskSubsystem,
Name: "sectors_read",
Help: "The total number of sectors read successfully.",
},
diskLabelNames,
),
prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: diskSubsystem,
Name: "read_time_ms",
Help: "The total number of milliseconds spent by all reads.",
},
diskLabelNames,
),
prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: diskSubsystem,
Name: "writes_completed",
Help: "The total number of writes completed successfully.",
},
diskLabelNames,
),
prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: diskSubsystem,
Name: "writes_merged",
Help: "The number of writes merged. See https://www.kernel.org/doc/Documentation/iostats.txt.",
},
diskLabelNames,
),
prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: diskSubsystem,
Name: "sectors_written",
Help: "The total number of sectors written successfully.",
},
diskLabelNames,
),
prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: diskSubsystem,
Name: "write_time_ms",
Help: "This is the total number of milliseconds spent by all writes.",
},
diskLabelNames,
),
prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: diskSubsystem,
Name: "io_now",
Help: "The number of I/Os currently in progress.",
},
diskLabelNames,
),
prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: diskSubsystem,
Name: "io_time_ms",
Help: "Milliseconds spent doing I/Os.",
},
diskLabelNames,
),
prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: diskSubsystem,
Name: "io_time_weighted",
Help: "The weighted # of milliseconds spent doing I/Os. See https://www.kernel.org/doc/Documentation/iostats.txt.",
},
diskLabelNames,
),
}
)
type diskstatsCollector struct {
config Config
ignoredDevicesPattern *regexp.Regexp
metrics []prometheus.Collector
}
func init() {
@ -142,38 +38,148 @@ func init() {
// Takes a config struct and prometheus registry and returns a new Collector exposing
// disk device stats.
func NewDiskstatsCollector(config Config) (Collector, error) {
c := diskstatsCollector{
var diskLabelNames = []string{"device"}
return &diskstatsCollector{
config: config,
ignoredDevicesPattern: regexp.MustCompile(*ignoredDevices),
}
return &c, nil
// Docs from https://www.kernel.org/doc/Documentation/iostats.txt
metrics: []prometheus.Collector{
prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: diskSubsystem,
Name: "reads_completed",
Help: "The total number of reads completed successfully.",
},
diskLabelNames,
),
prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: diskSubsystem,
Name: "reads_merged",
Help: "The number of reads merged. See https://www.kernel.org/doc/Documentation/iostats.txt.",
},
diskLabelNames,
),
prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: diskSubsystem,
Name: "sectors_read",
Help: "The total number of sectors read successfully.",
},
diskLabelNames,
),
prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: diskSubsystem,
Name: "read_time_ms",
Help: "The total number of milliseconds spent by all reads.",
},
diskLabelNames,
),
prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: diskSubsystem,
Name: "writes_completed",
Help: "The total number of writes completed successfully.",
},
diskLabelNames,
),
prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: diskSubsystem,
Name: "writes_merged",
Help: "The number of writes merged. See https://www.kernel.org/doc/Documentation/iostats.txt.",
},
diskLabelNames,
),
prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: diskSubsystem,
Name: "sectors_written",
Help: "The total number of sectors written successfully.",
},
diskLabelNames,
),
prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: diskSubsystem,
Name: "write_time_ms",
Help: "This is the total number of milliseconds spent by all writes.",
},
diskLabelNames,
),
prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: diskSubsystem,
Name: "io_now",
Help: "The number of I/Os currently in progress.",
},
diskLabelNames,
),
prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: diskSubsystem,
Name: "io_time_ms",
Help: "Milliseconds spent doing I/Os.",
},
diskLabelNames,
),
prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: diskSubsystem,
Name: "io_time_weighted",
Help: "The weighted # of milliseconds spent doing I/Os. See https://www.kernel.org/doc/Documentation/iostats.txt.",
},
diskLabelNames,
),
},
}, nil
}
func (c *diskstatsCollector) Update(ch chan<- prometheus.Metric) (err error) {
diskStats, err := getDiskStats()
if err != nil {
return fmt.Errorf("Couldn't get diskstats: %s", err)
return fmt.Errorf("couldn't get diskstats: %s", err)
}
for dev, stats := range diskStats {
if c.ignoredDevicesPattern.MatchString(dev) {
glog.V(1).Infof("Ignoring device: %s", dev)
continue
}
if len(stats) != len(c.metrics) {
return fmt.Errorf("invalid line for %s for %s", procDiskStats, dev)
}
for k, value := range stats {
v, err := strconv.ParseFloat(value, 64)
if err != nil {
return 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)
if ok {
if counter, ok := c.metrics[k].(*prometheus.CounterVec); ok {
counter.WithLabelValues(dev).Set(v)
} else {
var gauge = diskStatsMetrics[k].(*prometheus.GaugeVec)
} else if gauge, ok := c.metrics[k].(*prometheus.GaugeVec); ok {
gauge.WithLabelValues(dev).Set(v)
} else {
return fmt.Errorf("unexpected collector %d", k)
}
}
}
for _, c := range diskStatsMetrics {
for _, c := range c.metrics {
c.Collect(ch)
}
return err
@ -197,8 +203,8 @@ func parseDiskStats(r io.Reader) (map[string]map[int]string, error) {
for scanner.Scan() {
parts := strings.Fields(string(scanner.Text()))
if len(parts) != len(diskStatsMetrics)+3 { // we strip major, minor and dev
return nil, fmt.Errorf("Invalid line in %s: %s", procDiskStats, scanner.Text())
if len(parts) < 4 { // we strip major, minor and dev
return nil, fmt.Errorf("invalid line in %s: %s", procDiskStats, scanner.Text())
}
dev := parts[2]
diskStats[dev] = map[int]string{}

View file

@ -21,60 +21,14 @@ const (
)
var (
filesystemLabelNames = []string{"filesystem"}
fsSizeMetric = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: filesystemSubsystem,
Name: "size",
Help: "Filesystem size in bytes.",
},
filesystemLabelNames,
)
fsFreeMetric = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: filesystemSubsystem,
Name: "free",
Help: "Filesystem free space in bytes.",
},
filesystemLabelNames,
)
fsAvailMetric = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: filesystemSubsystem,
Name: "avail",
Help: "Filesystem space available to non-root users in bytes.",
},
filesystemLabelNames,
)
fsFilesMetric = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: filesystemSubsystem,
Name: "files",
Help: "Filesystem total file nodes.",
},
filesystemLabelNames,
)
fsFilesFreeMetric = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: filesystemSubsystem,
Name: "files_free",
Help: "Filesystem total free file nodes.",
},
filesystemLabelNames,
)
ignoredMountPoints = flag.String("filesystemIgnoredMountPoints", "^/(sys|proc|dev)($|/)", "Regexp of mount points to ignore for filesystem collector.")
)
type filesystemCollector struct {
config Config
ignoredMountPointsPattern *regexp.Regexp
size, free, avail, files, filesFree *prometheus.GaugeVec
}
func init() {
@ -84,11 +38,57 @@ func init() {
// Takes a config struct and prometheus registry and returns a new Collector exposing
// network device filesystems.
func NewFilesystemCollector(config Config) (Collector, error) {
c := filesystemCollector{
var filesystemLabelNames = []string{"filesystem"}
return &filesystemCollector{
config: config,
ignoredMountPointsPattern: regexp.MustCompile(*ignoredMountPoints),
}
return &c, nil
size: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: filesystemSubsystem,
Name: "size",
Help: "Filesystem size in bytes.",
},
filesystemLabelNames,
),
free: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: filesystemSubsystem,
Name: "free",
Help: "Filesystem free space in bytes.",
},
filesystemLabelNames,
),
avail: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: filesystemSubsystem,
Name: "avail",
Help: "Filesystem space available to non-root users in bytes.",
},
filesystemLabelNames,
),
files: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: filesystemSubsystem,
Name: "files",
Help: "Filesystem total file nodes.",
},
filesystemLabelNames,
),
filesFree: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: filesystemSubsystem,
Name: "files_free",
Help: "Filesystem total free file nodes.",
},
filesystemLabelNames,
),
}, nil
}
// Expose filesystem fullness.
@ -107,17 +107,17 @@ func (c *filesystemCollector) Update(ch chan<- prometheus.Metric) (err error) {
if err != nil {
return fmt.Errorf("Statfs on %s returned %s", mp, err)
}
fsSizeMetric.WithLabelValues(mp).Set(float64(buf.Blocks) * float64(buf.Bsize))
fsFreeMetric.WithLabelValues(mp).Set(float64(buf.Bfree) * float64(buf.Bsize))
fsAvailMetric.WithLabelValues(mp).Set(float64(buf.Bavail) * float64(buf.Bsize))
fsFilesMetric.WithLabelValues(mp).Set(float64(buf.Files))
fsFilesFreeMetric.WithLabelValues(mp).Set(float64(buf.Ffree))
c.size.WithLabelValues(mp).Set(float64(buf.Blocks) * float64(buf.Bsize))
c.free.WithLabelValues(mp).Set(float64(buf.Bfree) * float64(buf.Bsize))
c.avail.WithLabelValues(mp).Set(float64(buf.Bavail) * float64(buf.Bsize))
c.files.WithLabelValues(mp).Set(float64(buf.Files))
c.filesFree.WithLabelValues(mp).Set(float64(buf.Ffree))
}
fsSizeMetric.Collect(ch)
fsFreeMetric.Collect(ch)
fsAvailMetric.Collect(ch)
fsFilesMetric.Collect(ch)
fsFilesFreeMetric.Collect(ch)
c.size.Collect(ch)
c.free.Collect(ch)
c.avail.Collect(ch)
c.files.Collect(ch)
c.filesFree.Collect(ch)
return err
}

View file

@ -17,19 +17,9 @@ const (
procInterrupts = "/proc/interrupts"
)
var (
interruptsMetric = prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Name: "interrupts",
Help: "Interrupt details from /proc/interrupts.",
},
[]string{"CPU", "type", "info", "devices"},
)
)
type interruptsCollector struct {
config Config
metric *prometheus.CounterVec
}
func init() {
@ -39,10 +29,17 @@ func init() {
// Takes a config struct and prometheus registry and returns a new Collector exposing
// interrupts stats
func NewInterruptsCollector(config Config) (Collector, error) {
c := interruptsCollector{
return &interruptsCollector{
config: config,
}
return &c, nil
metric: prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Name: "interrupts",
Help: "Interrupt details from /proc/interrupts.",
},
[]string{"CPU", "type", "info", "devices"},
),
}, nil
}
func (c *interruptsCollector) Update(ch chan<- prometheus.Metric) (err error) {
@ -62,10 +59,10 @@ func (c *interruptsCollector) Update(ch chan<- prometheus.Metric) (err error) {
"info": interrupt.info,
"devices": interrupt.devices,
}
interruptsMetric.With(labels).Set(fv)
c.metric.With(labels).Set(fv)
}
}
interruptsMetric.Collect(ch)
c.metric.Collect(ch)
return err
}

View file

@ -16,17 +16,9 @@ import (
const lastLoginSubsystem = "last_login"
var (
lastSeen = prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: lastLoginSubsystem,
Name: "time",
Help: "The time of the last login.",
})
)
type lastLoginCollector struct {
config Config
metric prometheus.Gauge
}
func init() {
@ -36,10 +28,15 @@ func init() {
// Takes a config struct and prometheus registry and returns a new Collector exposing
// load, seconds since last login and a list of tags as specified by config.
func NewLastLoginCollector(config Config) (Collector, error) {
c := lastLoginCollector{
return &lastLoginCollector{
config: config,
}
return &c, nil
metric: prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: lastLoginSubsystem,
Name: "time",
Help: "The time of the last login.",
}),
}, nil
}
func (c *lastLoginCollector) Update(ch chan<- prometheus.Metric) (err error) {
@ -48,8 +45,8 @@ func (c *lastLoginCollector) Update(ch chan<- prometheus.Metric) (err error) {
return fmt.Errorf("Couldn't get last seen: %s", err)
}
glog.V(1).Infof("Set node_last_login_time: %f", last)
lastSeen.Set(last)
lastSeen.Collect(ch)
c.metric.Set(last)
c.metric.Collect(ch)
return err
}

View file

@ -16,16 +16,9 @@ const (
procLoad = "/proc/loadavg"
)
var (
load1 = prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: Namespace,
Name: "load1",
Help: "1m load average.",
})
)
type loadavgCollector struct {
config Config
metric prometheus.Gauge
}
func init() {
@ -35,10 +28,14 @@ func init() {
// Takes a config struct and prometheus registry and returns a new Collector exposing
// load, seconds since last login and a list of tags as specified by config.
func NewLoadavgCollector(config Config) (Collector, error) {
c := loadavgCollector{
return &loadavgCollector{
config: config,
}
return &c, nil
metric: prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: Namespace,
Name: "load1",
Help: "1m load average.",
}),
}, nil
}
func (c *loadavgCollector) Update(ch chan<- prometheus.Metric) (err error) {
@ -47,8 +44,8 @@ func (c *loadavgCollector) Update(ch chan<- prometheus.Metric) (err error) {
return fmt.Errorf("Couldn't get load: %s", err)
}
glog.V(1).Infof("Set node_load: %f", load)
load1.Set(load)
load1.Collect(ch)
c.metric.Set(load)
c.metric.Collect(ch)
return err
}

View file

@ -17,32 +17,60 @@ const (
adapterHeaderSep = "================"
)
var (
driveTemperature = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Namespace: Namespace,
Name: "megacli_drive_temperature_celsius",
Help: "megacli: drive temperature",
}, []string{"enclosure", "slot"})
type megaCliCollector struct {
config Config
cli string
driveCounters = prometheus.NewCounterVec(prometheus.CounterOpts{
Namespace: Namespace,
Name: "megacli_drive_count",
Help: "megacli: drive error and event counters",
}, []string{"enclosure", "slot", "type"})
drivePresence = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Namespace: Namespace,
Name: "megacli_adapter_disk_presence",
Help: "megacli: disk presence per adapter",
}, []string{"type"})
counters = []string{"Media Error Count", "Other Error Count", "Predictive Failure Count"}
)
driveTemperature *prometheus.GaugeVec
driveCounters *prometheus.CounterVec
drivePresence *prometheus.GaugeVec
}
func init() {
Factories["megacli"] = NewMegaCliCollector
}
// Takes a config struct and prometheus registry and returns a new Collector exposing
// RAID status through megacli.
func NewMegaCliCollector(config Config) (Collector, error) {
cli := defaultMegaCli
if config.Config["megacli_command"] != "" {
cli = config.Config["megacli_command"]
}
return &megaCliCollector{
config: config,
cli: cli,
driveTemperature: prometheus.NewGaugeVec(prometheus.GaugeOpts{
Namespace: Namespace,
Name: "megacli_drive_temperature_celsius",
Help: "megacli: drive temperature",
}, []string{"enclosure", "slot"}),
driveCounters: prometheus.NewCounterVec(prometheus.CounterOpts{
Namespace: Namespace,
Name: "megacli_drive_count",
Help: "megacli: drive error and event counters",
}, []string{"enclosure", "slot", "type"}),
drivePresence: prometheus.NewGaugeVec(prometheus.GaugeOpts{
Namespace: Namespace,
Name: "megacli_adapter_disk_presence",
Help: "megacli: disk presence per adapter",
}, []string{"type"}),
}, nil
}
func (c *megaCliCollector) Update(ch chan<- prometheus.Metric) (err error) {
err = c.updateAdapter()
if err != nil {
return err
}
err = c.updateDisks()
c.driveTemperature.Collect(ch)
c.driveCounters.Collect(ch)
c.drivePresence.Collect(ch)
return err
}
func parseMegaCliDisks(r io.Reader) (map[int]map[int]map[string]string, error) {
var (
stats = map[int]map[int]map[string]string{}
@ -118,38 +146,6 @@ func parseMegaCliAdapter(r io.Reader) (map[string]map[string]string, error) {
return raidStats, nil
}
type megaCliCollector struct {
config Config
cli string
}
// Takes a config struct and prometheus registry and returns a new Collector exposing
// RAID status through megacli.
func NewMegaCliCollector(config Config) (Collector, error) {
cli := defaultMegaCli
if config.Config["megacli_command"] != "" {
cli = config.Config["megacli_command"]
}
c := megaCliCollector{
config: config,
cli: cli,
}
return &c, nil
}
func (c *megaCliCollector) Update(ch chan<- prometheus.Metric) (err error) {
err = c.updateAdapter()
if err != nil {
return err
}
err = c.updateDisks()
driveTemperature.Collect(ch)
driveCounters.Collect(ch)
drivePresence.Collect(ch)
return err
}
func (c *megaCliCollector) updateAdapter() error {
cmd := exec.Command(c.cli, "-AdpAllInfo", "-aALL")
pipe, err := cmd.StdoutPipe()
@ -174,12 +170,14 @@ func (c *megaCliCollector) updateAdapter() error {
if err != nil {
return err
}
drivePresence.WithLabelValues(k).Set(value)
c.drivePresence.WithLabelValues(k).Set(value)
}
return nil
}
func (c *megaCliCollector) updateDisks() error {
var counters = []string{"Media Error Count", "Other Error Count", "Predictive Failure Count"}
cmd := exec.Command(c.cli, "-PDList", "-aALL")
pipe, err := cmd.StdoutPipe()
if err != nil {
@ -210,15 +208,15 @@ func (c *megaCliCollector) updateDisks() error {
encStr := strconv.Itoa(enc)
slotStr := strconv.Itoa(slot)
driveTemperature.WithLabelValues(encStr, slotStr).Set(t)
c.driveTemperature.WithLabelValues(encStr, slotStr).Set(t)
for _, c := range counters {
counter, err := strconv.ParseFloat(slotStats[c], 64)
for _, i := range counters {
counter, err := strconv.ParseFloat(slotStats[i], 64)
if err != nil {
return err
}
driveCounters.WithLabelValues(encStr, slotStr, c).Set(counter)
c.driveCounters.WithLabelValues(encStr, slotStr, i).Set(counter)
}
}
}

View file

@ -20,12 +20,9 @@ const (
memInfoSubsystem = "memory"
)
var (
memInfoMetrics = map[string]prometheus.Gauge{}
)
type meminfoCollector struct {
config Config
config Config
metrics map[string]prometheus.Gauge
}
func init() {
@ -35,10 +32,10 @@ func init() {
// Takes a config struct and prometheus registry and returns a new Collector exposing
// memory stats.
func NewMeminfoCollector(config Config) (Collector, error) {
c := meminfoCollector{
config: config,
}
return &c, nil
return &meminfoCollector{
config: config,
metrics: map[string]prometheus.Gauge{},
}, nil
}
func (c *meminfoCollector) Update(ch chan<- prometheus.Metric) (err error) {
@ -48,16 +45,16 @@ func (c *meminfoCollector) Update(ch chan<- prometheus.Metric) (err error) {
}
glog.V(1).Infof("Set node_mem: %#v", memInfo)
for k, v := range memInfo {
if _, ok := memInfoMetrics[k]; !ok {
memInfoMetrics[k] = prometheus.NewGauge(prometheus.GaugeOpts{
if _, ok := c.metrics[k]; !ok {
c.metrics[k] = prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: memInfoSubsystem,
Name: k,
Help: k + " from /proc/meminfo.",
})
}
memInfoMetrics[k].Set(v)
memInfoMetrics[k].Collect(ch)
c.metrics[k].Set(v)
c.metrics[k].Collect(ch)
}
return err
}

View file

@ -18,12 +18,9 @@ const (
netDevSubsystem = "network"
)
var (
netDevMetrics = map[string]*prometheus.GaugeVec{}
)
type netDevCollector struct {
config Config
config Config
metrics map[string]*prometheus.GaugeVec
}
func init() {
@ -33,10 +30,10 @@ func init() {
// Takes a config struct and prometheus registry and returns a new Collector exposing
// network device stats.
func NewNetDevCollector(config Config) (Collector, error) {
c := netDevCollector{
config: config,
}
return &c, nil
return &netDevCollector{
config: config,
metrics: map[string]*prometheus.GaugeVec{},
}, nil
}
func (c *netDevCollector) Update(ch chan<- prometheus.Metric) (err error) {
@ -48,8 +45,8 @@ func (c *netDevCollector) Update(ch chan<- prometheus.Metric) (err error) {
for dev, stats := range devStats {
for t, value := range stats {
key := direction + "_" + t
if _, ok := netDevMetrics[key]; !ok {
netDevMetrics[key] = prometheus.NewGaugeVec(
if _, ok := c.metrics[key]; !ok {
c.metrics[key] = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: netDevSubsystem,
@ -63,11 +60,11 @@ func (c *netDevCollector) Update(ch chan<- prometheus.Metric) (err error) {
if err != nil {
return fmt.Errorf("Invalid value %s in netstats: %s", value, err)
}
netDevMetrics[key].WithLabelValues(dev).Set(v)
c.metrics[key].WithLabelValues(dev).Set(v)
}
}
}
for _, m := range netDevMetrics {
for _, m := range c.metrics {
m.Collect(ch)
}
return err

View file

@ -18,12 +18,9 @@ const (
netStatsSubsystem = "netstat"
)
var (
netStatsMetrics = map[string]prometheus.Gauge{}
)
type netStatCollector struct {
config Config
config Config
metrics map[string]prometheus.Gauge
}
func init() {
@ -33,10 +30,10 @@ func init() {
// NewNetStatCollector takes a config struct and returns
// a new Collector exposing network stats.
func NewNetStatCollector(config Config) (Collector, error) {
c := netStatCollector{
config: config,
}
return &c, nil
return &netStatCollector{
config: config,
metrics: map[string]prometheus.Gauge{},
}, nil
}
func (c *netStatCollector) Update(ch chan<- prometheus.Metric) (err error) {
@ -47,8 +44,8 @@ func (c *netStatCollector) Update(ch chan<- prometheus.Metric) (err error) {
for protocol, protocolStats := range netStats {
for name, value := range protocolStats {
key := protocol + "_" + name
if _, ok := netStatsMetrics[key]; !ok {
netStatsMetrics[key] = prometheus.NewGauge(
if _, ok := c.metrics[key]; !ok {
c.metrics[key] = prometheus.NewGauge(
prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: netStatsSubsystem,
@ -61,10 +58,10 @@ func (c *netStatCollector) Update(ch chan<- prometheus.Metric) (err error) {
if err != nil {
return fmt.Errorf("invalid value %s in netstats: %s", value, err)
}
netStatsMetrics[key].Set(v)
c.metrics[key].Set(v)
}
}
for _, m := range netStatsMetrics {
for _, m := range c.metrics {
m.Collect(ch)
}
return err

View file

@ -14,14 +14,10 @@ import (
var (
ntpServer = flag.String("ntpServer", "", "NTP server to use for ntp collector.")
ntpDrift = prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: Namespace,
Name: "ntp_drift_seconds",
Help: "Time between system time and ntp time.",
})
)
type ntpCollector struct {
drift prometheus.Gauge
}
func init() {
@ -34,9 +30,14 @@ func NewNtpCollector(config Config) (Collector, error) {
if *ntpServer == "" {
return nil, fmt.Errorf("No NTP server specifies, see --ntpServer")
}
c := ntpCollector{}
return &c, nil
return &ntpCollector{
drift: prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: Namespace,
Name: "ntp_drift_seconds",
Help: "Time between system time and ntp time.",
}),
}, nil
}
func (c *ntpCollector) Update(ch chan<- prometheus.Metric) (err error) {
@ -46,7 +47,7 @@ func (c *ntpCollector) Update(ch chan<- prometheus.Metric) (err error) {
}
drift := t.Sub(time.Now())
glog.V(1).Infof("Set ntp_drift_seconds: %f", drift.Seconds())
ntpDrift.Set(drift.Seconds())
ntpDrift.Collect(ch)
c.drift.Set(drift.Seconds())
c.drift.Collect(ch)
return err
}

View file

@ -8,37 +8,14 @@ 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,
)
const (
runitSubsystem = "runit"
)
type runitCollector struct {
config Config
state, stateDesired, stateNormal *prometheus.GaugeVec
}
func init() {
@ -46,14 +23,41 @@ func init() {
}
func NewRunitCollector(config Config) (Collector, error) {
c := runitCollector{
config: config,
}
var labels = []string{"service"}
return &c, nil
return &runitCollector{
config: config,
state: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: runitSubsystem,
Name: "state",
Help: "state of runit service.",
},
labels,
),
stateDesired: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: runitSubsystem,
Name: "desired_state",
Help: "desired state of runit service.",
},
labels,
),
stateNormal: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: runitSubsystem,
Name: "normal_state",
Help: "normal state of runit service.",
},
labels,
),
}, nil
}
func (c *runitCollector) Update(ch chan<- prometheus.Metric) (err error) {
func (c *runitCollector) Update(ch chan<- prometheus.Metric) error {
services, err := runit.GetServices("/etc/service")
if err != nil {
return err
@ -67,16 +71,17 @@ func (c *runitCollector) Update(ch chan<- prometheus.Metric) (err error) {
}
glog.V(1).Infof("%s is %d on pid %d for %d seconds", service.Name, status.State, status.Pid, status.Duration)
runitState.WithLabelValues(service.Name).Set(float64(status.State))
runitStateDesired.WithLabelValues(service.Name).Set(float64(status.Want))
c.state.WithLabelValues(service.Name).Set(float64(status.State))
c.stateDesired.WithLabelValues(service.Name).Set(float64(status.Want))
if status.NormallyUp {
runitStateNormal.WithLabelValues(service.Name).Set(1)
c.stateNormal.WithLabelValues(service.Name).Set(1)
} else {
runitStateNormal.WithLabelValues(service.Name).Set(1)
c.stateNormal.WithLabelValues(service.Name).Set(0)
}
}
runitState.Collect(ch)
runitStateDesired.Collect(ch)
runitStateNormal.Collect(ch)
return err
c.state.Collect(ch)
c.stateDesired.Collect(ch)
c.stateNormal.Collect(ch)
return nil
}

View file

@ -18,49 +18,15 @@ const (
procStat = "/proc/stat"
)
var (
cpuMetrics = prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Name: "cpu",
Help: "Seconds the cpus spent in each mode.",
},
[]string{"cpu", "mode"},
)
intrMetric = prometheus.NewCounter(prometheus.CounterOpts{
Namespace: Namespace,
Name: "intr",
Help: "Total number of interrupts serviced.",
})
ctxtMetric = prometheus.NewCounter(prometheus.CounterOpts{
Namespace: Namespace,
Name: "context_switches",
Help: "Total number of context switches.",
})
forksMetric = prometheus.NewCounter(prometheus.CounterOpts{
Namespace: Namespace,
Name: "forks",
Help: "Total number of forks.",
})
btimeMetric = prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: Namespace,
Name: "boot_time",
Help: "Node boot time, in unixtime.",
})
procsRunningMetric = prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: Namespace,
Name: "procs_running",
Help: "Number of processes in runnable state.",
})
procsBlockedMetric = prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: Namespace,
Name: "procs_blocked",
Help: "Number of processes blocked waiting for I/O to complete.",
})
)
type statCollector struct {
config Config
config Config
cpu *prometheus.CounterVec
intr prometheus.Counter
ctxt prometheus.Counter
forks prometheus.Counter
btime prometheus.Gauge
procsRunning prometheus.Gauge
procsBlocked prometheus.Gauge
}
func init() {
@ -70,10 +36,47 @@ func init() {
// Takes a config struct and prometheus registry and returns a new Collector exposing
// network device stats.
func NewStatCollector(config Config) (Collector, error) {
c := statCollector{
return &statCollector{
config: config,
}
return &c, nil
cpu: prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Name: "cpu",
Help: "Seconds the cpus spent in each mode.",
},
[]string{"cpu", "mode"},
),
intr: prometheus.NewCounter(prometheus.CounterOpts{
Namespace: Namespace,
Name: "intr",
Help: "Total number of interrupts serviced.",
}),
ctxt: prometheus.NewCounter(prometheus.CounterOpts{
Namespace: Namespace,
Name: "context_switches",
Help: "Total number of context switches.",
}),
forks: prometheus.NewCounter(prometheus.CounterOpts{
Namespace: Namespace,
Name: "forks",
Help: "Total number of forks.",
}),
btime: prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: Namespace,
Name: "boot_time",
Help: "Node boot time, in unixtime.",
}),
procsRunning: prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: Namespace,
Name: "procs_running",
Help: "Number of processes in runnable state.",
}),
procsBlocked: prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: Namespace,
Name: "procs_blocked",
Help: "Number of processes blocked waiting for I/O to complete.",
}),
}, nil
}
// Expose a variety of stats from /proc/stats.
@ -102,7 +105,7 @@ func (c *statCollector) Update(ch chan<- prometheus.Metric) (err error) {
}
// Convert from ticks to seconds
value /= float64(C.sysconf(C._SC_CLK_TCK))
cpuMetrics.With(prometheus.Labels{"cpu": parts[0], "mode": cpuFields[i]}).Set(value)
c.cpu.With(prometheus.Labels{"cpu": parts[0], "mode": cpuFields[i]}).Set(value)
}
case parts[0] == "intr":
// Only expose the overall number, use the 'interrupts' collector for more detail.
@ -110,45 +113,45 @@ func (c *statCollector) Update(ch chan<- prometheus.Metric) (err error) {
if err != nil {
return err
}
intrMetric.Set(value)
c.intr.Set(value)
case parts[0] == "ctxt":
value, err := strconv.ParseFloat(parts[1], 64)
if err != nil {
return err
}
ctxtMetric.Set(value)
c.ctxt.Set(value)
case parts[0] == "processes":
value, err := strconv.ParseFloat(parts[1], 64)
if err != nil {
return err
}
forksMetric.Set(value)
c.forks.Set(value)
case parts[0] == "btime":
value, err := strconv.ParseFloat(parts[1], 64)
if err != nil {
return err
}
btimeMetric.Set(value)
c.btime.Set(value)
case parts[0] == "procs_running":
value, err := strconv.ParseFloat(parts[1], 64)
if err != nil {
return err
}
procsRunningMetric.Set(value)
c.procsRunning.Set(value)
case parts[0] == "procs_blocked":
value, err := strconv.ParseFloat(parts[1], 64)
if err != nil {
return err
}
procsBlockedMetric.Set(value)
c.procsBlocked.Set(value)
}
}
cpuMetrics.Collect(ch)
ctxtMetric.Collect(ch)
intrMetric.Collect(ch)
forksMetric.Collect(ch)
btimeMetric.Collect(ch)
procsRunningMetric.Collect(ch)
procsBlockedMetric.Collect(ch)
c.cpu.Collect(ch)
c.ctxt.Collect(ch)
c.intr.Collect(ch)
c.forks.Collect(ch)
c.btime.Collect(ch)
c.procsRunning.Collect(ch)
c.procsBlocked.Collect(ch)
return err
}

View file

@ -9,16 +9,9 @@ import (
"github.com/prometheus/client_golang/prometheus"
)
var (
systemTime = prometheus.NewCounter(prometheus.CounterOpts{
Namespace: Namespace,
Name: "time",
Help: "System time in seconds since epoch (1970).",
})
)
type timeCollector struct {
config Config
metric prometheus.Counter
}
func init() {
@ -28,17 +21,20 @@ func init() {
// Takes a config struct and prometheus registry and returns a new Collector exposing
// the current system time in seconds since epoch.
func NewTimeCollector(config Config) (Collector, error) {
c := timeCollector{
return &timeCollector{
config: config,
}
return &c, nil
metric: prometheus.NewCounter(prometheus.CounterOpts{
Namespace: Namespace,
Name: "time",
Help: "System time in seconds since epoch (1970).",
}),
}, nil
}
func (c *timeCollector) Update(ch chan<- prometheus.Metric) (err error) {
now := time.Now()
glog.V(1).Infof("Set time: %f", now.Unix())
systemTime.Set(float64(now.Unix()))
systemTime.Collect(ch)
c.metric.Set(float64(now.Unix()))
c.metric.Collect(ch)
return err
}