From b1298677aa13a5f48dd5303120fa4a4bd4579ab9 Mon Sep 17 00:00:00 2001 From: Paul Gier Date: Wed, 10 Apr 2019 11:16:12 -0500 Subject: [PATCH] Early init of procfs (#1315) Minor change to match naming convention in other collectors. Initialize the proc or sys FS instance once while initializing each collector instead of re-creating for each metric update. Signed-off-by: Paul Gier --- collector/buddyinfo.go | 14 +++++++------- collector/cpu_linux.go | 12 +++++++----- collector/cpufreq_linux.go | 14 ++++++++------ collector/ipvs_linux.go | 2 +- collector/netclass_linux.go | 18 ++++++++++-------- collector/processes_linux.go | 28 +++++++++++++++------------- collector/processes_linux_test.go | 10 ++++++++-- collector/stat_linux.go | 12 +++++++----- 8 files changed, 63 insertions(+), 47 deletions(-) diff --git a/collector/buddyinfo.go b/collector/buddyinfo.go index 72e5f207..9ac790fc 100644 --- a/collector/buddyinfo.go +++ b/collector/buddyinfo.go @@ -30,6 +30,7 @@ const ( ) type buddyinfoCollector struct { + fs procfs.FS desc *prometheus.Desc } @@ -44,18 +45,17 @@ func NewBuddyinfoCollector() (Collector, error) { "Count of free blocks according to size.", []string{"node", "zone", "size"}, nil, ) - return &buddyinfoCollector{desc}, nil + fs, err := procfs.NewFS(*procPath) + if err != nil { + return nil, fmt.Errorf("failed to open procfs: %v", err) + } + return &buddyinfoCollector{fs, desc}, nil } // Update calls (*buddyinfoCollector).getBuddyInfo to get the platform specific // buddyinfo metrics. func (c *buddyinfoCollector) Update(ch chan<- prometheus.Metric) error { - fs, err := procfs.NewFS(*procPath) - if err != nil { - return fmt.Errorf("failed to open procfs: %v", err) - } - - buddyInfo, err := fs.NewBuddyInfo() + buddyInfo, err := c.fs.NewBuddyInfo() if err != nil { return fmt.Errorf("couldn't get buddyinfo: %s", err) } diff --git a/collector/cpu_linux.go b/collector/cpu_linux.go index be63590d..a8b34db4 100644 --- a/collector/cpu_linux.go +++ b/collector/cpu_linux.go @@ -26,6 +26,7 @@ import ( ) type cpuCollector struct { + fs procfs.FS cpu *prometheus.Desc cpuGuest *prometheus.Desc cpuCoreThrottle *prometheus.Desc @@ -38,7 +39,12 @@ func init() { // NewCPUCollector returns a new Collector exposing kernel/system statistics. func NewCPUCollector() (Collector, error) { + fs, err := procfs.NewFS(*procPath) + if err != nil { + return nil, fmt.Errorf("failed to open procfs: %v", err) + } return &cpuCollector{ + fs: fs, cpu: nodeCPUSecondsDesc, cpuGuest: prometheus.NewDesc( prometheus.BuildFQName(namespace, cpuCollectorSubsystem, "guest_seconds_total"), @@ -149,11 +155,7 @@ func (c *cpuCollector) updateThermalThrottle(ch chan<- prometheus.Metric) error // updateStat reads /proc/stat through procfs and exports cpu related metrics. func (c *cpuCollector) updateStat(ch chan<- prometheus.Metric) error { - fs, err := procfs.NewFS(*procPath) - if err != nil { - return fmt.Errorf("failed to open procfs: %v", err) - } - stats, err := fs.NewStat() + stats, err := c.fs.NewStat() if err != nil { return err } diff --git a/collector/cpufreq_linux.go b/collector/cpufreq_linux.go index 11f6f38e..badc16f7 100644 --- a/collector/cpufreq_linux.go +++ b/collector/cpufreq_linux.go @@ -23,6 +23,7 @@ import ( ) type cpuFreqCollector struct { + fs sysfs.FS cpuFreq *prometheus.Desc cpuFreqMin *prometheus.Desc cpuFreqMax *prometheus.Desc @@ -37,7 +38,13 @@ func init() { // NewCPUFreqCollector returns a new Collector exposing kernel/system statistics. func NewCPUFreqCollector() (Collector, error) { + fs, err := sysfs.NewFS(*sysPath) + if err != nil { + return nil, fmt.Errorf("failed to open sysfs: %v", err) + } + return &cpuFreqCollector{ + fs: fs, cpuFreq: prometheus.NewDesc( prometheus.BuildFQName(namespace, cpuCollectorSubsystem, "frequency_hertz"), "Current cpu thread frequency in hertz.", @@ -73,12 +80,7 @@ func NewCPUFreqCollector() (Collector, error) { // Update implements Collector and exposes cpu related metrics from /proc/stat and /sys/.../cpu/. func (c *cpuFreqCollector) Update(ch chan<- prometheus.Metric) error { - fs, err := sysfs.NewFS(*sysPath) - if err != nil { - return fmt.Errorf("failed to open sysfs: %v", err) - } - - cpuFreqs, err := fs.NewSystemCpufreq() + cpuFreqs, err := c.fs.NewSystemCpufreq() if err != nil { return err } diff --git a/collector/ipvs_linux.go b/collector/ipvs_linux.go index 37391933..524bac4d 100644 --- a/collector/ipvs_linux.go +++ b/collector/ipvs_linux.go @@ -58,7 +58,7 @@ func newIPVSCollector() (*ipvsCollector, error) { c.fs, err = procfs.NewFS(*procPath) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to open procfs: %v", err) } c.connections = typedDesc{prometheus.NewDesc( diff --git a/collector/netclass_linux.go b/collector/netclass_linux.go index d70db586..d02ead65 100644 --- a/collector/netclass_linux.go +++ b/collector/netclass_linux.go @@ -30,6 +30,7 @@ var ( ) type netClassCollector struct { + fs sysfs.FS subsystem string ignoredDevicesPattern *regexp.Regexp metricDescs map[string]*prometheus.Desc @@ -41,8 +42,13 @@ func init() { // NewNetClassCollector returns a new Collector exposing network class stats. func NewNetClassCollector() (Collector, error) { + fs, err := sysfs.NewFS(*sysPath) + if err != nil { + return nil, fmt.Errorf("failed to open sysfs: %v", err) + } pattern := regexp.MustCompile(*netclassIgnoredDevices) return &netClassCollector{ + fs: fs, subsystem: "network", ignoredDevicesPattern: pattern, metricDescs: map[string]*prometheus.Desc{}, @@ -50,7 +56,7 @@ func NewNetClassCollector() (Collector, error) { } func (c *netClassCollector) Update(ch chan<- prometheus.Metric) error { - netClass, err := getNetClassInfo(c.ignoredDevicesPattern) + netClass, err := c.getNetClassInfo() if err != nil { return fmt.Errorf("could not get net class info: %s", err) } @@ -162,19 +168,15 @@ func pushMetric(ch chan<- prometheus.Metric, subsystem string, name string, valu ch <- prometheus.MustNewConstMetric(fieldDesc, valueType, float64(value), ifaceName) } -func getNetClassInfo(ignore *regexp.Regexp) (sysfs.NetClass, error) { - fs, err := sysfs.NewFS(*sysPath) - if err != nil { - return nil, err - } - netClass, err := fs.NewNetClass() +func (c *netClassCollector) getNetClassInfo() (sysfs.NetClass, error) { + netClass, err := c.fs.NewNetClass() if err != nil { return netClass, fmt.Errorf("error obtaining net class info: %s", err) } for device := range netClass { - if ignore.MatchString(device) { + if c.ignoredDevicesPattern.MatchString(device) { delete(netClass, device) } } diff --git a/collector/processes_linux.go b/collector/processes_linux.go index f321560f..1ee012ec 100644 --- a/collector/processes_linux.go +++ b/collector/processes_linux.go @@ -25,6 +25,7 @@ import ( ) type processCollector struct { + fs procfs.FS threadAlloc *prometheus.Desc threadLimit *prometheus.Desc procsState *prometheus.Desc @@ -38,8 +39,13 @@ func init() { // NewProcessStatCollector returns a new Collector exposing process data read from the proc filesystem. func NewProcessStatCollector() (Collector, error) { + fs, err := procfs.NewFS(*procPath) + if err != nil { + return nil, fmt.Errorf("failed to open procfs: %v", err) + } subsystem := "processes" return &processCollector{ + fs: fs, threadAlloc: prometheus.NewDesc( prometheus.BuildFQName(namespace, subsystem, "threads"), "Allocated threads in system", @@ -63,39 +69,35 @@ func NewProcessStatCollector() (Collector, error) { ), }, nil } -func (t *processCollector) Update(ch chan<- prometheus.Metric) error { - pids, states, threads, err := getAllocatedThreads() +func (c *processCollector) Update(ch chan<- prometheus.Metric) error { + pids, states, threads, err := c.getAllocatedThreads() if err != nil { return fmt.Errorf("unable to retrieve number of allocated threads: %q", err) } - ch <- prometheus.MustNewConstMetric(t.threadAlloc, prometheus.GaugeValue, float64(threads)) + ch <- prometheus.MustNewConstMetric(c.threadAlloc, prometheus.GaugeValue, float64(threads)) maxThreads, err := readUintFromFile(procFilePath("sys/kernel/threads-max")) if err != nil { return fmt.Errorf("unable to retrieve limit number of threads: %q", err) } - ch <- prometheus.MustNewConstMetric(t.threadLimit, prometheus.GaugeValue, float64(maxThreads)) + ch <- prometheus.MustNewConstMetric(c.threadLimit, prometheus.GaugeValue, float64(maxThreads)) for state := range states { - ch <- prometheus.MustNewConstMetric(t.procsState, prometheus.GaugeValue, float64(states[state]), state) + ch <- prometheus.MustNewConstMetric(c.procsState, prometheus.GaugeValue, float64(states[state]), state) } pidM, err := readUintFromFile(procFilePath("sys/kernel/pid_max")) if err != nil { return fmt.Errorf("unable to retrieve limit number of maximum pids alloved: %q", err) } - ch <- prometheus.MustNewConstMetric(t.pidUsed, prometheus.GaugeValue, float64(pids)) - ch <- prometheus.MustNewConstMetric(t.pidMax, prometheus.GaugeValue, float64(pidM)) + ch <- prometheus.MustNewConstMetric(c.pidUsed, prometheus.GaugeValue, float64(pids)) + ch <- prometheus.MustNewConstMetric(c.pidMax, prometheus.GaugeValue, float64(pidM)) return nil } -func getAllocatedThreads() (int, map[string]int32, int, error) { - fs, err := procfs.NewFS(*procPath) - if err != nil { - return 0, nil, 0, err - } - p, err := fs.AllProcs() +func (c *processCollector) getAllocatedThreads() (int, map[string]int32, int, error) { + p, err := c.fs.AllProcs() if err != nil { return 0, nil, 0, err } diff --git a/collector/processes_linux_test.go b/collector/processes_linux_test.go index 1cf9e4f0..dc71cedf 100644 --- a/collector/processes_linux_test.go +++ b/collector/processes_linux_test.go @@ -18,7 +18,8 @@ package collector import ( "testing" - "gopkg.in/alecthomas/kingpin.v2" + "github.com/prometheus/procfs" + kingpin "gopkg.in/alecthomas/kingpin.v2" ) func TestReadProcessStatus(t *testing.T) { @@ -26,7 +27,12 @@ func TestReadProcessStatus(t *testing.T) { t.Fatal(err) } want := 1 - pids, states, threads, err := getAllocatedThreads() + fs, err := procfs.NewFS(*procPath) + if err != nil { + t.Errorf("failed to open procfs: %v", err) + } + c := processCollector{fs: fs} + pids, states, threads, err := c.getAllocatedThreads() if err != nil { t.Fatalf("Cannot retrieve data from procfs getAllocatedThreads function: %v ", err) } diff --git a/collector/stat_linux.go b/collector/stat_linux.go index 290205f5..13a4b019 100644 --- a/collector/stat_linux.go +++ b/collector/stat_linux.go @@ -24,6 +24,7 @@ import ( ) type statCollector struct { + fs procfs.FS intr *prometheus.Desc ctxt *prometheus.Desc forks *prometheus.Desc @@ -38,7 +39,12 @@ func init() { // NewStatCollector returns a new Collector exposing kernel/system statistics. func NewStatCollector() (Collector, error) { + fs, err := procfs.NewFS(*procPath) + if err != nil { + return nil, fmt.Errorf("failed to open procfs: %v", err) + } return &statCollector{ + fs: fs, intr: prometheus.NewDesc( prometheus.BuildFQName(namespace, "", "intr_total"), "Total number of interrupts serviced.", @@ -74,11 +80,7 @@ func NewStatCollector() (Collector, error) { // Update implements Collector and exposes kernel and system statistics. func (c *statCollector) Update(ch chan<- prometheus.Metric) error { - fs, err := procfs.NewFS(*procPath) - if err != nil { - return fmt.Errorf("failed to open procfs: %v", err) - } - stats, err := fs.NewStat() + stats, err := c.fs.NewStat() if err != nil { return err }