Revamp the netdev collector to use throw-away ConstMetrics.

This commit is contained in:
Martín Ferrari 2015-09-15 15:31:51 +00:00
commit 13672ced48
3 changed files with 85 additions and 108 deletions

View file

@ -17,19 +17,20 @@ import (
)
const (
procNetDev = "/proc/net/dev"
netDevSubsystem = "network"
procNetDev = "/proc/net/dev"
subsystem = "network"
)
var (
fieldSep = regexp.MustCompile("[ :] *")
netdevIgnoredDevices = flag.String("collector.netdev.ignored-devices", "^$", "Regexp of net devices to ignore for netdev collector.")
fieldSep = regexp.MustCompile("[ :] *")
netdevIgnoredDevices = flag.String(
"collector.netdev.ignored-devices", "^$",
"Regexp of net devices to ignore for netdev collector.")
)
type netDevCollector struct {
ignoredDevicesPattern *regexp.Regexp
metrics map[string]*prometheus.GaugeVec
metricDescs map[string]*prometheus.Desc
}
func init() {
@ -39,9 +40,10 @@ func init() {
// Takes a prometheus registry and returns a new Collector exposing
// network device stats.
func NewNetDevCollector() (Collector, error) {
pattern := regexp.MustCompile(*netdevIgnoredDevices)
return &netDevCollector{
ignoredDevicesPattern: regexp.MustCompile(*netdevIgnoredDevices),
metrics: map[string]*prometheus.GaugeVec{},
ignoredDevicesPattern: pattern,
metricDescs: map[string]*prometheus.Desc{},
}, nil
}
@ -50,36 +52,34 @@ func (c *netDevCollector) Update(ch chan<- prometheus.Metric) (err error) {
if err != nil {
return fmt.Errorf("Couldn't get netstats: %s", err)
}
for direction, devStats := range netDev {
for dev, stats := range devStats {
for t, value := range stats {
key := direction + "_" + t
if _, ok := c.metrics[key]; !ok {
c.metrics[key] = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: netDevSubsystem,
Name: key,
Help: fmt.Sprintf("%s %s from /proc/net/dev.", t, direction),
},
[]string{"device"},
)
}
v, err := strconv.ParseFloat(value, 64)
if err != nil {
return fmt.Errorf("Invalid value %s in netstats: %s", value, err)
}
c.metrics[key].WithLabelValues(dev).Set(v)
for dev, devStats := range netDev {
for key, value := range devStats {
desc, ok := c.metricDescs[key]
if !ok {
desc = prometheus.NewDesc(
prometheus.BuildFQName(
Namespace, subsystem, key),
fmt.Sprintf(
"%s from /proc/net/dev.", key),
[]string{"device"},
nil,
)
c.metricDescs[key] = desc
}
v, err := strconv.ParseFloat(value, 64)
if err != nil {
return fmt.Errorf(
"Invalid value %s in netstats: %s",
value, err)
}
ch <- prometheus.MustNewConstMetric(
desc, prometheus.GaugeValue, v, dev)
}
}
for _, m := range c.metrics {
m.Collect(ch)
}
return err
return nil
}
func getNetDevStats(ignore *regexp.Regexp) (map[string]map[string]map[string]string, error) {
func getNetDevStats(ignore *regexp.Regexp) (map[string]map[string]string, error) {
file, err := os.Open(procNetDev)
if err != nil {
return nil, err
@ -89,11 +89,7 @@ func getNetDevStats(ignore *regexp.Regexp) (map[string]map[string]map[string]str
return parseNetDevStats(file, ignore)
}
func parseNetDevStats(r io.Reader, ignore *regexp.Regexp) (map[string]map[string]map[string]string, error) {
netDev := map[string]map[string]map[string]string{}
netDev["transmit"] = map[string]map[string]string{}
netDev["receive"] = map[string]map[string]string{}
func parseNetDevStats(r io.Reader, ignore *regexp.Regexp) (map[string]map[string]string, error) {
scanner := bufio.NewScanner(r)
scanner.Scan() // skip first header
scanner.Scan()
@ -102,7 +98,9 @@ func parseNetDevStats(r io.Reader, ignore *regexp.Regexp) (map[string]map[string
return nil, fmt.Errorf("Invalid header line in %s: %s",
procNetDev, scanner.Text())
}
header := strings.Fields(parts[1])
netDev := map[string]map[string]string{}
for scanner.Scan() {
line := strings.TrimLeft(string(scanner.Text()), " ")
parts := fieldSep.Split(line, -1)
@ -112,30 +110,15 @@ func parseNetDevStats(r io.Reader, ignore *regexp.Regexp) (map[string]map[string
}
dev := parts[0][:len(parts[0])]
receive, err := parseNetDevLine(parts[1:len(header)+1], header)
if err != nil {
return nil, err
}
transmit, err := parseNetDevLine(parts[len(header)+1:], header)
if err != nil {
return nil, err
}
if ignore.MatchString(dev) {
log.Debugf("Ignoring device: %s", dev)
continue
}
netDev["transmit"][dev] = transmit
netDev["receive"][dev] = receive
netDev[dev] = map[string]string{}
for i, v := range header {
netDev[dev]["receive_" + v] = parts[i+1]
netDev[dev]["transmit_" + v] = parts[i+1+len(header)]
}
}
return netDev, nil
}
func parseNetDevLine(parts []string, header []string) (map[string]string, error) {
devStats := map[string]string{}
for i, v := range parts {
devStats[header[i]] = v
}
return devStats, nil
}