Migrate arp_linux.go to procfs

Signed-off-by: James Bach <qweet.ing@gmail.com>
Signed-off-by: James Bach <james.bach@wise.com>
Signed-off-by: jalev <qweet.ing@gmail.com>
pull/2553/head
James Bach 2022-12-13 15:45:49 +00:00 committed by Johannes 'fish' Ziemke
parent da08a2959f
commit 5538773089
1 changed files with 17 additions and 45 deletions

View File

@ -17,14 +17,10 @@
package collector package collector
import ( import (
"bufio"
"fmt" "fmt"
"io"
"os"
"strings"
"github.com/go-kit/log" "github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/procfs"
"gopkg.in/alecthomas/kingpin.v2" "gopkg.in/alecthomas/kingpin.v2"
) )
@ -34,6 +30,7 @@ var (
) )
type arpCollector struct { type arpCollector struct {
fs procfs.FS
deviceFilter deviceFilter deviceFilter deviceFilter
entries *prometheus.Desc entries *prometheus.Desc
logger log.Logger logger log.Logger
@ -45,7 +42,13 @@ func init() {
// NewARPCollector returns a new Collector exposing ARP stats. // NewARPCollector returns a new Collector exposing ARP stats.
func NewARPCollector(logger log.Logger) (Collector, error) { func NewARPCollector(logger log.Logger) (Collector, error) {
fs, err := procfs.NewFS(*procPath)
if err != nil {
return nil, fmt.Errorf("failed to open procfs: %w", err)
}
return &arpCollector{ return &arpCollector{
fs: fs,
deviceFilter: newDeviceFilter(*arpDeviceExclude, *arpDeviceInclude), deviceFilter: newDeviceFilter(*arpDeviceExclude, *arpDeviceInclude),
entries: prometheus.NewDesc( entries: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "arp", "entries"), prometheus.BuildFQName(namespace, "arp", "entries"),
@ -56,61 +59,30 @@ func NewARPCollector(logger log.Logger) (Collector, error) {
}, nil }, nil
} }
func getARPEntries() (map[string]uint32, error) { func getTotalArpEntries(deviceEntries []procfs.ARPEntry) map[string]uint32 {
file, err := os.Open(procFilePath("net/arp"))
if err != nil {
return nil, err
}
defer file.Close()
entries, err := parseARPEntries(file)
if err != nil {
return nil, err
}
return entries, nil
}
// TODO: This should get extracted to the github.com/prometheus/procfs package
// to support more complete parsing of /proc/net/arp. Instead of adding
// more fields to this function's return values it should get moved and
// changed to support each field.
func parseARPEntries(data io.Reader) (map[string]uint32, error) {
scanner := bufio.NewScanner(data)
entries := make(map[string]uint32) entries := make(map[string]uint32)
for scanner.Scan() { for _, device := range deviceEntries {
columns := strings.Fields(scanner.Text()) entries[device.Device] += 1
if len(columns) < 6 {
return nil, fmt.Errorf("unexpected ARP table format")
}
if columns[0] != "IP" {
deviceIndex := len(columns) - 1
entries[columns[deviceIndex]]++
}
} }
if err := scanner.Err(); err != nil { return entries
return nil, fmt.Errorf("failed to parse ARP info: %w", err)
}
return entries, nil
} }
func (c *arpCollector) Update(ch chan<- prometheus.Metric) error { func (c *arpCollector) Update(ch chan<- prometheus.Metric) error {
entries, err := getARPEntries() entries, err := c.fs.GatherARPEntries()
if err != nil { if err != nil {
return fmt.Errorf("could not get ARP entries: %w", err) return fmt.Errorf("could not get ARP entries: %w", err)
} }
for device, entryCount := range entries { enumeratedEntry := getTotalArpEntries(entries)
for device, entry := range enumeratedEntry {
if c.deviceFilter.ignored(device) { if c.deviceFilter.ignored(device) {
continue continue
} }
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.entries, prometheus.GaugeValue, float64(entryCount), device) c.entries, prometheus.GaugeValue, float64(entry), device)
} }
return nil return nil