diff --git a/collector/arp_linux.go b/collector/arp_linux.go index c7861156f3..7d8e7edc40 100644 --- a/collector/arp_linux.go +++ b/collector/arp_linux.go @@ -21,7 +21,6 @@ import ( "fmt" "net" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/jsimonetti/rtnetlink" "github.com/prometheus/client_golang/prometheus" @@ -29,17 +28,12 @@ import ( "golang.org/x/sys/unix" ) -var ( - arpDeviceInclude = kingpin.Flag("collector.arp.device-include", "Regexp of arp devices to include (mutually exclusive to device-exclude).").String() - arpDeviceExclude = kingpin.Flag("collector.arp.device-exclude", "Regexp of arp devices to exclude (mutually exclusive to device-include).").String() - arpNetlink = kingpin.Flag("collector.arp.netlink", "Use netlink to gather stats instead of /proc/net/arp.").Default("true").Bool() -) - type arpCollector struct { fs procfs.FS deviceFilter deviceFilter entries *prometheus.Desc logger log.Logger + config *NodeCollectorConfig } func init() { @@ -47,21 +41,22 @@ func init() { } // NewARPCollector returns a new Collector exposing ARP stats. -func NewARPCollector(logger log.Logger) (Collector, error) { - fs, err := procfs.NewFS(*procPath) +func NewARPCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := procfs.NewFS(*config.Path.ProcPath) if err != nil { return nil, fmt.Errorf("failed to open procfs: %w", err) } return &arpCollector{ fs: fs, - deviceFilter: newDeviceFilter(*arpDeviceExclude, *arpDeviceInclude), + deviceFilter: newDeviceFilter(*config.Arp.DeviceExclude, *config.Arp.DeviceInclude), entries: prometheus.NewDesc( prometheus.BuildFQName(namespace, "arp", "entries"), "ARP entries by device", []string{"device"}, nil, ), logger: logger, + config: config, }, nil } @@ -119,7 +114,7 @@ func getTotalArpEntriesRTNL() (map[string]uint32, error) { func (c *arpCollector) Update(ch chan<- prometheus.Metric) error { var enumeratedEntry map[string]uint32 - if *arpNetlink { + if *c.config.Arp.Netlink { var err error enumeratedEntry, err = getTotalArpEntriesRTNL() diff --git a/collector/bcache_linux.go b/collector/bcache_linux.go index 1d402d3ff5..bcae26868e 100644 --- a/collector/bcache_linux.go +++ b/collector/bcache_linux.go @@ -19,30 +19,27 @@ package collector import ( "fmt" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/procfs/bcache" ) -var ( - priorityStats = kingpin.Flag("collector.bcache.priorityStats", "Expose expensive priority stats.").Bool() -) - func init() { registerCollector("bcache", defaultEnabled, NewBcacheCollector) + } // A bcacheCollector is a Collector which gathers metrics from Linux bcache. type bcacheCollector struct { fs bcache.FS logger log.Logger + config *NodeCollectorConfig } // NewBcacheCollector returns a newly allocated bcacheCollector. // It exposes a number of Linux bcache statistics. -func NewBcacheCollector(logger log.Logger) (Collector, error) { - fs, err := bcache.NewFS(*sysPath) +func NewBcacheCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := bcache.NewFS(*config.Path.SysPath) if err != nil { return nil, fmt.Errorf("failed to open sysfs: %w", err) } @@ -50,6 +47,7 @@ func NewBcacheCollector(logger log.Logger) (Collector, error) { return &bcacheCollector{ fs: fs, logger: logger, + config: config, }, nil } @@ -58,7 +56,7 @@ func NewBcacheCollector(logger log.Logger) (Collector, error) { func (c *bcacheCollector) Update(ch chan<- prometheus.Metric) error { var stats []*bcache.Stats var err error - if *priorityStats { + if *c.config.Bcache.PriorityStats { stats, err = c.fs.Stats() } else { stats, err = c.fs.StatsWithoutPriority() @@ -317,7 +315,7 @@ func (c *bcacheCollector) updateBcacheStats(ch chan<- prometheus.Metric, s *bcac extraLabelValue: cache.Name, }, } - if *priorityStats { + if *c.config.Bcache.PriorityStats { // metrics in /sys/fs/bcache///priority_stats priorityStatsMetrics := []bcacheMetric{ { diff --git a/collector/bonding_linux.go b/collector/bonding_linux.go index d9d04e222c..df54552c7b 100644 --- a/collector/bonding_linux.go +++ b/collector/bonding_linux.go @@ -31,6 +31,7 @@ import ( type bondingCollector struct { slaves, active typedDesc logger log.Logger + config *NodeCollectorConfig } func init() { @@ -39,7 +40,7 @@ func init() { // NewBondingCollector returns a newly allocated bondingCollector. // It exposes the number of configured and active slave of linux bonding interfaces. -func NewBondingCollector(logger log.Logger) (Collector, error) { +func NewBondingCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &bondingCollector{ slaves: typedDesc{prometheus.NewDesc( prometheus.BuildFQName(namespace, "bonding", "slaves"), @@ -52,12 +53,13 @@ func NewBondingCollector(logger log.Logger) (Collector, error) { []string{"master"}, nil, ), prometheus.GaugeValue}, logger: logger, + config: config, }, nil } // Update reads and exposes bonding states, implements Collector interface. Caution: This works only on linux. func (c *bondingCollector) Update(ch chan<- prometheus.Metric) error { - statusfile := sysFilePath("class/net") + statusfile := c.config.Path.sysFilePath("class/net") bondingStats, err := readBondingStats(statusfile) if err != nil { if errors.Is(err, os.ErrNotExist) { diff --git a/collector/boot_time_bsd.go b/collector/boot_time_bsd.go index 8a9c17b31a..ba49b965b0 100644 --- a/collector/boot_time_bsd.go +++ b/collector/boot_time_bsd.go @@ -32,7 +32,7 @@ func init() { } // newBootTimeCollector returns a new Collector exposing system boot time on BSD systems. -func newBootTimeCollector(logger log.Logger) (Collector, error) { +func newBootTimeCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &bootTimeCollector{ logger: logger, }, nil diff --git a/collector/boot_time_solaris.go b/collector/boot_time_solaris.go index 15955121f7..758c30d647 100644 --- a/collector/boot_time_solaris.go +++ b/collector/boot_time_solaris.go @@ -31,7 +31,7 @@ func init() { registerCollector("boottime", defaultEnabled, newBootTimeCollector) } -func newBootTimeCollector(logger log.Logger) (Collector, error) { +func newBootTimeCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &bootTimeCollector{ boottime: typedDesc{ prometheus.NewDesc( diff --git a/collector/btrfs_linux.go b/collector/btrfs_linux.go index f1490541a9..831e35d70b 100644 --- a/collector/btrfs_linux.go +++ b/collector/btrfs_linux.go @@ -33,6 +33,7 @@ import ( type btrfsCollector struct { fs btrfs.FS logger log.Logger + config *NodeCollectorConfig } func init() { @@ -40,8 +41,8 @@ func init() { } // NewBtrfsCollector returns a new Collector exposing Btrfs statistics. -func NewBtrfsCollector(logger log.Logger) (Collector, error) { - fs, err := btrfs.NewFS(*sysPath) +func NewBtrfsCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := btrfs.NewFS(*config.Path.SysPath) if err != nil { return nil, fmt.Errorf("failed to open sysfs: %w", err) } @@ -49,6 +50,7 @@ func NewBtrfsCollector(logger log.Logger) (Collector, error) { return &btrfsCollector{ fs: fs, logger: logger, + config: config, }, nil } @@ -103,7 +105,7 @@ type btrfsIoctlFsStats struct { func (c *btrfsCollector) getIoctlStats() (map[string]*btrfsIoctlFsStats, error) { // Instead of introducing more ioctl calls to scan for all btrfs // filesystems re-use our mount point utils to find known mounts - mountsList, err := mountPointDetails(c.logger) + mountsList, err := mountPointDetails(c.config, c.logger) if err != nil { return nil, err } @@ -123,7 +125,7 @@ func (c *btrfsCollector) getIoctlStats() (map[string]*btrfsIoctlFsStats, error) continue } - mountPath := rootfsFilePath(mount.mountPoint) + mountPath := c.config.Path.rootfsFilePath(mount.mountPoint) fs, err := dennwc.Open(mountPath, true) if err != nil { diff --git a/collector/buddyinfo.go b/collector/buddyinfo.go index c3cc5e046d..4f5708d35d 100644 --- a/collector/buddyinfo.go +++ b/collector/buddyinfo.go @@ -41,13 +41,13 @@ func init() { } // NewBuddyinfoCollector returns a new Collector exposing buddyinfo stats. -func NewBuddyinfoCollector(logger log.Logger) (Collector, error) { +func NewBuddyinfoCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { desc := prometheus.NewDesc( prometheus.BuildFQName(namespace, buddyInfoSubsystem, "blocks"), "Count of free blocks according to size.", []string{"node", "zone", "size"}, nil, ) - fs, err := procfs.NewFS(*procPath) + fs, err := procfs.NewFS(*config.Path.ProcPath) if err != nil { return nil, fmt.Errorf("failed to open procfs: %w", err) } diff --git a/collector/cgroups_linux.go b/collector/cgroups_linux.go index 9f6d01a465..4363a2149a 100644 --- a/collector/cgroups_linux.go +++ b/collector/cgroups_linux.go @@ -38,8 +38,8 @@ func init() { } // NewCgroupSummaryCollector returns a new Collector exposing a summary of cgroups. -func NewCgroupSummaryCollector(logger log.Logger) (Collector, error) { - fs, err := procfs.NewFS(*procPath) +func NewCgroupSummaryCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := procfs.NewFS(*config.Path.ProcPath) if err != nil { return nil, fmt.Errorf("failed to open procfs: %w", err) } diff --git a/collector/collector.go b/collector/collector.go index 3112c78970..1678bcaa73 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -50,27 +50,39 @@ const ( ) var ( - factories = make(map[string]func(logger log.Logger) (Collector, error)) + factories = make(map[string]func(config *NodeCollectorConfig, logger log.Logger) (Collector, error)) initiatedCollectorsMtx = sync.Mutex{} initiatedCollectors = make(map[string]Collector) - collectorState = make(map[string]*bool) + collectorStateGlobal = make(map[string]bool) + collectorFlagState = make(map[string]*bool) + availableCollectors = make([]string, 0) forcedCollectors = map[string]bool{} // collectors which have been explicitly enabled or disabled ) -func registerCollector(collector string, isDefaultEnabled bool, factory func(logger log.Logger) (Collector, error)) { +func GetFlagDefaults() map[string]bool { + defaults := make(map[string]bool) + for k, v := range collectorFlagState { + defaults[k] = *v + } + return defaults +} + +func registerCollector(collector string, isDefaultEnabled bool, factory func(config *NodeCollectorConfig, logger log.Logger) (Collector, error)) { var helpDefaultState string if isDefaultEnabled { helpDefaultState = "enabled" } else { helpDefaultState = "disabled" } + availableCollectors = append(availableCollectors, collector) flagName := fmt.Sprintf("collector.%s", collector) flagHelp := fmt.Sprintf("Enable the %s collector (default: %s).", collector, helpDefaultState) defaultValue := fmt.Sprintf("%v", isDefaultEnabled) flag := kingpin.Flag(flagName, flagHelp).Default(defaultValue).Action(collectorFlagAction(collector)).Bool() - collectorState[collector] = flag + collectorStateGlobal[collector] = isDefaultEnabled + collectorFlagState[collector] = flag factories[collector] = factory } @@ -84,9 +96,9 @@ type NodeCollector struct { // DisableDefaultCollectors sets the collector state to false for all collectors which // have not been explicitly enabled on the command line. func DisableDefaultCollectors() { - for c := range collectorState { + for c := range collectorFlagState { if _, ok := forcedCollectors[c]; !ok { - *collectorState[c] = false + *collectorFlagState[c] = false } } } @@ -104,29 +116,30 @@ func collectorFlagAction(collector string) func(ctx *kingpin.ParseContext) error } // NewNodeCollector creates a new NodeCollector. -func NewNodeCollector(logger log.Logger, filters ...string) (*NodeCollector, error) { +func NewNodeCollector(config *NodeCollectorConfig, logger log.Logger, filters ...string) (*NodeCollector, error) { f := make(map[string]bool) for _, filter := range filters { - enabled, exist := collectorState[filter] + enabled, exist := config.Collectors[filter] if !exist { return nil, fmt.Errorf("missing collector: %s", filter) } - if !*enabled { + if !enabled { return nil, fmt.Errorf("disabled collector: %s", filter) } f[filter] = true } collectors := make(map[string]Collector) + initiatedCollectorsMtx.Lock() defer initiatedCollectorsMtx.Unlock() - for key, enabled := range collectorState { - if !*enabled || (len(f) > 0 && !f[key]) { + for key, enabled := range config.Collectors { + if !enabled || (len(f) > 0 && !f[key]) { continue } - if collector, ok := initiatedCollectors[key]; ok { + if collector, ok := initiatedCollectors[key]; ok && config.AllowCachingOfCollectors { collectors[key] = collector } else { - collector, err := factories[key](log.With(logger, "collector", key)) + collector, err := factories[key](config, log.With(logger, "collector", key)) if err != nil { return nil, err } diff --git a/collector/config.go b/collector/config.go new file mode 100644 index 0000000000..32cbba8deb --- /dev/null +++ b/collector/config.go @@ -0,0 +1,209 @@ +// Copyright 2023 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package collector + +import "time" + +type NodeCollectorConfig struct { + Arp ArpConfig + Bcache BcacheConfig + CPU CPUConfig + DiskstatsDeviceFilter DiskstatsDeviceFilterConfig + Ethtool EthtoolConfig + Filesystem FilesystemConfig + HwMon HwMonConfig + IPVS IPVSConfig + NetClass NetClassConfig + NetDev NetDevConfig + NetStat NetStatConfig + NTP NTPConfig + Path PathConfig + Perf PerfConfig + PowerSupplyClass PowerSupplyClassConfig + Qdisc QdiscConfig + Rapl RaplConfig + Runit RunitConfig + Stat StatConfig + Supervisord SupervisordConfig + Sysctl SysctlConfig + Systemd SystemdConfig + Tapestats TapestatsConfig + TextFile TextFileConfig + VmStat VmStatConfig + Wifi WifiConfig + + Collectors map[string]bool + AllowCachingOfCollectors bool +} + +type WifiConfig struct { + Fixtures *string +} + +type VmStatConfig struct { + Fields *string +} + +type TextFileConfig struct { + Directory *string +} +type TapestatsConfig struct { + IgnoredDevices *string +} + +type SystemdConfig struct { + UnitInclude *string + UnitIncludeSet bool + UnitExclude *string + UnitExcludeSet bool + OldUnitInclude *string + OldUnitExclude *string + Private *bool + EnableTaskMetrics *bool + EnableRestartsMetrics *bool + EnableStartTimeMetrics *bool +} + +type SysctlConfig struct { + Include *[]string + IncludeInfo *[]string +} + +type SupervisordConfig struct { + URL *string +} + +type RunitConfig struct { + ServiceDir *string +} + +type StatConfig struct { + Softirq *bool +} + +type RaplConfig struct { + ZoneLabel *bool +} + +type QdiscConfig struct { + Fixtures *string + DeviceInclude *string + OldDeviceInclude *string + DeviceExclude *string + OldDeviceExclude *string +} + +type PowerSupplyClassConfig struct { + IgnoredPowerSupplies *string +} + +type PerfConfig struct { + CPUs *string + Tracepoint *[]string + NoHwProfiler *bool + HwProfiler *[]string + NoSwProfiler *bool + SwProfiler *[]string + NoCaProfiler *bool + CaProfilerFlag *[]string +} + +type PathConfig struct { + ProcPath *string + SysPath *string + RootfsPath *string + UdevDataPath *string +} + +type NTPConfig struct { + Server *string + ServerPort *int + ProtocolVersion *int + ServerIsLocal *bool + IPTTL *int + MaxDistance *time.Duration + OffsetTolerance *time.Duration +} + +type NetStatConfig struct { + Fields *string +} + +type NetDevConfig struct { + DeviceInclude *string + OldDeviceInclude *string + DeviceExclude *string + OldDeviceExclude *string + AddressInfo *bool + DetailedMetrics *bool + Netlink *bool +} + +type NetClassConfig struct { + IgnoredDevices *string + InvalidSpeed *bool + Netlink *bool + RTNLWithStats *bool +} + +type ArpConfig struct { + DeviceInclude *string + DeviceExclude *string + Netlink *bool +} + +type BcacheConfig struct { + PriorityStats *bool +} + +type CPUConfig struct { + EnableCPUGuest *bool + EnableCPUInfo *bool + FlagsInclude *string + BugsInclude *string +} + +type DiskstatsDeviceFilterConfig struct { + DeviceExclude *string + DeviceExcludeSet bool + OldDeviceExclude *string + DeviceInclude *string +} + +type EthtoolConfig struct { + DeviceInclude *string + DeviceExclude *string + IncludedMetrics *string +} + +type HwMonConfig struct { + ChipInclude *string + ChipExclude *string +} + +type FilesystemConfig struct { + MountPointsExclude *string + MountPointsExcludeSet bool + OldMountPointsExcluded *string + FSTypesExclude *string + FSTypesExcludeSet bool + OldFSTypesExcluded *string + MountTimeout *time.Duration + StatWorkerCount *int +} + +type IPVSConfig struct { + Labels *string + LabelsSet bool +} diff --git a/collector/conntrack_linux.go b/collector/conntrack_linux.go index e4ea954900..a035fa935d 100644 --- a/collector/conntrack_linux.go +++ b/collector/conntrack_linux.go @@ -39,6 +39,7 @@ type conntrackCollector struct { earlyDrop *prometheus.Desc searchRestart *prometheus.Desc logger log.Logger + config *NodeCollectorConfig } type conntrackStatistics struct { @@ -57,7 +58,7 @@ func init() { } // NewConntrackCollector returns a new Collector exposing conntrack stats. -func NewConntrackCollector(logger log.Logger) (Collector, error) { +func NewConntrackCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &conntrackCollector{ current: prometheus.NewDesc( prometheus.BuildFQName(namespace, "", "nf_conntrack_entries"), @@ -110,25 +111,26 @@ func NewConntrackCollector(logger log.Logger) (Collector, error) { nil, nil, ), logger: logger, + config: config, }, nil } func (c *conntrackCollector) Update(ch chan<- prometheus.Metric) error { - value, err := readUintFromFile(procFilePath("sys/net/netfilter/nf_conntrack_count")) + value, err := readUintFromFile(c.config.Path.procFilePath("sys/net/netfilter/nf_conntrack_count")) if err != nil { return c.handleErr(err) } ch <- prometheus.MustNewConstMetric( c.current, prometheus.GaugeValue, float64(value)) - value, err = readUintFromFile(procFilePath("sys/net/netfilter/nf_conntrack_max")) + value, err = readUintFromFile(c.config.Path.procFilePath("sys/net/netfilter/nf_conntrack_max")) if err != nil { return c.handleErr(err) } ch <- prometheus.MustNewConstMetric( c.limit, prometheus.GaugeValue, float64(value)) - conntrackStats, err := getConntrackStatistics() + conntrackStats, err := getConntrackStatistics(c.config) if err != nil { return c.handleErr(err) } @@ -160,10 +162,10 @@ func (c *conntrackCollector) handleErr(err error) error { return fmt.Errorf("failed to retrieve conntrack stats: %w", err) } -func getConntrackStatistics() (*conntrackStatistics, error) { +func getConntrackStatistics(config *NodeCollectorConfig) (*conntrackStatistics, error) { c := conntrackStatistics{} - fs, err := procfs.NewFS(*procPath) + fs, err := procfs.NewFS(*config.Path.ProcPath) if err != nil { return nil, fmt.Errorf("failed to open procfs: %w", err) } diff --git a/collector/cpu_darwin.go b/collector/cpu_darwin.go index 6c461cc348..6076890638 100644 --- a/collector/cpu_darwin.go +++ b/collector/cpu_darwin.go @@ -61,7 +61,7 @@ func init() { } // NewCPUCollector returns a new Collector exposing CPU stats. -func NewCPUCollector(logger log.Logger) (Collector, error) { +func NewCPUCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &statCollector{ cpu: nodeCPUSecondsDesc, logger: logger, diff --git a/collector/cpu_dragonfly.go b/collector/cpu_dragonfly.go index 61cba1eee4..69de4abeae 100644 --- a/collector/cpu_dragonfly.go +++ b/collector/cpu_dragonfly.go @@ -86,7 +86,7 @@ func init() { } // NewStatCollector returns a new Collector exposing CPU stats. -func NewStatCollector(logger log.Logger) (Collector, error) { +func NewStatCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &statCollector{ cpu: nodeCPUSecondsDesc, logger: logger, diff --git a/collector/cpu_freebsd.go b/collector/cpu_freebsd.go index 96b0f033cb..7d999c3239 100644 --- a/collector/cpu_freebsd.go +++ b/collector/cpu_freebsd.go @@ -93,7 +93,7 @@ func init() { } // NewStatCollector returns a new Collector exposing CPU stats. -func NewStatCollector(logger log.Logger) (Collector, error) { +func NewStatCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &statCollector{ cpu: typedDesc{nodeCPUSecondsDesc, prometheus.CounterValue}, temp: typedDesc{prometheus.NewDesc( diff --git a/collector/cpu_linux.go b/collector/cpu_linux.go index d158567f93..f35fcb5414 100644 --- a/collector/cpu_linux.go +++ b/collector/cpu_linux.go @@ -24,7 +24,6 @@ import ( "strconv" "sync" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" @@ -52,16 +51,14 @@ type cpuCollector struct { cpuFlagsIncludeRegexp *regexp.Regexp cpuBugsIncludeRegexp *regexp.Regexp + + config *NodeCollectorConfig } // Idle jump back limit in seconds. const jumpBackSeconds = 3.0 var ( - enableCPUGuest = kingpin.Flag("collector.cpu.guest", "Enables metric node_cpu_guest_seconds_total").Default("true").Bool() - enableCPUInfo = kingpin.Flag("collector.cpu.info", "Enables metric cpu_info").Bool() - flagsInclude = kingpin.Flag("collector.cpu.info.flags-include", "Filter the `flags` field in cpuInfo with a value that must be a regular expression").String() - bugsInclude = kingpin.Flag("collector.cpu.info.bugs-include", "Filter the `bugs` field in cpuInfo with a value that must be a regular expression").String() jumpBackDebugMessage = fmt.Sprintf("CPU Idle counter jumped backwards more than %f seconds, possible hotplug event, resetting CPU stats", jumpBackSeconds) ) @@ -70,13 +67,13 @@ func init() { } // NewCPUCollector returns a new Collector exposing kernel/system statistics. -func NewCPUCollector(logger log.Logger) (Collector, error) { - fs, err := procfs.NewFS(*procPath) +func NewCPUCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := procfs.NewFS(*config.Path.ProcPath) if err != nil { return nil, fmt.Errorf("failed to open procfs: %w", err) } - sysfs, err := sysfs.NewFS(*sysPath) + sysfs, err := sysfs.NewFS(*config.Path.SysPath) if err != nil { return nil, fmt.Errorf("failed to open sysfs: %w", err) } @@ -135,8 +132,9 @@ func NewCPUCollector(logger log.Logger) (Collector, error) { logger: logger, isolatedCpus: isolcpus, cpuStats: make(map[int64]procfs.CPUStat), + config: config, } - err = c.compileIncludeFlags(flagsInclude, bugsInclude) + err = c.compileIncludeFlags(c.config.CPU.FlagsInclude, c.config.CPU.BugsInclude) if err != nil { return nil, fmt.Errorf("fail to compile --collector.cpu.info.flags-include and --collector.cpu.info.bugs-include, the values of them must be regular expressions: %w", err) } @@ -144,8 +142,8 @@ func NewCPUCollector(logger log.Logger) (Collector, error) { } func (c *cpuCollector) compileIncludeFlags(flagsIncludeFlag, bugsIncludeFlag *string) error { - if (*flagsIncludeFlag != "" || *bugsIncludeFlag != "") && !*enableCPUInfo { - *enableCPUInfo = true + if (*flagsIncludeFlag != "" || *bugsIncludeFlag != "") && !*c.config.CPU.EnableCPUInfo { + *c.config.CPU.EnableCPUInfo = true level.Info(c.logger).Log("msg", "--collector.cpu.info has been set to `true` because you set the following flags, like --collector.cpu.info.flags-include and --collector.cpu.info.bugs-include") } @@ -167,7 +165,7 @@ func (c *cpuCollector) compileIncludeFlags(flagsIncludeFlag, bugsIncludeFlag *st // Update implements Collector and exposes cpu related metrics from /proc/stat and /sys/.../cpu/. func (c *cpuCollector) Update(ch chan<- prometheus.Metric) error { - if *enableCPUInfo { + if *c.config.CPU.EnableCPUInfo { if err := c.updateInfo(ch); err != nil { return err } @@ -178,7 +176,7 @@ func (c *cpuCollector) Update(ch chan<- prometheus.Metric) error { if c.isolatedCpus != nil { c.updateIsolated(ch) } - return c.updateThermalThrottle(ch) + return c.updateThermalThrottle(c.config, ch) } // updateInfo reads /proc/cpuinfo @@ -203,10 +201,8 @@ func (c *cpuCollector) updateInfo(ch chan<- prometheus.Metric) error { cpu.CacheSize) } - cpuFreqEnabled, ok := collectorState["cpufreq"] - if !ok || cpuFreqEnabled == nil { - level.Debug(c.logger).Log("cpufreq key missing or nil value in collectorState map", err) - } else if !*cpuFreqEnabled { + // This should only run if CPUFREQ is NOT enabled. + if found, enabled := c.config.Collectors["cpufreq"]; found && !enabled { for _, cpu := range info { ch <- prometheus.MustNewConstMetric(c.cpuFrequencyHz, prometheus.GaugeValue, @@ -249,8 +245,8 @@ func updateFieldInfo(valueList []string, filter *regexp.Regexp, desc *prometheus } // updateThermalThrottle reads /sys/devices/system/cpu/cpu* and expose thermal throttle statistics. -func (c *cpuCollector) updateThermalThrottle(ch chan<- prometheus.Metric) error { - cpus, err := filepath.Glob(sysFilePath("devices/system/cpu/cpu[0-9]*")) +func (c *cpuCollector) updateThermalThrottle(config *NodeCollectorConfig, ch chan<- prometheus.Metric) error { + cpus, err := filepath.Glob(config.Path.sysFilePath("devices/system/cpu/cpu[0-9]*")) if err != nil { return err } @@ -357,7 +353,7 @@ func (c *cpuCollector) updateStat(ch chan<- prometheus.Metric) error { ch <- prometheus.MustNewConstMetric(c.cpu, prometheus.CounterValue, cpuStat.SoftIRQ, cpuNum, "softirq") ch <- prometheus.MustNewConstMetric(c.cpu, prometheus.CounterValue, cpuStat.Steal, cpuNum, "steal") - if *enableCPUGuest { + if *c.config.CPU.EnableCPUGuest { // Guest CPU is also accounted for in cpuStat.User and cpuStat.Nice, expose these as separate metrics. ch <- prometheus.MustNewConstMetric(c.cpuGuest, prometheus.CounterValue, cpuStat.Guest, cpuNum, "user") ch <- prometheus.MustNewConstMetric(c.cpuGuest, prometheus.CounterValue, cpuStat.GuestNice, cpuNum, "nice") diff --git a/collector/cpu_netbsd.go b/collector/cpu_netbsd.go index 7fc95c8081..4bf1aaf27d 100644 --- a/collector/cpu_netbsd.go +++ b/collector/cpu_netbsd.go @@ -92,8 +92,8 @@ func ioctl(fd int, nr int64, typ byte, size uintptr, retptr unsafe.Pointer) erro return nil } -func readSysmonProperties() (sysmonProperties, error) { - fd, err := unix.Open(rootfsFilePath("/dev/sysmon"), unix.O_RDONLY, 0777) +func readSysmonProperties(p PathConfig) (sysmonProperties, error) { + fd, err := unix.Open(p.rootfsStripPrefix("/dev/sysmon"), unix.O_RDONLY, 0777) if err != nil { return nil, err } @@ -142,12 +142,12 @@ func convertTemperatures(prop sysmonProperty, res map[int]float64) error { return nil } -func getCPUTemperatures() (map[int]float64, error) { +func getCPUTemperatures(p PathConfig) (map[int]float64, error) { res := make(map[int]float64) // Read all properties - props, err := readSysmonProperties() + props, err := readSysmonProperties(p) if err != nil { return res, err } @@ -215,6 +215,7 @@ type statCollector struct { cpu typedDesc temp typedDesc logger log.Logger + p PathConfig } func init() { @@ -222,7 +223,7 @@ func init() { } // NewStatCollector returns a new Collector exposing CPU stats. -func NewStatCollector(logger log.Logger) (Collector, error) { +func NewStatCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &statCollector{ cpu: typedDesc{nodeCPUSecondsDesc, prometheus.CounterValue}, temp: typedDesc{prometheus.NewDesc( @@ -231,6 +232,7 @@ func NewStatCollector(logger log.Logger) (Collector, error) { []string{"cpu"}, nil, ), prometheus.GaugeValue}, logger: logger, + p: config.Path, }, nil } @@ -253,7 +255,7 @@ func (c *statCollector) Update(ch chan<- prometheus.Metric) error { return err } - cpuTemperatures, err := getCPUTemperatures() + cpuTemperatures, err := getCPUTemperatures(c.p) if err != nil { return err } diff --git a/collector/cpu_openbsd.go b/collector/cpu_openbsd.go index 8715ff9885..96eb2b3326 100644 --- a/collector/cpu_openbsd.go +++ b/collector/cpu_openbsd.go @@ -52,7 +52,7 @@ func init() { registerCollector("cpu", defaultEnabled, NewCPUCollector) } -func NewCPUCollector(logger log.Logger) (Collector, error) { +func NewCPUCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &cpuCollector{ cpu: typedDesc{nodeCPUSecondsDesc, prometheus.CounterValue}, logger: logger, diff --git a/collector/cpu_solaris.go b/collector/cpu_solaris.go index 32466a1e64..34911033d3 100644 --- a/collector/cpu_solaris.go +++ b/collector/cpu_solaris.go @@ -36,7 +36,7 @@ func init() { registerCollector("cpu", defaultEnabled, NewCpuCollector) } -func NewCpuCollector(logger log.Logger) (Collector, error) { +func NewCpuCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &cpuCollector{ cpu: typedDesc{nodeCPUSecondsDesc, prometheus.CounterValue}, logger: logger, diff --git a/collector/cpu_vulnerabilities_linux.go b/collector/cpu_vulnerabilities_linux.go index 1875488b73..039d548602 100644 --- a/collector/cpu_vulnerabilities_linux.go +++ b/collector/cpu_vulnerabilities_linux.go @@ -34,18 +34,20 @@ var ( ) ) -type cpuVulnerabilitiesCollector struct{} +type cpuVulnerabilitiesCollector struct { + config *NodeCollectorConfig +} func init() { registerCollector(cpuVulerabilitiesCollector, defaultDisabled, NewVulnerabilitySysfsCollector) } -func NewVulnerabilitySysfsCollector(logger log.Logger) (Collector, error) { - return &cpuVulnerabilitiesCollector{}, nil +func NewVulnerabilitySysfsCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + return &cpuVulnerabilitiesCollector{config}, nil } func (v *cpuVulnerabilitiesCollector) Update(ch chan<- prometheus.Metric) error { - fs, err := sysfs.NewFS(*sysPath) + fs, err := sysfs.NewFS(*v.config.Path.SysPath) if err != nil { return fmt.Errorf("failed to open sysfs: %w", err) } diff --git a/collector/cpufreq_linux.go b/collector/cpufreq_linux.go index 3372be1ab6..cf8cc8569f 100644 --- a/collector/cpufreq_linux.go +++ b/collector/cpufreq_linux.go @@ -18,10 +18,11 @@ package collector import ( "fmt" + "strings" + "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/procfs/sysfs" - "strings" ) type cpuFreqCollector struct { @@ -34,8 +35,8 @@ func init() { } // NewCPUFreqCollector returns a new Collector exposing kernel/system statistics. -func NewCPUFreqCollector(logger log.Logger) (Collector, error) { - fs, err := sysfs.NewFS(*sysPath) +func NewCPUFreqCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := sysfs.NewFS(*config.Path.SysPath) if err != nil { return nil, fmt.Errorf("failed to open sysfs: %w", err) } diff --git a/collector/cpufreq_solaris.go b/collector/cpufreq_solaris.go index c3fb9ee687..23492d9a51 100644 --- a/collector/cpufreq_solaris.go +++ b/collector/cpufreq_solaris.go @@ -33,10 +33,10 @@ type cpuFreqCollector struct { } func init() { - registerCollector("cpufreq", defaultEnabled, NewCpuFreqCollector) + registerCollector("cpufreq", defaultEnabled, NewCPUFreqCollector) } -func NewCpuFreqCollector(logger log.Logger) (Collector, error) { +func NewCpuFreqCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &cpuFreqCollector{ logger: logger, }, nil diff --git a/collector/devstat_dragonfly.go b/collector/devstat_dragonfly.go index 11678054f7..733e918ecf 100644 --- a/collector/devstat_dragonfly.go +++ b/collector/devstat_dragonfly.go @@ -106,7 +106,7 @@ func init() { } // NewDevstatCollector returns a new Collector exposing Device stats. -func NewDevstatCollector(logger log.Logger) (Collector, error) { +func NewDevstatCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &devstatCollector{ bytesDesc: prometheus.NewDesc( prometheus.BuildFQName(namespace, devstatSubsystem, "bytes_total"), diff --git a/collector/devstat_freebsd.go b/collector/devstat_freebsd.go index 20cdc27674..3bdd694146 100644 --- a/collector/devstat_freebsd.go +++ b/collector/devstat_freebsd.go @@ -51,7 +51,7 @@ func init() { } // NewDevstatCollector returns a new Collector exposing Device stats. -func NewDevstatCollector(logger log.Logger) (Collector, error) { +func NewDevstatCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &devstatCollector{ devinfo: &C.struct_devinfo{}, bytes: typedDesc{prometheus.NewDesc( diff --git a/collector/diskstats_common.go b/collector/diskstats_common.go index 2ab84438e7..dbe0b5cf44 100644 --- a/collector/diskstats_common.go +++ b/collector/diskstats_common.go @@ -20,7 +20,6 @@ package collector import ( "errors" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" @@ -33,21 +32,6 @@ const ( var ( diskLabelNames = []string{"device"} - diskstatsDeviceExcludeSet bool - diskstatsDeviceExclude = kingpin.Flag( - "collector.diskstats.device-exclude", - "Regexp of diskstats devices to exclude (mutually exclusive to device-include).", - ).Default(diskstatsDefaultIgnoredDevices).PreAction(func(c *kingpin.ParseContext) error { - diskstatsDeviceExcludeSet = true - return nil - }).String() - oldDiskstatsDeviceExclude = kingpin.Flag( - "collector.diskstats.ignored-devices", - "DEPRECATED: Use collector.diskstats.device-exclude", - ).Hidden().String() - - diskstatsDeviceInclude = kingpin.Flag("collector.diskstats.device-include", "Regexp of diskstats devices to include (mutually exclusive to device-exclude).").String() - readsCompletedDesc = prometheus.NewDesc( prometheus.BuildFQName(namespace, diskSubsystem, "reads_completed_total"), "The total number of reads completed successfully.", @@ -93,27 +77,32 @@ var ( ) ) -func newDiskstatsDeviceFilter(logger log.Logger) (deviceFilter, error) { - if *oldDiskstatsDeviceExclude != "" { - if !diskstatsDeviceExcludeSet { +func newDiskstatsDeviceFilter(config DiskstatsDeviceFilterConfig, logger log.Logger) (deviceFilter, error) { + if *config.OldDeviceExclude != "" { + if !config.DeviceExcludeSet { level.Warn(logger).Log("msg", "--collector.diskstats.ignored-devices is DEPRECATED and will be removed in 2.0.0, use --collector.diskstats.device-exclude") - *diskstatsDeviceExclude = *oldDiskstatsDeviceExclude + *config.DeviceExclude = *config.OldDeviceExclude } else { return deviceFilter{}, errors.New("--collector.diskstats.ignored-devices and --collector.diskstats.device-exclude are mutually exclusive") } } - if *diskstatsDeviceExclude != "" && *diskstatsDeviceInclude != "" { + if *config.DeviceExclude != "" && *config.DeviceInclude != "" { return deviceFilter{}, errors.New("device-exclude & device-include are mutually exclusive") } - if *diskstatsDeviceExclude != "" { - level.Info(logger).Log("msg", "Parsed flag --collector.diskstats.device-exclude", "flag", *diskstatsDeviceExclude) + if *config.DeviceExclude != "" { + level.Info(logger).Log("msg", "Parsed flag --collector.diskstats.device-exclude", "flag", *config.DeviceExclude) + } + + if *config.DeviceInclude != "" { + level.Info(logger).Log("msg", "Parsed Flag --collector.diskstats.device-include", "flag", *config.DeviceInclude) } - if *diskstatsDeviceInclude != "" { - level.Info(logger).Log("msg", "Parsed Flag --collector.diskstats.device-include", "flag", *diskstatsDeviceInclude) + if !config.DeviceExcludeSet { // use default exclude devices if flag is not set + devices := diskstatsDefaultIgnoredDevices + config.DeviceExclude = &devices } - return newDeviceFilter(*diskstatsDeviceExclude, *diskstatsDeviceInclude), nil + return newDeviceFilter(*config.DeviceExclude, *config.DeviceInclude), nil } diff --git a/collector/diskstats_darwin.go b/collector/diskstats_darwin.go index b5f6c53844..faae589a4c 100644 --- a/collector/diskstats_darwin.go +++ b/collector/diskstats_darwin.go @@ -43,10 +43,10 @@ func init() { } // NewDiskstatsCollector returns a new Collector exposing disk device stats. -func NewDiskstatsCollector(logger log.Logger) (Collector, error) { +func NewDiskstatsCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { var diskLabelNames = []string{"device"} - deviceFilter, err := newDiskstatsDeviceFilter(logger) + deviceFilter, err := newDiskstatsDeviceFilter(config.DiskstatsDeviceFilter, logger) if err != nil { return nil, fmt.Errorf("failed to parse device filter flags: %w", err) } diff --git a/collector/diskstats_linux.go b/collector/diskstats_linux.go index ffda6ae421..96f03cd2cd 100644 --- a/collector/diskstats_linux.go +++ b/collector/diskstats_linux.go @@ -86,7 +86,8 @@ type diskstatsCollector struct { deviceMapperInfoDesc typedFactorDesc ataDescs map[string]typedFactorDesc logger log.Logger - getUdevDeviceProperties func(uint32, uint32) (udevInfo, error) + getUdevDeviceProperties func(*NodeCollectorConfig, uint32, uint32) (udevInfo, error) + config *NodeCollectorConfig } func init() { @@ -95,14 +96,14 @@ func init() { // NewDiskstatsCollector returns a new Collector exposing disk device stats. // Docs from https://www.kernel.org/doc/Documentation/iostats.txt -func NewDiskstatsCollector(logger log.Logger) (Collector, error) { +func NewDiskstatsCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { var diskLabelNames = []string{"device"} - fs, err := blockdevice.NewFS(*procPath, *sysPath) + fs, err := blockdevice.NewFS(*config.Path.ProcPath, *config.Path.SysPath) if err != nil { return nil, fmt.Errorf("failed to open sysfs: %w", err) } - deviceFilter, err := newDiskstatsDeviceFilter(logger) + deviceFilter, err := newDiskstatsDeviceFilter(config.DiskstatsDeviceFilter, logger) if err != nil { return nil, fmt.Errorf("failed to parse device filter flags: %w", err) } @@ -258,11 +259,12 @@ func NewDiskstatsCollector(logger log.Logger) (Collector, error) { }, }, logger: logger, + config: config, } // Only enable getting device properties from udev if the directory is readable. - if stat, err := os.Stat(*udevDataPath); err != nil || !stat.IsDir() { - level.Error(logger).Log("msg", "Failed to open directory, disabling udev device properties", "path", *udevDataPath) + if stat, err := os.Stat(*config.Path.UdevDataPath); err != nil || !stat.IsDir() { + level.Error(logger).Log("msg", "Failed to open directory, disabling udev device properties", "path", *config.Path.UdevDataPath) } else { collector.getUdevDeviceProperties = getUdevDeviceProperties } @@ -282,7 +284,7 @@ func (c *diskstatsCollector) Update(ch chan<- prometheus.Metric) error { continue } - info, err := getUdevDeviceProperties(stats.MajorNumber, stats.MinorNumber) + info, err := getUdevDeviceProperties(c.config, stats.MajorNumber, stats.MinorNumber) if err != nil { level.Debug(c.logger).Log("msg", "Failed to parse udev info", "err", err) } @@ -370,8 +372,8 @@ func (c *diskstatsCollector) Update(ch chan<- prometheus.Metric) error { return nil } -func getUdevDeviceProperties(major, minor uint32) (udevInfo, error) { - filename := udevDataFilePath(fmt.Sprintf("b%d:%d", major, minor)) +func getUdevDeviceProperties(config *NodeCollectorConfig, major, minor uint32) (udevInfo, error) { + filename := config.Path.udevDataFilePath(fmt.Sprintf("b%d:%d", major, minor)) data, err := os.Open(filename) if err != nil { diff --git a/collector/diskstats_linux_test.go b/collector/diskstats_linux_test.go index f0d7499be0..f2540a6357 100644 --- a/collector/diskstats_linux_test.go +++ b/collector/diskstats_linux_test.go @@ -39,8 +39,8 @@ func (c testDiskStatsCollector) Describe(ch chan<- *prometheus.Desc) { prometheus.DescribeByCollect(c, ch) } -func NewTestDiskStatsCollector(logger log.Logger) (prometheus.Collector, error) { - dsc, err := NewDiskstatsCollector(logger) +func NewTestDiskStatsCollector(config *NodeCollectorConfig, logger log.Logger) (prometheus.Collector, error) { + dsc, err := NewDiskstatsCollector(config, logger) if err != nil { return testDiskStatsCollector{}, err } @@ -50,10 +50,24 @@ func NewTestDiskStatsCollector(logger log.Logger) (prometheus.Collector, error) } func TestDiskStats(t *testing.T) { - *sysPath = "fixtures/sys" - *procPath = "fixtures/proc" - *udevDataPath = "fixtures/udev/data" - *diskstatsDeviceExclude = "^(ram|loop|fd|(h|s|v|xv)d[a-z]|nvme\\d+n\\d+p)\\d+$" + config := &NodeCollectorConfig{ + DiskstatsDeviceFilter: DiskstatsDeviceFilterConfig{ + DeviceExclude: new(string), + DeviceInclude: new(string), + OldDeviceExclude: new(string), + }, + } + sysPath := "fixtures/sys" + config.Path.SysPath = &sysPath + + procPath := "fixtures/proc" + config.Path.ProcPath = &procPath + + udevDataPath := "fixtures/udev/data" + config.Path.UdevDataPath = &udevDataPath + + diskstatsDeviceExclude := "^(ram|loop|fd|(h|s|v|xv)d[a-z]|nvme\\d+n\\d+p)\\d+$" + config.DiskstatsDeviceFilter.DeviceExclude = &diskstatsDeviceExclude testcase := `# HELP node_disk_ata_rotation_rate_rpm ATA disk rotation rate in RPMs (0 for SSDs). # TYPE node_disk_ata_rotation_rate_rpm gauge node_disk_ata_rotation_rate_rpm{device="sda"} 7200 @@ -318,11 +332,11 @@ node_disk_written_bytes_total{device="vda"} 1.0938236928e+11 ` logger := log.NewLogfmtLogger(os.Stderr) - collector, err := NewDiskstatsCollector(logger) + collector, err := NewDiskstatsCollector(config, logger) if err != nil { panic(err) } - c, err := NewTestDiskStatsCollector(logger) + c, err := NewTestDiskStatsCollector(config, logger) if err != nil { t.Fatal(err) } diff --git a/collector/diskstats_openbsd.go b/collector/diskstats_openbsd.go index 2a69042aac..0bd6804704 100644 --- a/collector/diskstats_openbsd.go +++ b/collector/diskstats_openbsd.go @@ -49,8 +49,8 @@ func init() { } // NewDiskstatsCollector returns a new Collector exposing disk device stats. -func NewDiskstatsCollector(logger log.Logger) (Collector, error) { - deviceFilter, err := newDiskstatsDeviceFilter(logger) +func NewDiskstatsCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + deviceFilter, err := newDiskstatsDeviceFilter(config.DiskstatsDeviceFilter, logger) if err != nil { return nil, fmt.Errorf("failed to parse device filter flags: %w", err) } diff --git a/collector/diskstats_openbsd_amd64.go b/collector/diskstats_openbsd_amd64.go index a39cabb538..44a755596a 100644 --- a/collector/diskstats_openbsd_amd64.go +++ b/collector/diskstats_openbsd_amd64.go @@ -60,8 +60,8 @@ func init() { } // NewDiskstatsCollector returns a new Collector exposing disk device stats. -func NewDiskstatsCollector(logger log.Logger) (Collector, error) { - deviceFilter, err := newDiskstatsDeviceFilter(logger) +func NewDiskstatsCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + deviceFilter, err := newDiskstatsDeviceFilter(config.DiskstatsDeviceFilter, logger) if err != nil { return nil, fmt.Errorf("failed to parse device filter flags: %w", err) } diff --git a/collector/dmi.go b/collector/dmi.go index 794755076a..20fd7518d0 100644 --- a/collector/dmi.go +++ b/collector/dmi.go @@ -38,8 +38,8 @@ func init() { } // NewDMICollector returns a new Collector exposing DMI information. -func NewDMICollector(logger log.Logger) (Collector, error) { - fs, err := sysfs.NewFS(*sysPath) +func NewDMICollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := sysfs.NewFS(*config.Path.SysPath) if err != nil { return nil, fmt.Errorf("failed to open sysfs: %w", err) } diff --git a/collector/drbd_linux.go b/collector/drbd_linux.go index f192a24c6f..6a992b904a 100644 --- a/collector/drbd_linux.go +++ b/collector/drbd_linux.go @@ -80,13 +80,14 @@ type drbdCollector struct { stringPair map[string]drbdStringPairMetric connected *prometheus.Desc logger log.Logger + config *NodeCollectorConfig } func init() { registerCollector("drbd", defaultDisabled, newDRBDCollector) } -func newDRBDCollector(logger log.Logger) (Collector, error) { +func newDRBDCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &drbdCollector{ numerical: map[string]drbdNumericalMetric{ "ns": newDRBDNumericalMetric( @@ -183,11 +184,12 @@ func newDRBDCollector(logger log.Logger) (Collector, error) { nil, ), logger: logger, + config: config, }, nil } func (c *drbdCollector) Update(ch chan<- prometheus.Metric) error { - statsFile := procFilePath("drbd") + statsFile := c.config.Path.procFilePath("drbd") file, err := os.Open(statsFile) if err != nil { if errors.Is(err, os.ErrNotExist) { diff --git a/collector/drm_linux.go b/collector/drm_linux.go index 11b8c6283b..ed3fd185ae 100644 --- a/collector/drm_linux.go +++ b/collector/drm_linux.go @@ -46,8 +46,8 @@ func init() { } // NewDrmCollector returns a new Collector exposing /sys/class/drm/card?/device stats. -func NewDrmCollector(logger log.Logger) (Collector, error) { - fs, err := sysfs.NewFS(*sysPath) +func NewDrmCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := sysfs.NewFS(*config.Path.SysPath) if err != nil { return nil, fmt.Errorf("failed to open sysfs: %w", err) } diff --git a/collector/edac_linux.go b/collector/edac_linux.go index c7719b7a64..eafe80dee4 100644 --- a/collector/edac_linux.go +++ b/collector/edac_linux.go @@ -40,6 +40,7 @@ type edacCollector struct { csRowCECount *prometheus.Desc csRowUECount *prometheus.Desc logger log.Logger + config *NodeCollectorConfig } func init() { @@ -47,7 +48,7 @@ func init() { } // NewEdacCollector returns a new Collector exposing edac stats. -func NewEdacCollector(logger log.Logger) (Collector, error) { +func NewEdacCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &edacCollector{ ceCount: prometheus.NewDesc( prometheus.BuildFQName(namespace, edacSubsystem, "correctable_errors_total"), @@ -70,11 +71,12 @@ func NewEdacCollector(logger log.Logger) (Collector, error) { []string{"controller", "csrow"}, nil, ), logger: logger, + config: config, }, nil } func (c *edacCollector) Update(ch chan<- prometheus.Metric) error { - memControllers, err := filepath.Glob(sysFilePath("devices/system/edac/mc/mc[0-9]*")) + memControllers, err := filepath.Glob(c.config.Path.sysFilePath("devices/system/edac/mc/mc[0-9]*")) if err != nil { return err } diff --git a/collector/entropy_linux.go b/collector/entropy_linux.go index 909d2ff4c2..1b13a65c26 100644 --- a/collector/entropy_linux.go +++ b/collector/entropy_linux.go @@ -36,8 +36,8 @@ func init() { } // NewEntropyCollector returns a new Collector exposing entropy stats. -func NewEntropyCollector(logger log.Logger) (Collector, error) { - fs, err := procfs.NewFS(*procPath) +func NewEntropyCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := procfs.NewFS(*config.Path.ProcPath) if err != nil { return nil, fmt.Errorf("failed to open procfs: %w", err) } diff --git a/collector/ethtool_linux.go b/collector/ethtool_linux.go index 0111701bbe..6bfc869c4a 100644 --- a/collector/ethtool_linux.go +++ b/collector/ethtool_linux.go @@ -30,7 +30,6 @@ import ( "sync" "syscall" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" @@ -40,11 +39,8 @@ import ( ) var ( - ethtoolDeviceInclude = kingpin.Flag("collector.ethtool.device-include", "Regexp of ethtool devices to include (mutually exclusive to device-exclude).").String() - ethtoolDeviceExclude = kingpin.Flag("collector.ethtool.device-exclude", "Regexp of ethtool devices to exclude (mutually exclusive to device-include).").String() - ethtoolIncludedMetrics = kingpin.Flag("collector.ethtool.metrics-include", "Regexp of ethtool stats to include.").Default(".*").String() - ethtoolReceivedRegex = regexp.MustCompile(`(^|_)rx(_|$)`) - ethtoolTransmitRegex = regexp.MustCompile(`(^|_)tx(_|$)`) + ethtoolReceivedRegex = regexp.MustCompile(`(^|_)rx(_|$)`) + ethtoolTransmitRegex = regexp.MustCompile(`(^|_)tx(_|$)`) ) type Ethtool interface { @@ -85,8 +81,8 @@ type ethtoolCollector struct { // makeEthtoolCollector is the internal constructor for EthtoolCollector. // This allows NewEthtoolTestCollector to override its .ethtool interface // for testing. -func makeEthtoolCollector(logger log.Logger) (*ethtoolCollector, error) { - fs, err := sysfs.NewFS(*sysPath) +func makeEthtoolCollector(config *NodeCollectorConfig, logger log.Logger) (*ethtoolCollector, error) { + fs, err := sysfs.NewFS(*config.Path.SysPath) if err != nil { return nil, fmt.Errorf("failed to open sysfs: %w", err) } @@ -100,8 +96,8 @@ func makeEthtoolCollector(logger log.Logger) (*ethtoolCollector, error) { return ðtoolCollector{ fs: fs, ethtool: ðtoolLibrary{e}, - deviceFilter: newDeviceFilter(*ethtoolDeviceExclude, *ethtoolDeviceInclude), - metricsPattern: regexp.MustCompile(*ethtoolIncludedMetrics), + deviceFilter: newDeviceFilter(*config.Ethtool.DeviceExclude, *config.Ethtool.DeviceInclude), + metricsPattern: regexp.MustCompile(*config.Ethtool.IncludedMetrics), logger: logger, entries: map[string]*prometheus.Desc{ "rx_bytes": prometheus.NewDesc( @@ -213,8 +209,8 @@ func buildEthtoolFQName(metric string) string { } // NewEthtoolCollector returns a new Collector exposing ethtool stats. -func NewEthtoolCollector(logger log.Logger) (Collector, error) { - return makeEthtoolCollector(logger) +func NewEthtoolCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + return makeEthtoolCollector(config, logger) } // updatePortCapabilities generates metrics for autonegotiate, pause and asymmetricpause. diff --git a/collector/ethtool_linux_test.go b/collector/ethtool_linux_test.go index cf55c6b1f5..b2627bf84d 100644 --- a/collector/ethtool_linux_test.go +++ b/collector/ethtool_linux_test.go @@ -49,8 +49,8 @@ func (c testEthtoolCollector) Describe(ch chan<- *prometheus.Desc) { prometheus.DescribeByCollect(c, ch) } -func NewTestEthtoolCollector(logger log.Logger) (prometheus.Collector, error) { - dsc, err := NewEthtoolTestCollector(logger) +func NewTestEthtoolCollector(config *NodeCollectorConfig, logger log.Logger) (prometheus.Collector, error) { + dsc, err := NewEthtoolTestCollector(config, logger) if err != nil { return testEthtoolCollector{}, err } @@ -255,8 +255,8 @@ func (e *EthtoolFixture) LinkInfo(intf string) (ethtool.EthtoolCmd, error) { return res, err } -func NewEthtoolTestCollector(logger log.Logger) (Collector, error) { - collector, err := makeEthtoolCollector(logger) +func NewEthtoolTestCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + collector, err := makeEthtoolCollector(config, logger) collector.ethtool = &EthtoolFixture{ fixturePath: "fixtures/ethtool/", } @@ -285,6 +285,13 @@ func TestBuildEthtoolFQName(t *testing.T) { } func TestEthToolCollector(t *testing.T) { + config := &NodeCollectorConfig{ + Ethtool: EthtoolConfig{ + DeviceInclude: new(string), + DeviceExclude: new(string), + IncludedMetrics: new(string), + }, + } testcase := `# HELP node_ethtool_align_errors Network interface align_errors # TYPE node_ethtool_align_errors untyped node_ethtool_align_errors{device="eth0"} 0 @@ -368,14 +375,15 @@ node_network_supported_speed_bytes{device="eth0",duplex="full",mode="10baseT"} 1 node_network_supported_speed_bytes{device="eth0",duplex="half",mode="100baseT"} 1.25e+07 node_network_supported_speed_bytes{device="eth0",duplex="half",mode="10baseT"} 1.25e+06 ` - *sysPath = "fixtures/sys" + sysPath := "fixtures/sys" + config.Path.SysPath = &sysPath logger := log.NewLogfmtLogger(os.Stderr) - collector, err := NewEthtoolTestCollector(logger) + collector, err := NewEthtoolTestCollector(config, logger) if err != nil { panic(err) } - c, err := NewTestEthtoolCollector(logger) + c, err := NewTestEthtoolCollector(config, logger) if err != nil { t.Fatal(err) } diff --git a/collector/exec_bsd.go b/collector/exec_bsd.go index 7ae5e2ee32..1884bd0a90 100644 --- a/collector/exec_bsd.go +++ b/collector/exec_bsd.go @@ -32,7 +32,7 @@ func init() { } // NewExecCollector returns a new Collector exposing system execution statistics. -func NewExecCollector(logger log.Logger) (Collector, error) { +func NewExecCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { // From sys/vm/vm_meter.c: // All are of type CTLTYPE_UINT. // @@ -62,7 +62,6 @@ func NewExecCollector(logger log.Logger) (Collector, error) { description: "System calls since system boot. Resets at architecture unsigned integer.", mib: "vm.stats.sys.v_syscall", }, - labels: nil, { name: "exec_device_interrupts_total", description: "Device interrupts since system boot. Resets at architecture unsigned integer.", diff --git a/collector/fibrechannel_linux.go b/collector/fibrechannel_linux.go index 32e4d1e733..7a471ccb88 100644 --- a/collector/fibrechannel_linux.go +++ b/collector/fibrechannel_linux.go @@ -40,11 +40,11 @@ func init() { } // NewFibreChannelCollector returns a new Collector exposing FibreChannel stats. -func NewFibreChannelCollector(logger log.Logger) (Collector, error) { +func NewFibreChannelCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { var i fibrechannelCollector var err error - i.fs, err = sysfs.NewFS(*sysPath) + i.fs, err = sysfs.NewFS(*config.Path.SysPath) if err != nil { return nil, fmt.Errorf("failed to open sysfs: %w", err) } diff --git a/collector/filefd_linux.go b/collector/filefd_linux.go index 55069d6c5d..a067e00b7c 100644 --- a/collector/filefd_linux.go +++ b/collector/filefd_linux.go @@ -33,6 +33,7 @@ const ( type fileFDStatCollector struct { logger log.Logger + config *NodeCollectorConfig } func init() { @@ -40,12 +41,12 @@ func init() { } // NewFileFDStatCollector returns a new Collector exposing file-nr stats. -func NewFileFDStatCollector(logger log.Logger) (Collector, error) { - return &fileFDStatCollector{logger}, nil +func NewFileFDStatCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + return &fileFDStatCollector{logger, config}, nil } func (c *fileFDStatCollector) Update(ch chan<- prometheus.Metric) error { - fileFDStat, err := parseFileFDStats(procFilePath("sys/fs/file-nr")) + fileFDStat, err := parseFileFDStats(c.config.Path.procFilePath("sys/fs/file-nr")) if err != nil { return fmt.Errorf("couldn't get file-nr: %w", err) } diff --git a/collector/filesystem_bsd.go b/collector/filesystem_bsd.go index d3025a0171..ccd71a77bc 100644 --- a/collector/filesystem_bsd.go +++ b/collector/filesystem_bsd.go @@ -39,7 +39,7 @@ const ( ) // Expose filesystem fullness. -func (c *filesystemCollector) GetStats() (stats []filesystemStats, err error) { +func (c *filesystemCollector) GetStats(p PathConfig) (stats []filesystemStats, err error) { var mntbuf *C.struct_statfs count := C.getmntinfo(&mntbuf, C.MNT_NOWAIT) if count == 0 { @@ -70,7 +70,7 @@ func (c *filesystemCollector) GetStats() (stats []filesystemStats, err error) { stats = append(stats, filesystemStats{ labels: filesystemLabels{ device: device, - mountPoint: rootfsStripPrefix(mountpoint), + mountPoint: p.rootfsStripPrefix(mountpoint), fsType: fstype, }, size: float64(mnt[i].f_blocks) * float64(mnt[i].f_bsize), diff --git a/collector/filesystem_common.go b/collector/filesystem_common.go index f5dde59ab7..7723b727f4 100644 --- a/collector/filesystem_common.go +++ b/collector/filesystem_common.go @@ -19,12 +19,10 @@ package collector import ( "errors" - "regexp" - - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" + "regexp" ) // Arch-dependent implementation must define: @@ -34,32 +32,6 @@ import ( // * filesystemCollector.GetStats var ( - mountPointsExcludeSet bool - mountPointsExclude = kingpin.Flag( - "collector.filesystem.mount-points-exclude", - "Regexp of mount points to exclude for filesystem collector.", - ).Default(defMountPointsExcluded).PreAction(func(c *kingpin.ParseContext) error { - mountPointsExcludeSet = true - return nil - }).String() - oldMountPointsExcluded = kingpin.Flag( - "collector.filesystem.ignored-mount-points", - "Regexp of mount points to ignore for filesystem collector.", - ).Hidden().String() - - fsTypesExcludeSet bool - fsTypesExclude = kingpin.Flag( - "collector.filesystem.fs-types-exclude", - "Regexp of filesystem types to exclude for filesystem collector.", - ).Default(defFSTypesExcluded).PreAction(func(c *kingpin.ParseContext) error { - fsTypesExcludeSet = true - return nil - }).String() - oldFSTypesExcluded = kingpin.Flag( - "collector.filesystem.ignored-fs-types", - "Regexp of filesystem types to ignore for filesystem collector.", - ).Hidden().String() - filesystemLabelNames = []string{"device", "mountpoint", "fstype"} ) @@ -70,6 +42,7 @@ type filesystemCollector struct { filesDesc, filesFreeDesc *prometheus.Desc roDesc, deviceErrorDesc *prometheus.Desc logger log.Logger + config *NodeCollectorConfig } type filesystemLabels struct { @@ -88,30 +61,46 @@ func init() { } // NewFilesystemCollector returns a new Collector exposing filesystems stats. -func NewFilesystemCollector(logger log.Logger) (Collector, error) { - if *oldMountPointsExcluded != "" { - if !mountPointsExcludeSet { +func NewFilesystemCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + if *config.Filesystem.OldMountPointsExcluded != "" { + if !config.Filesystem.MountPointsExcludeSet { level.Warn(logger).Log("msg", "--collector.filesystem.ignored-mount-points is DEPRECATED and will be removed in 2.0.0, use --collector.filesystem.mount-points-exclude") - *mountPointsExclude = *oldMountPointsExcluded + *config.Filesystem.MountPointsExclude = *config.Filesystem.OldMountPointsExcluded } else { return nil, errors.New("--collector.filesystem.ignored-mount-points and --collector.filesystem.mount-points-exclude are mutually exclusive") } } - if *oldFSTypesExcluded != "" { - if !fsTypesExcludeSet { + if *config.Filesystem.MountPointsExclude != "" { + level.Info(logger).Log("msg", "Parsed flag --collector.filesystem.mount-points-exclude", "flag", *config.Filesystem.MountPointsExclude) + } + + if !config.Filesystem.MountPointsExcludeSet { // use default mount points if flag is not set + mountPoints := defMountPointsExcluded + config.Filesystem.MountPointsExclude = &mountPoints + } + + if *config.Filesystem.OldFSTypesExcluded != "" { + if !config.Filesystem.FSTypesExcludeSet { level.Warn(logger).Log("msg", "--collector.filesystem.ignored-fs-types is DEPRECATED and will be removed in 2.0.0, use --collector.filesystem.fs-types-exclude") - *fsTypesExclude = *oldFSTypesExcluded + *config.Filesystem.FSTypesExclude = *config.Filesystem.OldFSTypesExcluded } else { return nil, errors.New("--collector.filesystem.ignored-fs-types and --collector.filesystem.fs-types-exclude are mutually exclusive") } } + if *config.Filesystem.FSTypesExclude != "" { + level.Info(logger).Log("msg", "Parsed flag --collector.filesystem.fs-types-exclude", "flag", *config.Filesystem.FSTypesExclude) + } + + if !config.Filesystem.FSTypesExcludeSet { // use default fs types if flag is not set + fsTypes := defFSTypesExcluded + config.Filesystem.FSTypesExclude = &fsTypes + } + subsystem := "filesystem" - level.Info(logger).Log("msg", "Parsed flag --collector.filesystem.mount-points-exclude", "flag", *mountPointsExclude) - mountPointPattern := regexp.MustCompile(*mountPointsExclude) - level.Info(logger).Log("msg", "Parsed flag --collector.filesystem.fs-types-exclude", "flag", *fsTypesExclude) - filesystemsTypesPattern := regexp.MustCompile(*fsTypesExclude) + mountPointPattern := regexp.MustCompile(*config.Filesystem.MountPointsExclude) + filesystemsTypesPattern := regexp.MustCompile(*config.Filesystem.FSTypesExclude) sizeDesc := prometheus.NewDesc( prometheus.BuildFQName(namespace, subsystem, "size_bytes"), @@ -166,11 +155,12 @@ func NewFilesystemCollector(logger log.Logger) (Collector, error) { roDesc: roDesc, deviceErrorDesc: deviceErrorDesc, logger: logger, + config: config, }, nil } func (c *filesystemCollector) Update(ch chan<- prometheus.Metric) error { - stats, err := c.GetStats() + stats, err := c.GetStats(c.config.Path) if err != nil { return err } diff --git a/collector/filesystem_freebsd.go b/collector/filesystem_freebsd.go index f05702d14f..a48ac267c9 100644 --- a/collector/filesystem_freebsd.go +++ b/collector/filesystem_freebsd.go @@ -27,7 +27,7 @@ const ( ) // Expose filesystem fullness. -func (c *filesystemCollector) GetStats() ([]filesystemStats, error) { +func (c *filesystemCollector) GetStats(_ PathConfig) ([]filesystemStats, error) { n, err := unix.Getfsstat(nil, unix.MNT_NOWAIT) if err != nil { return nil, err @@ -65,7 +65,7 @@ func (c *filesystemCollector) GetStats() ([]filesystemStats, error) { stats = append(stats, filesystemStats{ labels: filesystemLabels{ device: device, - mountPoint: rootfsStripPrefix(mountpoint), + mountPoint: c.config.Path.rootfsStripPrefix(mountpoint), fsType: fstype, }, size: float64(fs.Blocks) * float64(fs.Bsize), diff --git a/collector/filesystem_linux.go b/collector/filesystem_linux.go index 6e7623e203..f403d953bc 100644 --- a/collector/filesystem_linux.go +++ b/collector/filesystem_linux.go @@ -26,7 +26,6 @@ import ( "sync" "time" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "golang.org/x/sys/unix" @@ -37,18 +36,12 @@ const ( defFSTypesExcluded = "^(autofs|binfmt_misc|bpf|cgroup2?|configfs|debugfs|devpts|devtmpfs|fusectl|hugetlbfs|iso9660|mqueue|nsfs|overlay|proc|procfs|pstore|rpc_pipefs|securityfs|selinuxfs|squashfs|sysfs|tracefs)$" ) -var mountTimeout = kingpin.Flag("collector.filesystem.mount-timeout", - "how long to wait for a mount to respond before marking it as stale"). - Hidden().Default("5s").Duration() -var statWorkerCount = kingpin.Flag("collector.filesystem.stat-workers", - "how many stat calls to process simultaneously"). - Hidden().Default("4").Int() var stuckMounts = make(map[string]struct{}) var stuckMountsMtx = &sync.Mutex{} // GetStats returns filesystem stats. -func (c *filesystemCollector) GetStats() ([]filesystemStats, error) { - mps, err := mountPointDetails(c.logger) +func (c *filesystemCollector) GetStats(_ PathConfig) ([]filesystemStats, error) { + mps, err := mountPointDetails(c.config, c.logger) if err != nil { return nil, err } @@ -57,7 +50,7 @@ func (c *filesystemCollector) GetStats() ([]filesystemStats, error) { statChan := make(chan filesystemStats) wg := sync.WaitGroup{} - workerCount := *statWorkerCount + workerCount := *c.config.Filesystem.StatWorkerCount if workerCount < 1 { workerCount = 1 } @@ -118,10 +111,10 @@ func (c *filesystemCollector) processStat(labels filesystemLabels) filesystemSta } success := make(chan struct{}) - go stuckMountWatcher(labels.mountPoint, success, c.logger) + go stuckMountWatcher(c.config.Filesystem.MountTimeout, labels.mountPoint, success, c.logger) buf := new(unix.Statfs_t) - err := unix.Statfs(rootfsFilePath(labels.mountPoint), buf) + err := unix.Statfs(c.config.Path.rootfsFilePath(labels.mountPoint), buf) stuckMountsMtx.Lock() close(success) @@ -133,7 +126,7 @@ func (c *filesystemCollector) processStat(labels filesystemLabels) filesystemSta stuckMountsMtx.Unlock() if err != nil { - level.Debug(c.logger).Log("msg", "Error on statfs() system call", "rootfs", rootfsFilePath(labels.mountPoint), "err", err) + level.Debug(c.logger).Log("msg", "Error on statfs() system call", "rootfs", c.config.Path.rootfsFilePath(labels.mountPoint), "err", err) return filesystemStats{ labels: labels, deviceError: 1, @@ -155,7 +148,7 @@ func (c *filesystemCollector) processStat(labels filesystemLabels) filesystemSta // stuckMountWatcher listens on the given success channel and if the channel closes // then the watcher does nothing. If instead the timeout is reached, the // mount point that is being watched is marked as stuck. -func stuckMountWatcher(mountPoint string, success chan struct{}, logger log.Logger) { +func stuckMountWatcher(mountTimeout *time.Duration, mountPoint string, success chan struct{}, logger log.Logger) { mountCheckTimer := time.NewTimer(*mountTimeout) defer mountCheckTimer.Stop() select { @@ -175,22 +168,22 @@ func stuckMountWatcher(mountPoint string, success chan struct{}, logger log.Logg } } -func mountPointDetails(logger log.Logger) ([]filesystemLabels, error) { - file, err := os.Open(procFilePath("1/mounts")) +func mountPointDetails(config *NodeCollectorConfig, logger log.Logger) ([]filesystemLabels, error) { + file, err := os.Open(config.Path.procFilePath("1/mounts")) if errors.Is(err, os.ErrNotExist) { // Fallback to `/proc/mounts` if `/proc/1/mounts` is missing due hidepid. level.Debug(logger).Log("msg", "Reading root mounts failed, falling back to system mounts", "err", err) - file, err = os.Open(procFilePath("mounts")) + file, err = os.Open(config.Path.procFilePath("mounts")) } if err != nil { return nil, err } defer file.Close() - return parseFilesystemLabels(file) + return parseFilesystemLabels(config, file) } -func parseFilesystemLabels(r io.Reader) ([]filesystemLabels, error) { +func parseFilesystemLabels(config *NodeCollectorConfig, r io.Reader) ([]filesystemLabels, error) { var filesystems []filesystemLabels scanner := bufio.NewScanner(r) @@ -208,7 +201,7 @@ func parseFilesystemLabels(r io.Reader) ([]filesystemLabels, error) { filesystems = append(filesystems, filesystemLabels{ device: parts[0], - mountPoint: rootfsStripPrefix(parts[1]), + mountPoint: config.Path.rootfsStripPrefix(parts[1]), fsType: parts[2], options: parts[3], }) diff --git a/collector/filesystem_linux_test.go b/collector/filesystem_linux_test.go index 325ffc87b2..a76c888b54 100644 --- a/collector/filesystem_linux_test.go +++ b/collector/filesystem_linux_test.go @@ -20,11 +20,11 @@ import ( "strings" "testing" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" ) func Test_parseFilesystemLabelsError(t *testing.T) { + config := &NodeCollectorConfig{} tests := []struct { name string in string @@ -37,7 +37,7 @@ func Test_parseFilesystemLabelsError(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if _, err := parseFilesystemLabels(strings.NewReader(tt.in)); err == nil { + if _, err := parseFilesystemLabels(config, strings.NewReader(tt.in)); err == nil { t.Fatal("expected an error, but none occurred") } }) @@ -45,9 +45,9 @@ func Test_parseFilesystemLabelsError(t *testing.T) { } func TestMountPointDetails(t *testing.T) { - if _, err := kingpin.CommandLine.Parse([]string{"--path.procfs", "./fixtures/proc"}); err != nil { - t.Fatal(err) - } + path := "./fixtures/proc" + config := newNodeCollectorWithPaths() + config.Path.ProcPath = &path expected := map[string]string{ "/": "", @@ -82,7 +82,7 @@ func TestMountPointDetails(t *testing.T) { "/var/lib/kubelet/plugins/kubernetes.io/vsphere-volume/mounts/[vsanDatastore] bafb9e5a-8856-7e6c-699c-801844e77a4a/kubernetes-dynamic-pvc-3eba5bba-48a3-11e8-89ab-005056b92113.vmdk": "", } - filesystems, err := mountPointDetails(log.NewNopLogger()) + filesystems, err := mountPointDetails(config, log.NewNopLogger()) if err != nil { t.Log(err) } @@ -95,15 +95,15 @@ func TestMountPointDetails(t *testing.T) { } func TestMountsFallback(t *testing.T) { - if _, err := kingpin.CommandLine.Parse([]string{"--path.procfs", "./fixtures_hidepid/proc"}); err != nil { - t.Fatal(err) - } + path := "./fixtures_hidepid/proc" + config := newNodeCollectorWithPaths() + config.Path.ProcPath = &path expected := map[string]string{ "/": "", } - filesystems, err := mountPointDetails(log.NewNopLogger()) + filesystems, err := mountPointDetails(config, log.NewNopLogger()) if err != nil { t.Log(err) } @@ -116,9 +116,11 @@ func TestMountsFallback(t *testing.T) { } func TestPathRootfs(t *testing.T) { - if _, err := kingpin.CommandLine.Parse([]string{"--path.procfs", "./fixtures_bindmount/proc", "--path.rootfs", "/host"}); err != nil { - t.Fatal(err) - } + procPath := "./fixtures_bindmount/proc" + rootfsPath := "/host" + config := newNodeCollectorWithPaths() + config.Path.ProcPath = &procPath + config.Path.RootfsPath = &rootfsPath expected := map[string]string{ // should modify these mountpoints (removes /host, see fixture proc file) @@ -131,7 +133,7 @@ func TestPathRootfs(t *testing.T) { "/sys/fs/cgroup": "", } - filesystems, err := mountPointDetails(log.NewNopLogger()) + filesystems, err := mountPointDetails(config, log.NewNopLogger()) if err != nil { t.Log(err) } diff --git a/collector/filesystem_openbsd.go b/collector/filesystem_openbsd.go index 1c1e479e1f..eebb33290c 100644 --- a/collector/filesystem_openbsd.go +++ b/collector/filesystem_openbsd.go @@ -27,7 +27,7 @@ const ( ) // Expose filesystem fullness. -func (c *filesystemCollector) GetStats() (stats []filesystemStats, err error) { +func (c *filesystemCollector) GetStats(_ PathConfig) (stats []filesystemStats, err error) { var mnt []unix.Statfs_t size, err := unix.Getfsstat(mnt, unix.MNT_NOWAIT) if err != nil { diff --git a/collector/hwmon_linux.go b/collector/hwmon_linux.go index 3ad469a61a..40fd559975 100644 --- a/collector/hwmon_linux.go +++ b/collector/hwmon_linux.go @@ -24,7 +24,6 @@ import ( "strconv" "strings" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" @@ -32,9 +31,6 @@ import ( ) var ( - collectorHWmonChipInclude = kingpin.Flag("collector.hwmon.chip-include", "Regexp of hwmon chip to include (mutually exclusive to device-exclude).").String() - collectorHWmonChipExclude = kingpin.Flag("collector.hwmon.chip-exclude", "Regexp of hwmon chip to exclude (mutually exclusive to device-include).").String() - hwmonInvalidMetricChars = regexp.MustCompile("[^a-z0-9:_]") hwmonFilenameFormat = regexp.MustCompile(`^(?P[^0-9]+)(?P[0-9]*)?(_(?P.+))?$`) hwmonLabelDesc = []string{"chip", "sensor"} @@ -53,15 +49,17 @@ func init() { type hwMonCollector struct { deviceFilter deviceFilter logger log.Logger + config *NodeCollectorConfig } // NewHwMonCollector returns a new Collector exposing /sys/class/hwmon stats // (similar to lm-sensors). -func NewHwMonCollector(logger log.Logger) (Collector, error) { +func NewHwMonCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &hwMonCollector{ logger: logger, - deviceFilter: newDeviceFilter(*collectorHWmonChipExclude, *collectorHWmonChipInclude), + deviceFilter: newDeviceFilter(*config.HwMon.ChipExclude, *config.HwMon.ChipInclude), + config: config, }, nil } @@ -432,7 +430,7 @@ func (c *hwMonCollector) Update(ch chan<- prometheus.Metric) error { // Step 1: scan /sys/class/hwmon, resolve all symlinks and call // updatesHwmon for each folder - hwmonPathName := filepath.Join(sysFilePath("class"), "hwmon") + hwmonPathName := filepath.Join(c.config.Path.sysFilePath("class"), "hwmon") hwmonFiles, err := os.ReadDir(hwmonPathName) if err != nil { diff --git a/collector/infiniband_linux.go b/collector/infiniband_linux.go index b0928da3cf..15d3fb3e7a 100644 --- a/collector/infiniband_linux.go +++ b/collector/infiniband_linux.go @@ -40,11 +40,11 @@ func init() { } // NewInfiniBandCollector returns a new Collector exposing InfiniBand stats. -func NewInfiniBandCollector(logger log.Logger) (Collector, error) { +func NewInfiniBandCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { var i infinibandCollector var err error - i.fs, err = sysfs.NewFS(*sysPath) + i.fs, err = sysfs.NewFS(*config.Path.SysPath) if err != nil { return nil, fmt.Errorf("failed to open sysfs: %w", err) } diff --git a/collector/interrupts_common.go b/collector/interrupts_common.go index eea703f97e..94c4b60ce0 100644 --- a/collector/interrupts_common.go +++ b/collector/interrupts_common.go @@ -25,6 +25,7 @@ import ( type interruptsCollector struct { desc typedDesc logger log.Logger + config *NodeCollectorConfig } func init() { @@ -32,7 +33,7 @@ func init() { } // NewInterruptsCollector returns a new Collector exposing interrupts stats. -func NewInterruptsCollector(logger log.Logger) (Collector, error) { +func NewInterruptsCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &interruptsCollector{ desc: typedDesc{prometheus.NewDesc( namespace+"_interrupts_total", @@ -40,5 +41,6 @@ func NewInterruptsCollector(logger log.Logger) (Collector, error) { interruptLabelNames, nil, ), prometheus.CounterValue}, logger: logger, + config: config, }, nil } diff --git a/collector/interrupts_linux.go b/collector/interrupts_linux.go index ede7819111..b78aa33e90 100644 --- a/collector/interrupts_linux.go +++ b/collector/interrupts_linux.go @@ -33,7 +33,7 @@ var ( ) func (c *interruptsCollector) Update(ch chan<- prometheus.Metric) (err error) { - interrupts, err := getInterrupts() + interrupts, err := getInterrupts(c.config) if err != nil { return fmt.Errorf("couldn't get interrupts: %w", err) } @@ -55,8 +55,8 @@ type interrupt struct { values []string } -func getInterrupts() (map[string]interrupt, error) { - file, err := os.Open(procFilePath("interrupts")) +func getInterrupts(config *NodeCollectorConfig) (map[string]interrupt, error) { + file, err := os.Open(config.Path.procFilePath("interrupts")) if err != nil { return nil, err } diff --git a/collector/ipvs_linux.go b/collector/ipvs_linux.go index 63a3a1a8a8..3a7c1389b2 100644 --- a/collector/ipvs_linux.go +++ b/collector/ipvs_linux.go @@ -24,7 +24,6 @@ import ( "strconv" "strings" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" @@ -64,7 +63,6 @@ var ( ipvsLabelProto, ipvsLabelLocalMark, } - ipvsLabels = kingpin.Flag("collector.ipvs.backend-labels", "Comma separated list for IPVS backend stats labels.").Default(strings.Join(fullIpvsBackendLabels, ",")).String() ) func init() { @@ -73,23 +71,28 @@ func init() { // NewIPVSCollector sets up a new collector for IPVS metrics. It accepts the // "procfs" config parameter to override the default proc location (/proc). -func NewIPVSCollector(logger log.Logger) (Collector, error) { - return newIPVSCollector(logger) +func NewIPVSCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + return newIPVSCollector(config, logger) } -func newIPVSCollector(logger log.Logger) (*ipvsCollector, error) { +func newIPVSCollector(config *NodeCollectorConfig, logger log.Logger) (*ipvsCollector, error) { var ( c ipvsCollector err error subsystem = "ipvs" ) - if c.backendLabels, err = c.parseIpvsLabels(*ipvsLabels); err != nil { + if !config.IPVS.LabelsSet { // use default labels if flag is not set + labels := strings.Join(fullIpvsBackendLabels, ",") + config.IPVS.Labels = &labels + } + + if c.backendLabels, err = c.parseIpvsLabels(*config.IPVS.Labels); err != nil { return nil, err } c.logger = logger - c.fs, err = procfs.NewFS(*procPath) + c.fs, err = procfs.NewFS(*config.Path.ProcPath) if err != nil { return nil, fmt.Errorf("failed to open procfs: %w", err) } diff --git a/collector/ipvs_linux_test.go b/collector/ipvs_linux_test.go index 6ee41b299b..c33c65f3cc 100644 --- a/collector/ipvs_linux_test.go +++ b/collector/ipvs_linux_test.go @@ -27,12 +27,15 @@ import ( "github.com/go-kit/log" - "github.com/alecthomas/kingpin/v2" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" ) func TestIPVSCollector(t *testing.T) { + path := "fixtures/proc" + config := newNodeCollectorWithPaths() + config.Path.ProcPath = &path + testcases := []struct { labels string expects []string @@ -107,14 +110,11 @@ func TestIPVSCollector(t *testing.T) { } for _, test := range testcases { t.Run(test.labels, func(t *testing.T) { - args := []string{"--path.procfs", "fixtures/proc"} if test.labels != "" { - args = append(args, "--collector.ipvs.backend-labels="+test.labels) - } - if _, err := kingpin.CommandLine.Parse(args); err != nil { - t.Fatal(err) + config.IPVS.LabelsSet = true + config.IPVS.Labels = &test.labels } - collector, err := newIPVSCollector(log.NewNopLogger()) + collector, err := newIPVSCollector(config, log.NewNopLogger()) if err != nil { if test.err == nil { t.Fatal(err) @@ -164,6 +164,10 @@ func (c miniCollector) Describe(ch chan<- *prometheus.Desc) { } func TestIPVSCollectorResponse(t *testing.T) { + path := "fixtures/proc" + config := newNodeCollectorWithPaths() + config.Path.ProcPath = &path + testcases := []struct { labels string metricsFile string @@ -175,14 +179,11 @@ func TestIPVSCollectorResponse(t *testing.T) { } for _, test := range testcases { t.Run(test.labels, func(t *testing.T) { - args := []string{"--path.procfs", "fixtures/proc"} if test.labels != "" { - args = append(args, "--collector.ipvs.backend-labels="+test.labels) - } - if _, err := kingpin.CommandLine.Parse(args); err != nil { - t.Fatal(err) + config.IPVS.LabelsSet = true + config.IPVS.Labels = &test.labels } - collector, err := NewIPVSCollector(log.NewNopLogger()) + collector, err := NewIPVSCollector(config, log.NewNopLogger()) if err != nil { t.Fatal(err) } diff --git a/collector/ksmd_linux.go b/collector/ksmd_linux.go index 6d4142ae9a..091fb37305 100644 --- a/collector/ksmd_linux.go +++ b/collector/ksmd_linux.go @@ -32,6 +32,7 @@ var ( type ksmdCollector struct { metricDescs map[string]*prometheus.Desc logger log.Logger + config *NodeCollectorConfig } func init() { @@ -50,7 +51,7 @@ func getCanonicalMetricName(filename string) string { } // NewKsmdCollector returns a new Collector exposing kernel/system statistics. -func NewKsmdCollector(logger log.Logger) (Collector, error) { +func NewKsmdCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { subsystem := "ksmd" descs := make(map[string]*prometheus.Desc) @@ -59,13 +60,13 @@ func NewKsmdCollector(logger log.Logger) (Collector, error) { prometheus.BuildFQName(namespace, subsystem, getCanonicalMetricName(n)), fmt.Sprintf("ksmd '%s' file.", n), nil, nil) } - return &ksmdCollector{descs, logger}, nil + return &ksmdCollector{descs, logger, config}, nil } // Update implements Collector and exposes kernel and system statistics. func (c *ksmdCollector) Update(ch chan<- prometheus.Metric) error { for _, n := range ksmdFiles { - val, err := readUintFromFile(sysFilePath(filepath.Join("kernel/mm/ksm", n))) + val, err := readUintFromFile(c.config.Path.sysFilePath(filepath.Join("kernel/mm/ksm", n))) if err != nil { return err } diff --git a/collector/lnstat_linux.go b/collector/lnstat_linux.go index b3c90dc06e..f74207b5fd 100644 --- a/collector/lnstat_linux.go +++ b/collector/lnstat_linux.go @@ -27,14 +27,15 @@ import ( type lnstatCollector struct { logger log.Logger + config *NodeCollectorConfig } func init() { registerCollector("lnstat", defaultDisabled, NewLnstatCollector) } -func NewLnstatCollector(logger log.Logger) (Collector, error) { - return &lnstatCollector{logger}, nil +func NewLnstatCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + return &lnstatCollector{logger, config}, nil } func (c *lnstatCollector) Update(ch chan<- prometheus.Metric) error { @@ -42,7 +43,7 @@ func (c *lnstatCollector) Update(ch chan<- prometheus.Metric) error { subsystem = "lnstat" ) - fs, err := procfs.NewFS(*procPath) + fs, err := procfs.NewFS(*c.config.Path.ProcPath) if err != nil { return fmt.Errorf("failed to open procfs: %w", err) } diff --git a/collector/loadavg.go b/collector/loadavg.go index cb7b2cb142..086886c474 100644 --- a/collector/loadavg.go +++ b/collector/loadavg.go @@ -28,6 +28,7 @@ import ( type loadavgCollector struct { metric []typedDesc logger log.Logger + config *NodeCollectorConfig } func init() { @@ -35,7 +36,7 @@ func init() { } // NewLoadavgCollector returns a new Collector exposing load average stats. -func NewLoadavgCollector(logger log.Logger) (Collector, error) { +func NewLoadavgCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &loadavgCollector{ metric: []typedDesc{ {prometheus.NewDesc(namespace+"_load1", "1m load average.", nil, nil), prometheus.GaugeValue}, @@ -43,11 +44,12 @@ func NewLoadavgCollector(logger log.Logger) (Collector, error) { {prometheus.NewDesc(namespace+"_load15", "15m load average.", nil, nil), prometheus.GaugeValue}, }, logger: logger, + config: config, }, nil } func (c *loadavgCollector) Update(ch chan<- prometheus.Metric) error { - loads, err := getLoad() + loads, err := getLoad(c.config) if err != nil { return fmt.Errorf("couldn't get load: %w", err) } diff --git a/collector/loadavg_bsd.go b/collector/loadavg_bsd.go index a1f5ae6643..1d591b8fbb 100644 --- a/collector/loadavg_bsd.go +++ b/collector/loadavg_bsd.go @@ -23,7 +23,7 @@ import ( "golang.org/x/sys/unix" ) -func getLoad() ([]float64, error) { +func getLoad(_ *NodeCollectorConfig) ([]float64, error) { type loadavg struct { load [3]uint32 scale int diff --git a/collector/loadavg_linux.go b/collector/loadavg_linux.go index aab11b1851..28af2a2d30 100644 --- a/collector/loadavg_linux.go +++ b/collector/loadavg_linux.go @@ -24,12 +24,12 @@ import ( ) // Read loadavg from /proc. -func getLoad() (loads []float64, err error) { - data, err := os.ReadFile(procFilePath("loadavg")) +func getLoad(config *NodeCollectorConfig) (loads []float64, err error) { + data, err := os.ReadFile(config.Path.procFilePath("loadavg")) if err != nil { return nil, err } - loads, err = parseLoad(string(data)) + loads, err = parseLoad(config, string(data)) if err != nil { return nil, err } @@ -37,11 +37,11 @@ func getLoad() (loads []float64, err error) { } // Parse /proc loadavg and return 1m, 5m and 15m. -func parseLoad(data string) (loads []float64, err error) { +func parseLoad(config *NodeCollectorConfig, data string) (loads []float64, err error) { loads = make([]float64, 3) parts := strings.Fields(data) if len(parts) < 3 { - return nil, fmt.Errorf("unexpected content in %s", procFilePath("loadavg")) + return nil, fmt.Errorf("unexpected content in %s", config.Path.procFilePath("loadavg")) } for i, load := range parts[0:3] { loads[i], err = strconv.ParseFloat(load, 64) diff --git a/collector/loadavg_linux_test.go b/collector/loadavg_linux_test.go index 2d56317dc5..cd96f3c01c 100644 --- a/collector/loadavg_linux_test.go +++ b/collector/loadavg_linux_test.go @@ -19,8 +19,10 @@ package collector import "testing" func TestLoad(t *testing.T) { + config := &NodeCollectorConfig{} + want := []float64{0.21, 0.37, 0.39} - loads, err := parseLoad("0.21 0.37 0.39 1/719 19737") + loads, err := parseLoad(config, "0.21 0.37 0.39 1/719 19737") if err != nil { t.Fatal(err) } diff --git a/collector/loadavg_solaris.go b/collector/loadavg_solaris.go index 316233fa98..4d4c8e0978 100644 --- a/collector/loadavg_solaris.go +++ b/collector/loadavg_solaris.go @@ -43,7 +43,7 @@ func kstatToFloat(ks *kstat.KStat, kstatKey string) float64 { return kstatLoadavg } -func getLoad() ([]float64, error) { +func getLoad(_ *NodeCollectorConfig) ([]float64, error) { tok, err := kstat.Open() if err != nil { panic(err) diff --git a/collector/logind_linux.go b/collector/logind_linux.go index de5b0d18ad..265f87678c 100644 --- a/collector/logind_linux.go +++ b/collector/logind_linux.go @@ -86,7 +86,7 @@ func init() { } // NewLogindCollector returns a new Collector exposing logind statistics. -func NewLogindCollector(logger log.Logger) (Collector, error) { +func NewLogindCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &logindCollector{logger}, nil } diff --git a/collector/mdadm_linux.go b/collector/mdadm_linux.go index 89c56b75d0..1e3c7d383e 100644 --- a/collector/mdadm_linux.go +++ b/collector/mdadm_linux.go @@ -29,6 +29,7 @@ import ( type mdadmCollector struct { logger log.Logger + config *NodeCollectorConfig } func init() { @@ -36,8 +37,8 @@ func init() { } // NewMdadmCollector returns a new Collector exposing raid statistics. -func NewMdadmCollector(logger log.Logger) (Collector, error) { - return &mdadmCollector{logger}, nil +func NewMdadmCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + return &mdadmCollector{logger, config}, nil } var ( @@ -102,7 +103,7 @@ var ( ) func (c *mdadmCollector) Update(ch chan<- prometheus.Metric) error { - fs, err := procfs.NewFS(*procPath) + fs, err := procfs.NewFS(*c.config.Path.ProcPath) if err != nil { return fmt.Errorf("failed to open procfs: %w", err) @@ -112,7 +113,7 @@ func (c *mdadmCollector) Update(ch chan<- prometheus.Metric) error { if err != nil { if errors.Is(err, os.ErrNotExist) { - level.Debug(c.logger).Log("msg", "Not collecting mdstat, file does not exist", "file", *procPath) + level.Debug(c.logger).Log("msg", "Not collecting mdstat, file does not exist", "file", *c.config.Path.ProcPath) return ErrNoData } diff --git a/collector/meminfo.go b/collector/meminfo.go index b59337ddbd..26f85f5ada 100644 --- a/collector/meminfo.go +++ b/collector/meminfo.go @@ -32,6 +32,7 @@ const ( type meminfoCollector struct { logger log.Logger + config *NodeCollectorConfig } func init() { @@ -39,8 +40,8 @@ func init() { } // NewMeminfoCollector returns a new Collector exposing memory stats. -func NewMeminfoCollector(logger log.Logger) (Collector, error) { - return &meminfoCollector{logger}, nil +func NewMeminfoCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + return &meminfoCollector{logger, config}, nil } // Update calls (*meminfoCollector).getMemInfo to get the platform specific diff --git a/collector/meminfo_linux.go b/collector/meminfo_linux.go index cee295024f..c6c2497073 100644 --- a/collector/meminfo_linux.go +++ b/collector/meminfo_linux.go @@ -31,7 +31,7 @@ var ( ) func (c *meminfoCollector) getMemInfo() (map[string]float64, error) { - file, err := os.Open(procFilePath("meminfo")) + file, err := os.Open(c.config.Path.procFilePath("meminfo")) if err != nil { return nil, err } diff --git a/collector/meminfo_numa_linux.go b/collector/meminfo_numa_linux.go index 5ce08e99d9..94ed6bcb6d 100644 --- a/collector/meminfo_numa_linux.go +++ b/collector/meminfo_numa_linux.go @@ -46,6 +46,7 @@ type meminfoMetric struct { type meminfoNumaCollector struct { metricDescs map[string]*prometheus.Desc logger log.Logger + config *NodeCollectorConfig } func init() { @@ -53,15 +54,16 @@ func init() { } // NewMeminfoNumaCollector returns a new Collector exposing memory stats. -func NewMeminfoNumaCollector(logger log.Logger) (Collector, error) { +func NewMeminfoNumaCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &meminfoNumaCollector{ metricDescs: map[string]*prometheus.Desc{}, logger: logger, + config: config, }, nil } func (c *meminfoNumaCollector) Update(ch chan<- prometheus.Metric) error { - metrics, err := getMemInfoNuma() + metrics, err := getMemInfoNuma(c.config) if err != nil { return fmt.Errorf("couldn't get NUMA meminfo: %w", err) } @@ -79,12 +81,12 @@ func (c *meminfoNumaCollector) Update(ch chan<- prometheus.Metric) error { return nil } -func getMemInfoNuma() ([]meminfoMetric, error) { +func getMemInfoNuma(config *NodeCollectorConfig) ([]meminfoMetric, error) { var ( metrics []meminfoMetric ) - nodes, err := filepath.Glob(sysFilePath("devices/system/node/node[0-9]*")) + nodes, err := filepath.Glob(config.Path.sysFilePath("devices/system/node/node[0-9]*")) if err != nil { return nil, err } diff --git a/collector/memory_bsd.go b/collector/memory_bsd.go index 6f16ac896d..f9c62a1cda 100644 --- a/collector/memory_bsd.go +++ b/collector/memory_bsd.go @@ -41,7 +41,7 @@ func init() { } // NewMemoryCollector returns a new Collector exposing memory stats. -func NewMemoryCollector(logger log.Logger) (Collector, error) { +func NewMemoryCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { tmp32, err := unix.SysctlUint32("vm.stats.vm.v_page_size") if err != nil { return nil, fmt.Errorf("sysctl(vm.stats.vm.v_page_size) failed: %w", err) diff --git a/collector/mountstats_linux.go b/collector/mountstats_linux.go index 9dea6fad71..fb9bce5ca6 100644 --- a/collector/mountstats_linux.go +++ b/collector/mountstats_linux.go @@ -111,8 +111,8 @@ func init() { } // NewMountStatsCollector returns a new Collector exposing NFS statistics. -func NewMountStatsCollector(logger log.Logger) (Collector, error) { - fs, err := procfs.NewFS(*procPath) +func NewMountStatsCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := procfs.NewFS(*config.Path.ProcPath) if err != nil { return nil, fmt.Errorf("failed to open procfs: %w", err) } diff --git a/collector/netclass_linux.go b/collector/netclass_linux.go index 5d9324cdee..0cacb9fbc7 100644 --- a/collector/netclass_linux.go +++ b/collector/netclass_linux.go @@ -23,25 +23,19 @@ import ( "os" "regexp" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/procfs/sysfs" ) -var ( - netclassIgnoredDevices = kingpin.Flag("collector.netclass.ignored-devices", "Regexp of net devices to ignore for netclass collector.").Default("^$").String() - netclassInvalidSpeed = kingpin.Flag("collector.netclass.ignore-invalid-speed", "Ignore devices where the speed is invalid. This will be the default behavior in 2.x.").Bool() - netclassNetlink = kingpin.Flag("collector.netclass.netlink", "Use netlink to gather stats instead of /proc/net/dev.").Default("false").Bool() -) - type netClassCollector struct { fs sysfs.FS subsystem string ignoredDevicesPattern *regexp.Regexp metricDescs map[string]*prometheus.Desc logger log.Logger + config *NodeCollectorConfig } func init() { @@ -49,23 +43,24 @@ func init() { } // NewNetClassCollector returns a new Collector exposing network class stats. -func NewNetClassCollector(logger log.Logger) (Collector, error) { - fs, err := sysfs.NewFS(*sysPath) +func NewNetClassCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := sysfs.NewFS(*config.Path.SysPath) if err != nil { return nil, fmt.Errorf("failed to open sysfs: %w", err) } - pattern := regexp.MustCompile(*netclassIgnoredDevices) + pattern := regexp.MustCompile(*config.NetClass.IgnoredDevices) return &netClassCollector{ fs: fs, subsystem: "network", ignoredDevicesPattern: pattern, metricDescs: map[string]*prometheus.Desc{}, logger: logger, + config: config, }, nil } func (c *netClassCollector) Update(ch chan<- prometheus.Metric) error { - if *netclassNetlink { + if *c.config.NetClass.Netlink { return c.netClassRTNLUpdate(ch) } return c.netClassSysfsUpdate(ch) @@ -121,7 +116,7 @@ func (c *netClassCollector) netClassSysfsUpdate(ch chan<- prometheus.Metric) err if ifaceInfo.Speed != nil { // Some devices return -1 if the speed is unknown. - if *ifaceInfo.Speed >= 0 || !*netclassInvalidSpeed { + if *ifaceInfo.Speed >= 0 || !*c.config.NetClass.InvalidSpeed { speedBytes := int64(*ifaceInfo.Speed * 1000 * 1000 / 8) pushMetric(ch, c.getFieldDesc("speed_bytes"), "speed_bytes", speedBytes, prometheus.GaugeValue, ifaceInfo.Name) } diff --git a/collector/netclass_rtnl_linux.go b/collector/netclass_rtnl_linux.go index ef963715e5..0bf98cf3fe 100644 --- a/collector/netclass_rtnl_linux.go +++ b/collector/netclass_rtnl_linux.go @@ -22,7 +22,6 @@ import ( "io/fs" "path/filepath" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log/level" "github.com/jsimonetti/rtnetlink" "github.com/mdlayher/ethtool" @@ -31,8 +30,7 @@ import ( ) var ( - netclassRTNLWithStats = kingpin.Flag("collector.netclass_rtnl.with-stats", "Expose the statistics for each network device, replacing netdev collector.").Bool() - operstateStr = []string{ + operstateStr = []string{ "unknown", "notpresent", "down", "lowerlayerdown", "testing", "dormant", "up", } @@ -142,7 +140,7 @@ func (c *netClassCollector) netClassRTNLUpdate(ch chan<- prometheus.Metric) erro pushMetric(ch, c.getFieldDesc("protocol_type"), "protocol_type", msg.Type, prometheus.GaugeValue, msg.Attributes.Name) // Skip statistics if argument collector.netclass_rtnl.with-stats is false or statistics are unavailable. - if netclassRTNLWithStats == nil || !*netclassRTNLWithStats || msg.Attributes.Stats64 == nil { + if c.config.NetClass.RTNLWithStats == nil || !*c.config.NetClass.RTNLWithStats || msg.Attributes.Stats64 == nil { continue } diff --git a/collector/netdev_bsd.go b/collector/netdev_bsd.go index 691bbec4ad..93342193c8 100644 --- a/collector/netdev_bsd.go +++ b/collector/netdev_bsd.go @@ -34,7 +34,7 @@ import ( */ import "C" -func getNetDevStats(filter *deviceFilter, logger log.Logger) (netDevStats, error) { +func getNetDevStats(_ *NodeCollectorConfig, _ *bool, filter *deviceFilter, logger log.Logger) (netDevStats, error) { netDev := netDevStats{} var ifap, ifa *C.struct_ifaddrs diff --git a/collector/netdev_common.go b/collector/netdev_common.go index 089f1e5870..b841378e16 100644 --- a/collector/netdev_common.go +++ b/collector/netdev_common.go @@ -24,27 +24,18 @@ import ( "strconv" "sync" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" ) -var ( - netdevDeviceInclude = kingpin.Flag("collector.netdev.device-include", "Regexp of net devices to include (mutually exclusive to device-exclude).").String() - oldNetdevDeviceInclude = kingpin.Flag("collector.netdev.device-whitelist", "DEPRECATED: Use collector.netdev.device-include").Hidden().String() - netdevDeviceExclude = kingpin.Flag("collector.netdev.device-exclude", "Regexp of net devices to exclude (mutually exclusive to device-include).").String() - oldNetdevDeviceExclude = kingpin.Flag("collector.netdev.device-blacklist", "DEPRECATED: Use collector.netdev.device-exclude").Hidden().String() - netdevAddressInfo = kingpin.Flag("collector.netdev.address-info", "Collect address-info for every device").Bool() - netdevDetailedMetrics = kingpin.Flag("collector.netdev.enable-detailed-metrics", "Use (incompatible) metric names that provide more detailed stats on Linux").Bool() -) - type netDevCollector struct { subsystem string deviceFilter deviceFilter metricDescsMutex sync.Mutex metricDescs map[string]*prometheus.Desc logger log.Logger + config *NodeCollectorConfig } type netDevStats map[string]map[string]uint64 @@ -54,42 +45,43 @@ func init() { } // NewNetDevCollector returns a new Collector exposing network device stats. -func NewNetDevCollector(logger log.Logger) (Collector, error) { - if *oldNetdevDeviceInclude != "" { - if *netdevDeviceInclude == "" { +func NewNetDevCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + if *config.NetDev.OldDeviceInclude != "" { + if *config.NetDev.DeviceInclude == "" { level.Warn(logger).Log("msg", "--collector.netdev.device-whitelist is DEPRECATED and will be removed in 2.0.0, use --collector.netdev.device-include") - *netdevDeviceInclude = *oldNetdevDeviceInclude + *config.NetDev.DeviceInclude = *config.NetDev.OldDeviceInclude } else { return nil, errors.New("--collector.netdev.device-whitelist and --collector.netdev.device-include are mutually exclusive") } } - if *oldNetdevDeviceExclude != "" { - if *netdevDeviceExclude == "" { + if *config.NetDev.OldDeviceExclude != "" { + if *config.NetDev.DeviceExclude == "" { level.Warn(logger).Log("msg", "--collector.netdev.device-blacklist is DEPRECATED and will be removed in 2.0.0, use --collector.netdev.device-exclude") - *netdevDeviceExclude = *oldNetdevDeviceExclude + *config.NetDev.DeviceExclude = *config.NetDev.OldDeviceExclude } else { return nil, errors.New("--collector.netdev.device-blacklist and --collector.netdev.device-exclude are mutually exclusive") } } - if *netdevDeviceExclude != "" && *netdevDeviceInclude != "" { + if *config.NetDev.DeviceExclude != "" && *config.NetDev.DeviceInclude != "" { return nil, errors.New("device-exclude & device-include are mutually exclusive") } - if *netdevDeviceExclude != "" { - level.Info(logger).Log("msg", "Parsed flag --collector.netdev.device-exclude", "flag", *netdevDeviceExclude) + if *config.NetDev.DeviceExclude != "" { + level.Info(logger).Log("msg", "Parsed flag --collector.netdev.device-exclude", "flag", *config.NetDev.DeviceExclude) } - if *netdevDeviceInclude != "" { - level.Info(logger).Log("msg", "Parsed Flag --collector.netdev.device-include", "flag", *netdevDeviceInclude) + if *config.NetDev.DeviceInclude != "" { + level.Info(logger).Log("msg", "Parsed Flag --collector.netdev.device-include", "flag", *config.NetDev.DeviceInclude) } return &netDevCollector{ subsystem: "network", - deviceFilter: newDeviceFilter(*netdevDeviceExclude, *netdevDeviceInclude), + deviceFilter: newDeviceFilter(*config.NetDev.DeviceExclude, *config.NetDev.DeviceInclude), metricDescs: map[string]*prometheus.Desc{}, logger: logger, + config: config, }, nil } @@ -110,12 +102,12 @@ func (c *netDevCollector) metricDesc(key string) *prometheus.Desc { } func (c *netDevCollector) Update(ch chan<- prometheus.Metric) error { - netDev, err := getNetDevStats(&c.deviceFilter, c.logger) + netDev, err := getNetDevStats(c.config, c.config.NetDev.Netlink, &c.deviceFilter, c.logger) if err != nil { return fmt.Errorf("couldn't get netstats: %w", err) } for dev, devStats := range netDev { - if !*netdevDetailedMetrics { + if !*c.config.NetDev.DetailedMetrics { legacy(devStats) } for key, value := range devStats { @@ -123,7 +115,7 @@ func (c *netDevCollector) Update(ch chan<- prometheus.Metric) error { ch <- prometheus.MustNewConstMetric(desc, prometheus.CounterValue, float64(value), dev) } } - if *netdevAddressInfo { + if *c.config.NetDev.AddressInfo { interfaces, err := net.Interfaces() if err != nil { return fmt.Errorf("could not get network interfaces: %w", err) diff --git a/collector/netdev_darwin.go b/collector/netdev_darwin.go index c08f1f8ede..fc68822d02 100644 --- a/collector/netdev_darwin.go +++ b/collector/netdev_darwin.go @@ -27,7 +27,7 @@ import ( "golang.org/x/sys/unix" ) -func getNetDevStats(filter *deviceFilter, logger log.Logger) (netDevStats, error) { +func getNetDevStats(_ *NodeCollectorConfig, _ *bool, filter *deviceFilter, logger log.Logger) (netDevStats, error) { netDev := netDevStats{} ifs, err := net.Interfaces() diff --git a/collector/netdev_linux.go b/collector/netdev_linux.go index f3348cda73..01d5501256 100644 --- a/collector/netdev_linux.go +++ b/collector/netdev_linux.go @@ -19,22 +19,17 @@ package collector import ( "fmt" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/jsimonetti/rtnetlink" "github.com/prometheus/procfs" ) -var ( - netDevNetlink = kingpin.Flag("collector.netdev.netlink", "Use netlink to gather stats instead of /proc/net/dev.").Default("true").Bool() -) - -func getNetDevStats(filter *deviceFilter, logger log.Logger) (netDevStats, error) { +func getNetDevStats(config *NodeCollectorConfig, netDevNetlink *bool, filter *deviceFilter, logger log.Logger) (netDevStats, error) { if *netDevNetlink { return netlinkStats(filter, logger) } - return procNetDevStats(filter, logger) + return procNetDevStats(config, filter, logger) } func netlinkStats(filter *deviceFilter, logger log.Logger) (netDevStats, error) { @@ -141,10 +136,10 @@ func parseNetlinkStats(links []rtnetlink.LinkMessage, filter *deviceFilter, logg return metrics } -func procNetDevStats(filter *deviceFilter, logger log.Logger) (netDevStats, error) { +func procNetDevStats(config *NodeCollectorConfig, filter *deviceFilter, logger log.Logger) (netDevStats, error) { metrics := netDevStats{} - fs, err := procfs.NewFS(*procPath) + fs, err := procfs.NewFS(*config.Path.ProcPath) if err != nil { return metrics, fmt.Errorf("failed to open procfs: %w", err) } diff --git a/collector/netdev_openbsd.go b/collector/netdev_openbsd.go index b90e3ba7ab..a5397ff33b 100644 --- a/collector/netdev_openbsd.go +++ b/collector/netdev_openbsd.go @@ -31,7 +31,7 @@ import ( */ import "C" -func getNetDevStats(filter *deviceFilter, logger log.Logger) (netDevStats, error) { +func getNetDevStats(_ *NodeCollectorConfig, _ *bool, filter *deviceFilter, logger log.Logger) (netDevStats, error) { netDev := netDevStats{} var ifap, ifa *C.struct_ifaddrs diff --git a/collector/netdev_openbsd_amd64.go b/collector/netdev_openbsd_amd64.go index da8a81f34e..415cd3eacb 100644 --- a/collector/netdev_openbsd_amd64.go +++ b/collector/netdev_openbsd_amd64.go @@ -24,7 +24,7 @@ import ( "unsafe" ) -func getNetDevStats(filter *deviceFilter, logger log.Logger) (netDevStats, error) { +func getNetDevStats(_ *NodeCollectorConfig, _ *bool, filter *deviceFilter, logger log.Logger) (netDevStats, error) { netDev := netDevStats{} mib := [6]_C_int{unix.CTL_NET, unix.AF_ROUTE, 0, 0, unix.NET_RT_IFLIST, 0} diff --git a/collector/netisr_freebsd.go b/collector/netisr_freebsd.go index 43991f3ab9..cc417b33c3 100644 --- a/collector/netisr_freebsd.go +++ b/collector/netisr_freebsd.go @@ -36,7 +36,7 @@ func init() { registerCollector("netisr", defaultEnabled, NewNetisrCollector) } -func NewNetisrCollector(logger log.Logger) (Collector, error) { +func NewNetisrCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &netisrCollector{ sysctls: []bsdSysctl{ { diff --git a/collector/netstat_linux.go b/collector/netstat_linux.go index 9115ef57b0..b3f21dbc01 100644 --- a/collector/netstat_linux.go +++ b/collector/netstat_linux.go @@ -26,7 +26,6 @@ import ( "strconv" "strings" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" ) @@ -35,39 +34,37 @@ const ( netStatsSubsystem = "netstat" ) -var ( - netStatFields = kingpin.Flag("collector.netstat.fields", "Regexp of fields to return for netstat collector.").Default("^(.*_(InErrors|InErrs)|Ip_Forwarding|Ip(6|Ext)_(InOctets|OutOctets)|Icmp6?_(InMsgs|OutMsgs)|TcpExt_(Listen.*|Syncookies.*|TCPSynRetrans|TCPTimeouts)|Tcp_(ActiveOpens|InSegs|OutSegs|OutRsts|PassiveOpens|RetransSegs|CurrEstab)|Udp6?_(InDatagrams|OutDatagrams|NoPorts|RcvbufErrors|SndbufErrors))$").String() -) - type netStatCollector struct { fieldPattern *regexp.Regexp logger log.Logger + config *NodeCollectorConfig } func init() { - registerCollector("netstat", defaultEnabled, NewNetStatCollector) + registerCollector(netStatsSubsystem, defaultEnabled, NewNetStatCollector) } // NewNetStatCollector takes and returns // a new Collector exposing network stats. -func NewNetStatCollector(logger log.Logger) (Collector, error) { - pattern := regexp.MustCompile(*netStatFields) +func NewNetStatCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + pattern := regexp.MustCompile(*config.NetStat.Fields) return &netStatCollector{ fieldPattern: pattern, logger: logger, + config: config, }, nil } func (c *netStatCollector) Update(ch chan<- prometheus.Metric) error { - netStats, err := getNetStats(procFilePath("net/netstat")) + netStats, err := getNetStats(c.config.Path.procFilePath("net/netstat")) if err != nil { return fmt.Errorf("couldn't get netstats: %w", err) } - snmpStats, err := getNetStats(procFilePath("net/snmp")) + snmpStats, err := getNetStats(c.config.Path.procFilePath("net/snmp")) if err != nil { return fmt.Errorf("couldn't get SNMP stats: %w", err) } - snmp6Stats, err := getSNMP6Stats(procFilePath("net/snmp6")) + snmp6Stats, err := getSNMP6Stats(c.config.Path.procFilePath("net/snmp6")) if err != nil { return fmt.Errorf("couldn't get SNMP6 stats: %w", err) } diff --git a/collector/network_route_linux.go b/collector/network_route_linux.go index c77e175109..210636d117 100644 --- a/collector/network_route_linux.go +++ b/collector/network_route_linux.go @@ -18,10 +18,11 @@ package collector import ( "fmt" - "golang.org/x/sys/unix" "net" "strconv" + "golang.org/x/sys/unix" + "github.com/go-kit/log" "github.com/jsimonetti/rtnetlink" "github.com/prometheus/client_golang/prometheus" @@ -38,7 +39,7 @@ func init() { } // NewNetworkRouteCollector returns a new Collector exposing systemd statistics. -func NewNetworkRouteCollector(logger log.Logger) (Collector, error) { +func NewNetworkRouteCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { const subsystem = "network" routeInfoDesc := prometheus.NewDesc( diff --git a/collector/nfs_linux.go b/collector/nfs_linux.go index e08acdbad7..c711e89136 100644 --- a/collector/nfs_linux.go +++ b/collector/nfs_linux.go @@ -48,8 +48,8 @@ func init() { } // NewNfsCollector returns a new Collector exposing NFS statistics. -func NewNfsCollector(logger log.Logger) (Collector, error) { - fs, err := nfs.NewFS(*procPath) +func NewNfsCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := nfs.NewFS(*config.Path.ProcPath) if err != nil { return nil, fmt.Errorf("failed to open procfs: %w", err) } diff --git a/collector/nfsd_linux.go b/collector/nfsd_linux.go index 8b310ea23c..5bd9590011 100644 --- a/collector/nfsd_linux.go +++ b/collector/nfsd_linux.go @@ -44,8 +44,8 @@ const ( ) // NewNFSdCollector returns a new Collector exposing /proc/net/rpc/nfsd statistics. -func NewNFSdCollector(logger log.Logger) (Collector, error) { - fs, err := nfs.NewFS(*procPath) +func NewNFSdCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := nfs.NewFS(*config.Path.ProcPath) if err != nil { return nil, fmt.Errorf("failed to open procfs: %w", err) } @@ -82,8 +82,6 @@ func (c *nfsdCollector) Update(ch chan<- prometheus.Metric) error { c.updateNFSdRequestsv2Stats(ch, &stats.V2Stats) c.updateNFSdRequestsv3Stats(ch, &stats.V3Stats) c.updateNFSdRequestsv4Stats(ch, &stats.V4Ops) - ch <- prometheus.MustNewConstMetric(c.requestsDesc, prometheus.CounterValue, - float64(stats.WdelegGetattr), "4", "WdelegGetattr") return nil } @@ -397,10 +395,6 @@ func (c *nfsdCollector) updateNFSdRequestsv4Stats(ch chan<- prometheus.Metric, s float64(s.SecInfo), proto, "SecInfo") ch <- prometheus.MustNewConstMetric(c.requestsDesc, prometheus.CounterValue, float64(s.SetAttr), proto, "SetAttr") - ch <- prometheus.MustNewConstMetric(c.requestsDesc, prometheus.CounterValue, - float64(s.SetClientID), proto, "SetClientID") - ch <- prometheus.MustNewConstMetric(c.requestsDesc, prometheus.CounterValue, - float64(s.SetClientIDConfirm), proto, "SetClientIDConfirm") ch <- prometheus.MustNewConstMetric(c.requestsDesc, prometheus.CounterValue, float64(s.Verify), proto, "Verify") ch <- prometheus.MustNewConstMetric(c.requestsDesc, prometheus.CounterValue, diff --git a/collector/ntp.go b/collector/ntp.go index 8b8db8a950..72643f8509 100644 --- a/collector/ntp.go +++ b/collector/ntp.go @@ -22,7 +22,6 @@ import ( "sync" "time" - "github.com/alecthomas/kingpin/v2" "github.com/beevik/ntp" "github.com/go-kit/log" "github.com/go-kit/log/level" @@ -35,16 +34,6 @@ const ( ) var ( - ntpServer = kingpin.Flag("collector.ntp.server", "NTP server to use for ntp collector").Default("127.0.0.1").String() - ntpServerPort = kingpin.Flag("collector.ntp.server-port", "UDP port number to connect to on NTP server").Default("123").Int() - ntpProtocolVersion = kingpin.Flag("collector.ntp.protocol-version", "NTP protocol version").Default("4").Int() - ntpServerIsLocal = kingpin.Flag("collector.ntp.server-is-local", "Certify that collector.ntp.server address is not a public ntp server").Default("false").Bool() - ntpIPTTL = kingpin.Flag("collector.ntp.ip-ttl", "IP TTL to use while sending NTP query").Default("1").Int() - // 3.46608s ~ 1.5s + PHI * (1 << maxPoll), where 1.5s is MAXDIST from ntp.org, it is 1.0 in RFC5905 - // max-distance option is used as-is without phi*(1< 4 { - return nil, fmt.Errorf("invalid NTP protocol version %d; must be 2, 3, or 4", *ntpProtocolVersion) + if *config.NTP.ProtocolVersion < 2 || *config.NTP.ProtocolVersion > 4 { + return nil, fmt.Errorf("invalid NTP protocol version %d; must be 2, 3, or 4", *config.NTP.ProtocolVersion) } - if *ntpOffsetTolerance < 0 { + if *config.NTP.OffsetTolerance < 0 { return nil, fmt.Errorf("offset tolerance must be non-negative") } - if *ntpServerPort < 1 || *ntpServerPort > 65535 { - return nil, fmt.Errorf("invalid NTP port number %d; must be between 1 and 65535 inclusive", *ntpServerPort) + if *config.NTP.ServerPort < 1 || *config.NTP.ServerPort > 65535 { + return nil, fmt.Errorf("invalid NTP port number %d; must be between 1 and 65535 inclusive", *config.NTP.ServerPort) } level.Warn(logger).Log("msg", "This collector is deprecated and will be removed in the next major version release.") @@ -123,15 +113,16 @@ func NewNtpCollector(logger log.Logger) (Collector, error) { nil, nil, ), prometheus.GaugeValue}, logger: logger, + config: config, }, nil } func (c *ntpCollector) Update(ch chan<- prometheus.Metric) error { - resp, err := ntp.QueryWithOptions(*ntpServer, ntp.QueryOptions{ - Version: *ntpProtocolVersion, - TTL: *ntpIPTTL, + resp, err := ntp.QueryWithOptions(*c.config.NTP.Server, ntp.QueryOptions{ + Version: *c.config.NTP.ProtocolVersion, + TTL: *c.config.NTP.IPTTL, Timeout: time.Second, // default `ntpdate` timeout - Port: *ntpServerPort, + Port: *c.config.NTP.ServerPort, }) if err != nil { return fmt.Errorf("couldn't get SNTP reply: %w", err) @@ -156,7 +147,7 @@ func (c *ntpCollector) Update(ch chan<- prometheus.Metric) error { // Here is SNTP packet sanity check that is exposed to move burden of // configuration from node_exporter user to the developer. - maxerr := *ntpOffsetTolerance + maxerr := *c.config.NTP.OffsetTolerance leapMidnightMutex.Lock() if resp.Leap == ntp.LeapAddSecond || resp.Leap == ntp.LeapDelSecond { // state of leapMidnight is cached as leap flag is dropped right after midnight @@ -168,7 +159,7 @@ func (c *ntpCollector) Update(ch chan<- prometheus.Metric) error { } leapMidnightMutex.Unlock() - if resp.Validate() == nil && resp.RootDistance <= *ntpMaxDistance && resp.MinError <= maxerr { + if resp.Validate() == nil && resp.RootDistance <= *c.config.NTP.MaxDistance && resp.MinError <= maxerr { ch <- c.sanity.mustNewConstMetric(1) } else { ch <- c.sanity.mustNewConstMetric(0) diff --git a/collector/nvme_linux.go b/collector/nvme_linux.go index 81d4ab2985..601c9265be 100644 --- a/collector/nvme_linux.go +++ b/collector/nvme_linux.go @@ -37,8 +37,8 @@ func init() { } // NewNVMeCollector returns a new Collector exposing NVMe stats. -func NewNVMeCollector(logger log.Logger) (Collector, error) { - fs, err := sysfs.NewFS(*sysPath) +func NewNVMeCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := sysfs.NewFS(*config.Path.SysPath) if err != nil { return nil, fmt.Errorf("failed to open sysfs: %w", err) } diff --git a/collector/os_release.go b/collector/os_release.go index 14a025a454..62f0afd699 100644 --- a/collector/os_release.go +++ b/collector/os_release.go @@ -65,6 +65,7 @@ type osReleaseCollector struct { osReleaseFilenames []string // all os-release file names to check version float64 versionDesc *prometheus.Desc + config *NodeCollectorConfig } type Plist struct { @@ -81,7 +82,7 @@ func init() { } // NewOSCollector returns a new Collector exposing os-release information. -func NewOSCollector(logger log.Logger) (Collector, error) { +func NewOSCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &osReleaseCollector{ logger: logger, infoDesc: prometheus.NewDesc( @@ -97,6 +98,7 @@ func NewOSCollector(logger log.Logger) (Collector, error) { "Metric containing the major.minor part of the OS version.", []string{"id", "id_like", "name"}, nil, ), + config: config, }, nil } @@ -174,7 +176,7 @@ func (c *osReleaseCollector) UpdateStruct(path string) error { func (c *osReleaseCollector) Update(ch chan<- prometheus.Metric) error { for i, path := range c.osReleaseFilenames { - err := c.UpdateStruct(*rootfsPath + path) + err := c.UpdateStruct(*c.config.Path.RootfsPath + path) if err == nil { break } diff --git a/collector/os_release_test.go b/collector/os_release_test.go index 46838f15f1..80cb0a25df 100644 --- a/collector/os_release_test.go +++ b/collector/os_release_test.go @@ -87,7 +87,7 @@ func TestUpdateStruct(t *testing.T) { } wantedVersion := 20.04 - collector, err := NewOSCollector(log.NewNopLogger()) + collector, err := NewOSCollector(&NodeCollectorConfig{}, log.NewNopLogger()) if err != nil { t.Fatal(err) } diff --git a/collector/paths.go b/collector/paths.go index 82c941876d..6a2c665542 100644 --- a/collector/paths.go +++ b/collector/paths.go @@ -16,40 +16,29 @@ package collector import ( "path/filepath" "strings" - - "github.com/alecthomas/kingpin/v2" - "github.com/prometheus/procfs" -) - -var ( - // The path of the proc filesystem. - procPath = kingpin.Flag("path.procfs", "procfs mountpoint.").Default(procfs.DefaultMountPoint).String() - sysPath = kingpin.Flag("path.sysfs", "sysfs mountpoint.").Default("/sys").String() - rootfsPath = kingpin.Flag("path.rootfs", "rootfs mountpoint.").Default("/").String() - udevDataPath = kingpin.Flag("path.udev.data", "udev data path.").Default("/run/udev/data").String() ) -func procFilePath(name string) string { - return filepath.Join(*procPath, name) +func (p *PathConfig) procFilePath(name string) string { + return filepath.Join(*p.ProcPath, name) } -func sysFilePath(name string) string { - return filepath.Join(*sysPath, name) +func (p *PathConfig) sysFilePath(name string) string { + return filepath.Join(*p.SysPath, name) } -func rootfsFilePath(name string) string { - return filepath.Join(*rootfsPath, name) +func (p *PathConfig) rootfsFilePath(name string) string { + return filepath.Join(*p.RootfsPath, name) } -func udevDataFilePath(name string) string { - return filepath.Join(*udevDataPath, name) +func (p *PathConfig) udevDataFilePath(name string) string { + return filepath.Join(*p.UdevDataPath, name) } -func rootfsStripPrefix(path string) string { - if *rootfsPath == "/" { +func (p *PathConfig) rootfsStripPrefix(path string) string { + if *p.RootfsPath == "/" { return path } - stripped := strings.TrimPrefix(path, *rootfsPath) + stripped := strings.TrimPrefix(path, *p.RootfsPath) if stripped == "" { return "/" } diff --git a/collector/paths_test.go b/collector/paths_test.go index 9426fa4b8a..7034ffa0cf 100644 --- a/collector/paths_test.go +++ b/collector/paths_test.go @@ -16,62 +16,70 @@ package collector import ( "testing" - "github.com/alecthomas/kingpin/v2" "github.com/prometheus/procfs" ) func TestDefaultProcPath(t *testing.T) { - if _, err := kingpin.CommandLine.Parse([]string{"--path.procfs", procfs.DefaultMountPoint}); err != nil { - t.Fatal(err) - } + config := newNodeCollectorWithPaths() + path := procfs.DefaultMountPoint + config.Path.ProcPath = &path - if got, want := procFilePath("somefile"), "/proc/somefile"; got != want { + if got, want := config.Path.procFilePath("somefile"), "/proc/somefile"; got != want { t.Errorf("Expected: %s, Got: %s", want, got) } - if got, want := procFilePath("some/file"), "/proc/some/file"; got != want { + if got, want := config.Path.procFilePath("some/file"), "/proc/some/file"; got != want { t.Errorf("Expected: %s, Got: %s", want, got) } } func TestCustomProcPath(t *testing.T) { - if _, err := kingpin.CommandLine.Parse([]string{"--path.procfs", "./../some/./place/"}); err != nil { - t.Fatal(err) - } + config := newNodeCollectorWithPaths() + path := "./../some/./place/" + config.Path.ProcPath = &path - if got, want := procFilePath("somefile"), "../some/place/somefile"; got != want { + if got, want := config.Path.procFilePath("somefile"), "../some/place/somefile"; got != want { t.Errorf("Expected: %s, Got: %s", want, got) } - if got, want := procFilePath("some/file"), "../some/place/some/file"; got != want { + if got, want := config.Path.procFilePath("some/file"), "../some/place/some/file"; got != want { t.Errorf("Expected: %s, Got: %s", want, got) } } func TestDefaultSysPath(t *testing.T) { - if _, err := kingpin.CommandLine.Parse([]string{"--path.sysfs", "/sys"}); err != nil { - t.Fatal(err) - } + config := newNodeCollectorWithPaths() + path := "/sys" + config.Path.SysPath = &path - if got, want := sysFilePath("somefile"), "/sys/somefile"; got != want { + if got, want := config.Path.sysFilePath("somefile"), "/sys/somefile"; got != want { t.Errorf("Expected: %s, Got: %s", want, got) } - if got, want := sysFilePath("some/file"), "/sys/some/file"; got != want { + if got, want := config.Path.sysFilePath("some/file"), "/sys/some/file"; got != want { t.Errorf("Expected: %s, Got: %s", want, got) } } func TestCustomSysPath(t *testing.T) { - if _, err := kingpin.CommandLine.Parse([]string{"--path.sysfs", "./../some/./place/"}); err != nil { - t.Fatal(err) - } + config := newNodeCollectorWithPaths() + path := "./../some/./place/" + config.Path.SysPath = &path - if got, want := sysFilePath("somefile"), "../some/place/somefile"; got != want { + if got, want := config.Path.sysFilePath("somefile"), "../some/place/somefile"; got != want { t.Errorf("Expected: %s, Got: %s", want, got) } - if got, want := sysFilePath("some/file"), "../some/place/some/file"; got != want { + if got, want := config.Path.sysFilePath("some/file"), "../some/place/some/file"; got != want { t.Errorf("Expected: %s, Got: %s", want, got) } } + +func newNodeCollectorWithPaths() *NodeCollectorConfig { + return &NodeCollectorConfig{Path: PathConfig{ + ProcPath: new(string), + SysPath: new(string), + RootfsPath: new(string), + UdevDataPath: new(string), + }} +} diff --git a/collector/perf_linux.go b/collector/perf_linux.go index 8934371ad0..bedc5a43d4 100644 --- a/collector/perf_linux.go +++ b/collector/perf_linux.go @@ -22,7 +22,6 @@ import ( "strconv" "strings" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/hodgesds/perf-utils" @@ -34,17 +33,6 @@ const ( perfSubsystem = "perf" ) -var ( - perfCPUsFlag = kingpin.Flag("collector.perf.cpus", "List of CPUs from which perf metrics should be collected").Default("").String() - perfTracepointFlag = kingpin.Flag("collector.perf.tracepoint", "perf tracepoint that should be collected").Strings() - perfNoHwProfiler = kingpin.Flag("collector.perf.disable-hardware-profilers", "disable perf hardware profilers").Default("false").Bool() - perfHwProfilerFlag = kingpin.Flag("collector.perf.hardware-profilers", "perf hardware profilers that should be collected").Strings() - perfNoSwProfiler = kingpin.Flag("collector.perf.disable-software-profilers", "disable perf software profilers").Default("false").Bool() - perfSwProfilerFlag = kingpin.Flag("collector.perf.software-profilers", "perf software profilers that should be collected").Strings() - perfNoCaProfiler = kingpin.Flag("collector.perf.disable-cache-profilers", "disable perf cache profilers").Default("false").Bool() - perfCaProfilerFlag = kingpin.Flag("collector.perf.cache-profilers", "perf cache profilers that should be collected").Strings() -) - func init() { registerCollector(perfSubsystem, defaultDisabled, NewPerfCollector) } @@ -301,7 +289,7 @@ func newPerfTracepointCollector( // NewPerfCollector returns a new perf based collector, it creates a profiler // per CPU. -func NewPerfCollector(logger log.Logger) (Collector, error) { +func NewPerfCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { collector := &perfCollector{ perfHwProfilers: map[int]*perf.HardwareProfiler{}, perfSwProfilers: map[int]*perf.SoftwareProfiler{}, @@ -316,8 +304,8 @@ func NewPerfCollector(logger log.Logger) (Collector, error) { cpus []int err error ) - if perfCPUsFlag != nil && *perfCPUsFlag != "" { - cpus, err = perfCPUFlagToCPUs(*perfCPUsFlag) + if config.Perf.CPUs != nil && *config.Perf.CPUs != "" { + cpus, err = perfCPUFlagToCPUs(*config.Perf.CPUs) if err != nil { return nil, err } @@ -329,8 +317,8 @@ func NewPerfCollector(logger log.Logger) (Collector, error) { } // First configure any tracepoints. - if *perfTracepointFlag != nil && len(*perfTracepointFlag) > 0 { - tracepointCollector, err := newPerfTracepointCollector(logger, *perfTracepointFlag, cpus) + if *config.Perf.Tracepoint != nil && len(*config.Perf.Tracepoint) > 0 { + tracepointCollector, err := newPerfTracepointCollector(logger, *config.Perf.Tracepoint, cpus) if err != nil { return nil, err } @@ -339,27 +327,27 @@ func NewPerfCollector(logger log.Logger) (Collector, error) { // Configure perf profilers hardwareProfilers := perf.AllHardwareProfilers - if *perfHwProfilerFlag != nil && len(*perfHwProfilerFlag) > 0 { + if *config.Perf.HwProfiler != nil && len(*config.Perf.HwProfiler) > 0 { // hardwareProfilers = 0 - for _, hf := range *perfHwProfilerFlag { + for _, hf := range *config.Perf.HwProfiler { if v, ok := perfHardwareProfilerMap[hf]; ok { hardwareProfilers |= v } } } softwareProfilers := perf.AllSoftwareProfilers - if *perfSwProfilerFlag != nil && len(*perfSwProfilerFlag) > 0 { + if *config.Perf.SwProfiler != nil && len(*config.Perf.SwProfiler) > 0 { // softwareProfilers = 0 - for _, sf := range *perfSwProfilerFlag { + for _, sf := range *config.Perf.SwProfiler { if v, ok := perfSoftwareProfilerMap[sf]; ok { softwareProfilers |= v } } } cacheProfilers := perf.L1DataReadHitProfiler | perf.L1DataReadMissProfiler | perf.L1DataWriteHitProfiler | perf.L1InstrReadMissProfiler | perf.InstrTLBReadHitProfiler | perf.InstrTLBReadMissProfiler | perf.LLReadHitProfiler | perf.LLReadMissProfiler | perf.LLWriteHitProfiler | perf.LLWriteMissProfiler | perf.BPUReadHitProfiler | perf.BPUReadMissProfiler - if *perfCaProfilerFlag != nil && len(*perfCaProfilerFlag) > 0 { + if *config.Perf.CaProfilerFlag != nil && len(*config.Perf.CaProfilerFlag) > 0 { cacheProfilers = 0 - for _, cf := range *perfCaProfilerFlag { + for _, cf := range *config.Perf.CaProfilerFlag { if v, ok := perfCacheProfilerMap[cf]; ok { cacheProfilers |= v } @@ -370,7 +358,7 @@ func NewPerfCollector(logger log.Logger) (Collector, error) { for _, cpu := range cpus { // Use -1 to profile all processes on the CPU, see: // man perf_event_open - if !*perfNoHwProfiler { + if !*config.Perf.NoHwProfiler { hwProf, err := perf.NewHardwareProfiler( -1, cpu, @@ -386,7 +374,7 @@ func NewPerfCollector(logger log.Logger) (Collector, error) { collector.hwProfilerCPUMap[&hwProf] = cpu } - if !*perfNoSwProfiler { + if !*config.Perf.NoSwProfiler { swProf, err := perf.NewSoftwareProfiler(-1, cpu, softwareProfilers) if err != nil && !swProf.HasProfilers() { return nil, err @@ -398,7 +386,7 @@ func NewPerfCollector(logger log.Logger) (Collector, error) { collector.swProfilerCPUMap[&swProf] = cpu } - if !*perfNoCaProfiler { + if !*config.Perf.NoCaProfiler { cacheProf, err := perf.NewCacheProfiler( -1, cpu, diff --git a/collector/perf_linux_test.go b/collector/perf_linux_test.go index fc557ffd32..9eef00b8d3 100644 --- a/collector/perf_linux_test.go +++ b/collector/perf_linux_test.go @@ -44,7 +44,7 @@ func canTestPerf(t *testing.T) { func TestPerfCollector(t *testing.T) { canTestPerf(t) - collector, err := NewPerfCollector(log.NewNopLogger()) + collector, err := NewPerfCollector(&NodeCollectorConfig{}, log.NewNopLogger()) if err != nil { t.Fatal(err) } @@ -64,6 +64,8 @@ func TestPerfCollector(t *testing.T) { } func TestPerfCollectorStride(t *testing.T) { + config := &NodeCollectorConfig{} + canTestPerf(t) tests := []struct { @@ -96,8 +98,8 @@ func TestPerfCollectorStride(t *testing.T) { t.Skipf("Skipping test because runtime.NumCPU < %d", cpu) } } - perfCPUsFlag = &test.flag - collector, err := NewPerfCollector(log.NewNopLogger()) + config.Perf.CPUs = &test.flag + collector, err := NewPerfCollector(config, log.NewNopLogger()) if err != nil { t.Fatal(err) } diff --git a/collector/powersupplyclass.go b/collector/powersupplyclass.go index 7f231dac47..89b3875141 100644 --- a/collector/powersupplyclass.go +++ b/collector/powersupplyclass.go @@ -20,32 +20,29 @@ package collector import ( "regexp" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" ) -var ( - powerSupplyClassIgnoredPowerSupplies = kingpin.Flag("collector.powersupply.ignored-supplies", "Regexp of power supplies to ignore for powersupplyclass collector.").Default("^$").String() -) - type powerSupplyClassCollector struct { subsystem string ignoredPattern *regexp.Regexp metricDescs map[string]*prometheus.Desc logger log.Logger + config *NodeCollectorConfig } func init() { registerCollector("powersupplyclass", defaultEnabled, NewPowerSupplyClassCollector) } -func NewPowerSupplyClassCollector(logger log.Logger) (Collector, error) { - pattern := regexp.MustCompile(*powerSupplyClassIgnoredPowerSupplies) +func NewPowerSupplyClassCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + pattern := regexp.MustCompile(*config.PowerSupplyClass.IgnoredPowerSupplies) return &powerSupplyClassCollector{ subsystem: "power_supply", ignoredPattern: pattern, metricDescs: map[string]*prometheus.Desc{}, logger: logger, + config: config, }, nil } diff --git a/collector/powersupplyclass_linux.go b/collector/powersupplyclass_linux.go index 86e81fb6a2..5fde7c086b 100644 --- a/collector/powersupplyclass_linux.go +++ b/collector/powersupplyclass_linux.go @@ -28,7 +28,7 @@ import ( ) func (c *powerSupplyClassCollector) Update(ch chan<- prometheus.Metric) error { - powerSupplyClass, err := getPowerSupplyClassInfo(c.ignoredPattern) + powerSupplyClass, err := getPowerSupplyClassInfo(c.config, c.ignoredPattern) if err != nil { if errors.Is(err, os.ErrNotExist) { return ErrNoData @@ -155,8 +155,8 @@ func pushPowerSupplyMetric(ch chan<- prometheus.Metric, subsystem string, name s ch <- prometheus.MustNewConstMetric(fieldDesc, valueType, value, powerSupplyName) } -func getPowerSupplyClassInfo(ignore *regexp.Regexp) (sysfs.PowerSupplyClass, error) { - fs, err := sysfs.NewFS(*sysPath) +func getPowerSupplyClassInfo(config *NodeCollectorConfig, ignore *regexp.Regexp) (sysfs.PowerSupplyClass, error) { + fs, err := sysfs.NewFS(*config.Path.SysPath) if err != nil { return nil, err } diff --git a/collector/pressure_linux.go b/collector/pressure_linux.go index ceaced7eef..22fb89f5e0 100644 --- a/collector/pressure_linux.go +++ b/collector/pressure_linux.go @@ -49,8 +49,8 @@ func init() { } // NewPressureStatsCollector returns a Collector exposing pressure stall information -func NewPressureStatsCollector(logger log.Logger) (Collector, error) { - fs, err := procfs.NewFS(*procPath) +func NewPressureStatsCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := procfs.NewFS(*config.Path.ProcPath) if err != nil { return nil, fmt.Errorf("failed to open procfs: %w", err) } diff --git a/collector/processes_linux.go b/collector/processes_linux.go index 798aeaeb30..0579812f3c 100644 --- a/collector/processes_linux.go +++ b/collector/processes_linux.go @@ -40,15 +40,16 @@ type processCollector struct { pidUsed *prometheus.Desc pidMax *prometheus.Desc logger log.Logger + config *NodeCollectorConfig } func init() { - registerCollector("processes", defaultDisabled, NewProcessStatCollector) + registerCollector("processes", defaultEnabled, NewProcessStatCollector) } // NewProcessStatCollector returns a new Collector exposing process data read from the proc filesystem. -func NewProcessStatCollector(logger log.Logger) (Collector, error) { - fs, err := procfs.NewFS(*procPath) +func NewProcessStatCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := procfs.NewFS(*config.Path.ProcPath) if err != nil { return nil, fmt.Errorf("failed to open procfs: %w", err) } @@ -82,6 +83,7 @@ func NewProcessStatCollector(logger log.Logger) (Collector, error) { "Number of max PIDs limit", nil, nil, ), logger: logger, + config: config, }, nil } func (c *processCollector) Update(ch chan<- prometheus.Metric) error { @@ -91,7 +93,7 @@ func (c *processCollector) Update(ch chan<- prometheus.Metric) error { } ch <- prometheus.MustNewConstMetric(c.threadAlloc, prometheus.GaugeValue, float64(threads)) - maxThreads, err := readUintFromFile(procFilePath("sys/kernel/threads-max")) + maxThreads, err := readUintFromFile(c.config.Path.procFilePath("sys/kernel/threads-max")) if err != nil { return fmt.Errorf("unable to retrieve limit number of threads: %w", err) } @@ -105,7 +107,7 @@ func (c *processCollector) Update(ch chan<- prometheus.Metric) error { ch <- prometheus.MustNewConstMetric(c.threadsState, prometheus.GaugeValue, float64(threadStates[state]), state) } - pidM, err := readUintFromFile(procFilePath("sys/kernel/pid_max")) + pidM, err := readUintFromFile(c.config.Path.procFilePath("sys/kernel/pid_max")) if err != nil { return fmt.Errorf("unable to retrieve limit number of maximum pids alloved: %w", err) } @@ -148,7 +150,7 @@ func (c *processCollector) getAllocatedThreads() (int, map[string]int32, int, ma } func (c *processCollector) getThreadStates(pid int, pidStat procfs.ProcStat, threadStates map[string]int32) error { - fs, err := procfs.NewFS(procFilePath(path.Join(strconv.Itoa(pid), "task"))) + fs, err := procfs.NewFS(c.config.Path.procFilePath(path.Join(strconv.Itoa(pid), "task"))) if err != nil { if c.isIgnoredError(err) { level.Debug(c.logger).Log("msg", "file not found when retrieving tasks for pid", "pid", pid, "err", err) diff --git a/collector/processes_linux_test.go b/collector/processes_linux_test.go index e2814a0104..e79859a6ea 100644 --- a/collector/processes_linux_test.go +++ b/collector/processes_linux_test.go @@ -19,21 +19,21 @@ package collector import ( "testing" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/prometheus/procfs" ) func TestReadProcessStatus(t *testing.T) { - if _, err := kingpin.CommandLine.Parse([]string{"--path.procfs", "fixtures/proc"}); err != nil { - t.Fatal(err) - } + path := "fixtures/proc" + config := newNodeCollectorWithPaths() + config.Path.ProcPath = &path + want := 1 - fs, err := procfs.NewFS(*procPath) + fs, err := procfs.NewFS(*config.Path.ProcPath) if err != nil { t.Errorf("failed to open procfs: %v", err) } - c := processCollector{fs: fs, logger: log.NewNopLogger()} + c := processCollector{fs: fs, logger: log.NewNopLogger(), config: config} pids, states, threads, _, err := c.getAllocatedThreads() if err != nil { t.Fatalf("Cannot retrieve data from procfs getAllocatedThreads function: %v ", err) @@ -45,7 +45,7 @@ func TestReadProcessStatus(t *testing.T) { t.Fatalf("Process states cannot be nil %v:", states) } - maxPid, err := readUintFromFile(procFilePath("sys/kernel/pid_max")) + maxPid, err := readUintFromFile(c.config.Path.procFilePath("sys/kernel/pid_max")) if err != nil { t.Fatalf("Unable to retrieve limit number of maximum pids alloved %v\n", err) } diff --git a/collector/qdisc_linux.go b/collector/qdisc_linux.go index 06ab6a88d6..fb5217eceb 100644 --- a/collector/qdisc_linux.go +++ b/collector/qdisc_linux.go @@ -22,7 +22,6 @@ import ( "os" "path/filepath" - "github.com/alecthomas/kingpin/v2" "github.com/ema/qdisc" "github.com/go-kit/log" "github.com/go-kit/log/level" @@ -39,41 +38,34 @@ type qdiscStatCollector struct { overlimits typedDesc qlength typedDesc backlog typedDesc + config *NodeCollectorConfig } -var ( - collectorQdisc = kingpin.Flag("collector.qdisc.fixtures", "test fixtures to use for qdisc collector end-to-end testing").Default("").String() - collectorQdiscDeviceInclude = kingpin.Flag("collector.qdisc.device-include", "Regexp of qdisc devices to include (mutually exclusive to device-exclude).").String() - oldCollectorQdiskDeviceInclude = kingpin.Flag("collector.qdisk.device-include", "DEPRECATED: Use collector.qdisc.device-include").Hidden().String() - collectorQdiscDeviceExclude = kingpin.Flag("collector.qdisc.device-exclude", "Regexp of qdisc devices to exclude (mutually exclusive to device-include).").String() - oldCollectorQdiskDeviceExclude = kingpin.Flag("collector.qdisk.device-exclude", "DEPRECATED: Use collector.qdisc.device-exclude").Hidden().String() -) - func init() { registerCollector("qdisc", defaultDisabled, NewQdiscStatCollector) } // NewQdiscStatCollector returns a new Collector exposing queuing discipline statistics. -func NewQdiscStatCollector(logger log.Logger) (Collector, error) { - if *oldCollectorQdiskDeviceInclude != "" { - if *collectorQdiscDeviceInclude == "" { +func NewQdiscStatCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + if *config.Qdisc.OldDeviceInclude != "" { + if *config.Qdisc.DeviceInclude == "" { level.Warn(logger).Log("msg", "--collector.qdisk.device-include is DEPRECATED and will be removed in 2.0.0, use --collector.qdisc.device-include") - *collectorQdiscDeviceInclude = *oldCollectorQdiskDeviceInclude + *config.Qdisc.DeviceInclude = *config.Qdisc.OldDeviceInclude } else { return nil, fmt.Errorf("--collector.qdisk.device-include and --collector.qdisc.device-include are mutually exclusive") } } - if *oldCollectorQdiskDeviceExclude != "" { - if *collectorQdiscDeviceExclude == "" { + if *config.Qdisc.OldDeviceExclude != "" { + if *config.Qdisc.DeviceExclude == "" { level.Warn(logger).Log("msg", "--collector.qdisk.device-exclude is DEPRECATED and will be removed in 2.0.0, use --collector.qdisc.device-exclude") - *collectorQdiscDeviceExclude = *oldCollectorQdiskDeviceExclude + *config.Qdisc.DeviceExclude = *config.Qdisc.OldDeviceExclude } else { return nil, fmt.Errorf("--collector.qdisk.device-exclude and --collector.qdisc.device-exclude are mutually exclusive") } } - if *collectorQdiscDeviceExclude != "" && *collectorQdiscDeviceInclude != "" { + if *config.Qdisc.DeviceInclude != "" && *config.Qdisc.DeviceExclude != "" { return nil, fmt.Errorf("collector.qdisc.device-include and collector.qdisc.device-exclude are mutaly exclusive") } @@ -114,7 +106,8 @@ func NewQdiscStatCollector(logger log.Logger) (Collector, error) { []string{"device", "kind"}, nil, ), prometheus.GaugeValue}, logger: logger, - deviceFilter: newDeviceFilter(*collectorQdiscDeviceExclude, *collectorQdiscDeviceInclude), + deviceFilter: newDeviceFilter(*config.Qdisc.OldDeviceExclude, *config.Qdisc.DeviceInclude), + config: config, }, nil } @@ -134,7 +127,7 @@ func (c *qdiscStatCollector) Update(ch chan<- prometheus.Metric) error { var msgs []qdisc.QdiscInfo var err error - fixtures := *collectorQdisc + fixtures := *c.config.Qdisc.Fixtures if fixtures == "" { msgs, err = qdisc.Get() diff --git a/collector/rapl_linux.go b/collector/rapl_linux.go index 642de6c146..94a0ba0530 100644 --- a/collector/rapl_linux.go +++ b/collector/rapl_linux.go @@ -22,7 +22,6 @@ import ( "os" "strconv" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" @@ -36,19 +35,16 @@ type raplCollector struct { logger log.Logger joulesMetricDesc *prometheus.Desc + config *NodeCollectorConfig } func init() { registerCollector(raplCollectorSubsystem, defaultEnabled, NewRaplCollector) } -var ( - raplZoneLabel = kingpin.Flag("collector.rapl.enable-zone-label", "Enables service unit metric unit_start_time_seconds").Bool() -) - // NewRaplCollector returns a new Collector exposing RAPL metrics. -func NewRaplCollector(logger log.Logger) (Collector, error) { - fs, err := sysfs.NewFS(*sysPath) +func NewRaplCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := sysfs.NewFS(*config.Path.SysPath) if err != nil { return nil, err @@ -64,6 +60,7 @@ func NewRaplCollector(logger log.Logger) (Collector, error) { fs: fs, logger: logger, joulesMetricDesc: joulesMetricDesc, + config: config, } return &collector, nil } @@ -96,7 +93,7 @@ func (c *raplCollector) Update(ch chan<- prometheus.Metric) error { joules := float64(microJoules) / 1000000.0 - if *raplZoneLabel { + if *c.config.Rapl.ZoneLabel { ch <- c.joulesMetricWithZoneLabel(rz, joules) } else { ch <- c.joulesMetric(rz, joules) diff --git a/collector/runit.go b/collector/runit.go index 3cae657c33..73b406540c 100644 --- a/collector/runit.go +++ b/collector/runit.go @@ -17,21 +17,19 @@ package collector import ( - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/go-runit/runit" "github.com/prometheus/client_golang/prometheus" ) -var runitServiceDir = kingpin.Flag("collector.runit.servicedir", "Path to runit service directory.").Default("/etc/service").String() - type runitCollector struct { state typedDesc stateDesired typedDesc stateNormal typedDesc stateTimestamp typedDesc logger log.Logger + config *NodeCollectorConfig } func init() { @@ -39,7 +37,7 @@ func init() { } // NewRunitCollector returns a new Collector exposing runit statistics. -func NewRunitCollector(logger log.Logger) (Collector, error) { +func NewRunitCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { var ( subsystem = "service" constLabels = prometheus.Labels{"supervisor": "runit"} @@ -70,11 +68,12 @@ func NewRunitCollector(logger log.Logger) (Collector, error) { labelNames, constLabels, ), prometheus.GaugeValue}, logger: logger, + config: config, }, nil } func (c *runitCollector) Update(ch chan<- prometheus.Metric) error { - services, err := runit.GetServices(*runitServiceDir) + services, err := runit.GetServices(*c.config.Runit.ServiceDir) if err != nil { return err } diff --git a/collector/schedstat_linux.go b/collector/schedstat_linux.go index e5016561da..d6d5b8b938 100644 --- a/collector/schedstat_linux.go +++ b/collector/schedstat_linux.go @@ -53,8 +53,8 @@ var ( ) // NewSchedstatCollector returns a new Collector exposing task scheduler statistics -func NewSchedstatCollector(logger log.Logger) (Collector, error) { - fs, err := procfs.NewFS(*procPath) +func NewSchedstatCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := procfs.NewFS(*config.Path.ProcPath) if err != nil { return nil, fmt.Errorf("failed to open procfs: %w", err) } diff --git a/collector/selinux_linux.go b/collector/selinux_linux.go index 79316362fe..ee88590211 100644 --- a/collector/selinux_linux.go +++ b/collector/selinux_linux.go @@ -34,7 +34,7 @@ func init() { } // NewSelinuxCollector returns a new Collector exposing SELinux statistics. -func NewSelinuxCollector(logger log.Logger) (Collector, error) { +func NewSelinuxCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { const subsystem = "selinux" return &selinuxCollector{ diff --git a/collector/slabinfo_linux.go b/collector/slabinfo_linux.go index a3c3ebced7..23aa74b3ef 100644 --- a/collector/slabinfo_linux.go +++ b/collector/slabinfo_linux.go @@ -35,8 +35,8 @@ func init() { registerCollector("slabinfo", defaultDisabled, NewSlabinfoCollector) } -func NewSlabinfoCollector(logger log.Logger) (Collector, error) { - fs, err := procfs.NewFS(*procPath) +func NewSlabinfoCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := procfs.NewFS(*config.Path.ProcPath) if err != nil { return nil, fmt.Errorf("failed to open procfs: %w", err) } diff --git a/collector/sockstat_linux.go b/collector/sockstat_linux.go index 480c83b1da..b045c63ac1 100644 --- a/collector/sockstat_linux.go +++ b/collector/sockstat_linux.go @@ -36,6 +36,7 @@ var pageSize = os.Getpagesize() type sockStatCollector struct { logger log.Logger + config *NodeCollectorConfig } func init() { @@ -43,12 +44,12 @@ func init() { } // NewSockStatCollector returns a new Collector exposing socket stats. -func NewSockStatCollector(logger log.Logger) (Collector, error) { - return &sockStatCollector{logger}, nil +func NewSockStatCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + return &sockStatCollector{logger, config}, nil } func (c *sockStatCollector) Update(ch chan<- prometheus.Metric) error { - fs, err := procfs.NewFS(*procPath) + fs, err := procfs.NewFS(*c.config.Path.ProcPath) if err != nil { return fmt.Errorf("failed to open procfs: %w", err) } diff --git a/collector/softirqs_common.go b/collector/softirqs_common.go index 08ef780f26..29fbf91e46 100644 --- a/collector/softirqs_common.go +++ b/collector/softirqs_common.go @@ -18,6 +18,7 @@ package collector import ( "fmt" + "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/procfs" @@ -34,14 +35,14 @@ func init() { } // NewSoftirqsCollector returns a new Collector exposing softirq stats. -func NewSoftirqsCollector(logger log.Logger) (Collector, error) { +func NewSoftirqsCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { desc := typedDesc{prometheus.NewDesc( namespace+"_softirqs_functions_total", "Softirq counts per CPU.", softirqLabelNames, nil, ), prometheus.CounterValue} - fs, err := procfs.NewFS(*procPath) + fs, err := procfs.NewFS(*config.Path.ProcPath) if err != nil { return nil, fmt.Errorf("failed to open procfs: %w", err) } diff --git a/collector/softnet_linux.go b/collector/softnet_linux.go index 42d47780e3..af3ec1030e 100644 --- a/collector/softnet_linux.go +++ b/collector/softnet_linux.go @@ -46,8 +46,8 @@ func init() { } // NewSoftnetCollector returns a new Collector exposing softnet metrics. -func NewSoftnetCollector(logger log.Logger) (Collector, error) { - fs, err := procfs.NewFS(*procPath) +func NewSoftnetCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := procfs.NewFS(*config.Path.ProcPath) if err != nil { return nil, fmt.Errorf("failed to open procfs: %w", err) } diff --git a/collector/stat_linux.go b/collector/stat_linux.go index 9974ae7aa7..01393387e2 100644 --- a/collector/stat_linux.go +++ b/collector/stat_linux.go @@ -19,7 +19,6 @@ package collector import ( "fmt" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/procfs" @@ -35,17 +34,16 @@ type statCollector struct { procsBlocked *prometheus.Desc softIRQ *prometheus.Desc logger log.Logger + config *NodeCollectorConfig } -var statSoftirqFlag = kingpin.Flag("collector.stat.softirq", "Export softirq calls per vector").Default("false").Bool() - func init() { registerCollector("stat", defaultEnabled, NewStatCollector) } // NewStatCollector returns a new Collector exposing kernel/system statistics. -func NewStatCollector(logger log.Logger) (Collector, error) { - fs, err := procfs.NewFS(*procPath) +func NewStatCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := procfs.NewFS(*config.Path.ProcPath) if err != nil { return nil, fmt.Errorf("failed to open procfs: %w", err) } @@ -87,6 +85,7 @@ func NewStatCollector(logger log.Logger) (Collector, error) { []string{"vector"}, nil, ), logger: logger, + config: config, }, nil } @@ -106,7 +105,7 @@ func (c *statCollector) Update(ch chan<- prometheus.Metric) error { ch <- prometheus.MustNewConstMetric(c.procsRunning, prometheus.GaugeValue, float64(stats.ProcessesRunning)) ch <- prometheus.MustNewConstMetric(c.procsBlocked, prometheus.GaugeValue, float64(stats.ProcessesBlocked)) - if *statSoftirqFlag { + if *c.config.Stat.Softirq { si := stats.SoftIRQ for _, vec := range []struct { diff --git a/collector/supervisord.go b/collector/supervisord.go index 9b517f0a42..57ac5b8f90 100644 --- a/collector/supervisord.go +++ b/collector/supervisord.go @@ -24,7 +24,6 @@ import ( "net/url" "time" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/mattn/go-xmlrpc" @@ -32,8 +31,7 @@ import ( ) var ( - supervisordURL = kingpin.Flag("collector.supervisord.url", "XML RPC endpoint.").Default("http://localhost:9001/RPC2").Envar("SUPERVISORD_URL").String() - xrpc *xmlrpc.Client + xrpc *xmlrpc.Client ) type supervisordCollector struct { @@ -49,13 +47,13 @@ func init() { } // NewSupervisordCollector returns a new Collector exposing supervisord statistics. -func NewSupervisordCollector(logger log.Logger) (Collector, error) { +func NewSupervisordCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { var ( subsystem = "supervisord" labelNames = []string{"name", "group"} ) - if u, err := url.Parse(*supervisordURL); err == nil && u.Scheme == "unix" { + if u, err := url.Parse(*config.Supervisord.URL); err == nil && u.Scheme == "unix" { // Fake the URI scheme as http, since net/http.*Transport.roundTrip will complain // about a non-http(s) transport. xrpc = xmlrpc.NewClient("http://unix/RPC2") @@ -66,7 +64,7 @@ func NewSupervisordCollector(logger log.Logger) (Collector, error) { }, } } else { - xrpc = xmlrpc.NewClient(*supervisordURL) + xrpc = xmlrpc.NewClient(*config.Supervisord.URL) } level.Warn(logger).Log("msg", "This collector is deprecated and will be removed in the next major version release.") diff --git a/collector/sysctl_linux.go b/collector/sysctl_linux.go index c14341db85..63c1307dc6 100644 --- a/collector/sysctl_linux.go +++ b/collector/sysctl_linux.go @@ -18,16 +18,12 @@ import ( "strconv" "strings" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/procfs" ) var ( - sysctlInclude = kingpin.Flag("collector.sysctl.include", "Select sysctl metrics to include").Strings() - sysctlIncludeInfo = kingpin.Flag("collector.sysctl.include-info", "Select sysctl metrics to include as info metrics").Strings() - sysctlInfoDesc = prometheus.NewDesc(prometheus.BuildFQName(namespace, "sysctl", "info"), "sysctl info", []string{"name", "value", "index"}, nil) ) @@ -41,8 +37,8 @@ func init() { registerCollector("sysctl", defaultDisabled, NewSysctlCollector) } -func NewSysctlCollector(logger log.Logger) (Collector, error) { - fs, err := procfs.NewFS(*procPath) +func NewSysctlCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := procfs.NewFS(*config.Path.ProcPath) if err != nil { return nil, fmt.Errorf("failed to open sysfs: %w", err) } @@ -52,7 +48,7 @@ func NewSysctlCollector(logger log.Logger) (Collector, error) { sysctls: []*sysctl{}, } - for _, include := range *sysctlInclude { + for _, include := range *config.Sysctl.Include { sysctl, err := newSysctl(include, true) if err != nil { return nil, err @@ -60,7 +56,7 @@ func NewSysctlCollector(logger log.Logger) (Collector, error) { c.sysctls = append(c.sysctls, sysctl) } - for _, include := range *sysctlIncludeInfo { + for _, include := range *config.Sysctl.IncludeInfo { sysctl, err := newSysctl(include, false) if err != nil { return nil, err diff --git a/collector/systemd_linux.go b/collector/systemd_linux.go index 3323251114..dd7bf40613 100644 --- a/collector/systemd_linux.go +++ b/collector/systemd_linux.go @@ -27,7 +27,6 @@ import ( "sync" "time" - "github.com/alecthomas/kingpin/v2" "github.com/coreos/go-systemd/v22/dbus" "github.com/go-kit/log" "github.com/go-kit/log/level" @@ -42,23 +41,6 @@ const ( ) var ( - systemdUnitIncludeSet bool - systemdUnitInclude = kingpin.Flag("collector.systemd.unit-include", "Regexp of systemd units to include. Units must both match include and not match exclude to be included.").Default(".+").PreAction(func(c *kingpin.ParseContext) error { - systemdUnitIncludeSet = true - return nil - }).String() - oldSystemdUnitInclude = kingpin.Flag("collector.systemd.unit-whitelist", "DEPRECATED: Use --collector.systemd.unit-include").Hidden().String() - systemdUnitExcludeSet bool - systemdUnitExclude = kingpin.Flag("collector.systemd.unit-exclude", "Regexp of systemd units to exclude. Units must both match include and not match exclude to be included.").Default(".+\\.(automount|device|mount|scope|slice)").PreAction(func(c *kingpin.ParseContext) error { - systemdUnitExcludeSet = true - return nil - }).String() - oldSystemdUnitExclude = kingpin.Flag("collector.systemd.unit-blacklist", "DEPRECATED: Use collector.systemd.unit-exclude").Hidden().String() - systemdPrivate = kingpin.Flag("collector.systemd.private", "Establish a private, direct connection to systemd without dbus (Strongly discouraged since it requires root. For testing purposes only).").Hidden().Bool() - enableTaskMetrics = kingpin.Flag("collector.systemd.enable-task-metrics", "Enables service unit tasks metrics unit_tasks_current and unit_tasks_max").Bool() - enableRestartsMetrics = kingpin.Flag("collector.systemd.enable-restarts-metrics", "Enables service unit metric service_restart_total").Bool() - enableStartTimeMetrics = kingpin.Flag("collector.systemd.enable-start-time-metrics", "Enables service unit metric unit_start_time_seconds").Bool() - systemdVersionRE = regexp.MustCompile(`[0-9]{3,}(\.[0-9]+)?`) ) @@ -79,6 +61,7 @@ type systemdCollector struct { systemdUnitIncludePattern *regexp.Regexp systemdUnitExcludePattern *regexp.Regexp logger log.Logger + config *NodeCollectorConfig } var unitStatesName = []string{"active", "activating", "deactivating", "inactive", "failed"} @@ -88,7 +71,7 @@ func init() { } // NewSystemdCollector returns a new Collector exposing systemd statistics. -func NewSystemdCollector(logger log.Logger) (Collector, error) { +func NewSystemdCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { const subsystem = "systemd" unitDesc := prometheus.NewDesc( @@ -134,26 +117,26 @@ func NewSystemdCollector(logger log.Logger) (Collector, error) { prometheus.BuildFQName(namespace, subsystem, "version"), "Detected systemd version", []string{"version"}, nil) - if *oldSystemdUnitExclude != "" { - if !systemdUnitExcludeSet { + if *config.Systemd.OldUnitExclude != "" { + if !config.Systemd.UnitExcludeSet { level.Warn(logger).Log("msg", "--collector.systemd.unit-blacklist is DEPRECATED and will be removed in 2.0.0, use --collector.systemd.unit-exclude") - *systemdUnitExclude = *oldSystemdUnitExclude + *config.Systemd.UnitExclude = *config.Systemd.OldUnitExclude } else { return nil, errors.New("--collector.systemd.unit-blacklist and --collector.systemd.unit-exclude are mutually exclusive") } } - if *oldSystemdUnitInclude != "" { - if !systemdUnitIncludeSet { + if *config.Systemd.OldUnitInclude != "" { + if !config.Systemd.UnitIncludeSet { level.Warn(logger).Log("msg", "--collector.systemd.unit-whitelist is DEPRECATED and will be removed in 2.0.0, use --collector.systemd.unit-include") - *systemdUnitInclude = *oldSystemdUnitInclude + *config.Systemd.UnitInclude = *config.Systemd.OldUnitInclude } else { return nil, errors.New("--collector.systemd.unit-whitelist and --collector.systemd.unit-include are mutually exclusive") } } - level.Info(logger).Log("msg", "Parsed flag --collector.systemd.unit-include", "flag", *systemdUnitInclude) - systemdUnitIncludePattern := regexp.MustCompile(fmt.Sprintf("^(?:%s)$", *systemdUnitInclude)) - level.Info(logger).Log("msg", "Parsed flag --collector.systemd.unit-exclude", "flag", *systemdUnitExclude) - systemdUnitExcludePattern := regexp.MustCompile(fmt.Sprintf("^(?:%s)$", *systemdUnitExclude)) + level.Info(logger).Log("msg", "Parsed flag --collector.systemd.unit-include", "flag", *config.Systemd.UnitInclude) + systemdUnitIncludePattern := regexp.MustCompile(fmt.Sprintf("^(?:%s)$", *config.Systemd.UnitInclude)) + level.Info(logger).Log("msg", "Parsed flag --collector.systemd.unit-exclude", "flag", *config.Systemd.UnitExclude) + systemdUnitExcludePattern := regexp.MustCompile(fmt.Sprintf("^(?:%s)$", *config.Systemd.UnitExclude)) return &systemdCollector{ unitDesc: unitDesc, @@ -171,6 +154,7 @@ func NewSystemdCollector(logger log.Logger) (Collector, error) { systemdUnitIncludePattern: systemdUnitIncludePattern, systemdUnitExcludePattern: systemdUnitExcludePattern, logger: logger, + config: config, }, nil } @@ -178,7 +162,7 @@ func NewSystemdCollector(logger log.Logger) (Collector, error) { // to reduce wait time for responses. func (c *systemdCollector) Update(ch chan<- prometheus.Metric) error { begin := time.Now() - conn, err := newSystemdDbusConn() + conn, err := newSystemdDbusConn(c.config.Systemd.Private) if err != nil { return fmt.Errorf("couldn't get dbus connection: %w", err) } @@ -221,7 +205,7 @@ func (c *systemdCollector) Update(ch chan<- prometheus.Metric) error { level.Debug(c.logger).Log("msg", "collectUnitStatusMetrics took", "duration_seconds", time.Since(begin).Seconds()) }() - if *enableStartTimeMetrics { + if *c.config.Systemd.EnableStartTimeMetrics { wg.Add(1) go func() { defer wg.Done() @@ -231,7 +215,7 @@ func (c *systemdCollector) Update(ch chan<- prometheus.Metric) error { }() } - if *enableTaskMetrics { + if *c.config.Systemd.EnableTaskMetrics { wg.Add(1) go func() { defer wg.Done() @@ -295,7 +279,7 @@ func (c *systemdCollector) collectUnitStatusMetrics(conn *dbus.Conn, ch chan<- p c.unitDesc, prometheus.GaugeValue, isActive, unit.Name, stateName, serviceType) } - if *enableRestartsMetrics && strings.HasSuffix(unit.Name, ".service") { + if *c.config.Systemd.EnableRestartsMetrics && strings.HasSuffix(unit.Name, ".service") { // NRestarts wasn't added until systemd 235. restartsCount, err := conn.GetUnitTypePropertyContext(context.TODO(), unit.Name, "Service", "NRestarts") if err != nil { @@ -434,7 +418,7 @@ func (c *systemdCollector) collectSystemState(conn *dbus.Conn, ch chan<- prometh return nil } -func newSystemdDbusConn() (*dbus.Conn, error) { +func newSystemdDbusConn(systemdPrivate *bool) (*dbus.Conn, error) { if *systemdPrivate { return dbus.NewSystemdConnectionContext(context.TODO()) } diff --git a/collector/systemd_linux_test.go b/collector/systemd_linux_test.go index d4e300d1d2..c5b12cac8e 100644 --- a/collector/systemd_linux_test.go +++ b/collector/systemd_linux_test.go @@ -103,7 +103,15 @@ func TestSystemdIgnoreFilter(t *testing.T) { } func TestSystemdIgnoreFilterDefaultKeepsAll(t *testing.T) { logger := log.NewNopLogger() - c, err := NewSystemdCollector(logger) + defaultInclude := ".+" + defaultExclude := ".+\\.(automount|device|mount|scope|slice)" + config := &NodeCollectorConfig{Systemd: SystemdConfig{ + UnitInclude: &defaultInclude, + UnitExclude: &defaultExclude, + OldUnitInclude: new(string), + OldUnitExclude: new(string), + }} + c, err := NewSystemdCollector(config, logger) if err != nil { t.Fatal(err) } diff --git a/collector/tapestats_linux.go b/collector/tapestats_linux.go index 264c2210f1..d7088d8408 100644 --- a/collector/tapestats_linux.go +++ b/collector/tapestats_linux.go @@ -21,17 +21,12 @@ import ( "os" "regexp" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/procfs/sysfs" ) -var ( - ignoredTapeDevices = kingpin.Flag("collector.tapestats.ignored-devices", "Regexp of devices to ignore for tapestats.").Default("^$").String() -) - type tapestatsCollector struct { ignoredDevicesPattern *regexp.Regexp ioNow *prometheus.Desc @@ -54,10 +49,10 @@ func init() { // NewTapestatsCollector returns a new Collector exposing tape device stats. // Docs from https://www.kernel.org/doc/html/latest/scsi/st.html#sysfs-and-statistics-for-tape-devices -func NewTapestatsCollector(logger log.Logger) (Collector, error) { +func NewTapestatsCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { var tapeLabelNames = []string{"device"} - fs, err := sysfs.NewFS(*sysPath) + fs, err := sysfs.NewFS(*config.Path.SysPath) if err != nil { return nil, fmt.Errorf("failed to open sysfs: %w", err) } @@ -65,7 +60,7 @@ func NewTapestatsCollector(logger log.Logger) (Collector, error) { tapeSubsystem := "tape" return &tapestatsCollector{ - ignoredDevicesPattern: regexp.MustCompile(*ignoredTapeDevices), + ignoredDevicesPattern: regexp.MustCompile(*config.Tapestats.IgnoredDevices), ioNow: prometheus.NewDesc( prometheus.BuildFQName(namespace, tapeSubsystem, "io_now"), diff --git a/collector/tcpstat_linux.go b/collector/tcpstat_linux.go index 99e33bc6a3..d8fbc6d70b 100644 --- a/collector/tcpstat_linux.go +++ b/collector/tcpstat_linux.go @@ -61,6 +61,7 @@ const ( type tcpStatCollector struct { desc typedDesc logger log.Logger + config *NodeCollectorConfig } func init() { @@ -68,7 +69,7 @@ func init() { } // NewTCPStatCollector returns a new Collector exposing network stats. -func NewTCPStatCollector(logger log.Logger) (Collector, error) { +func NewTCPStatCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &tcpStatCollector{ desc: typedDesc{prometheus.NewDesc( prometheus.BuildFQName(namespace, "tcp", "connection_states"), @@ -76,6 +77,7 @@ func NewTCPStatCollector(logger log.Logger) (Collector, error) { []string{"state"}, nil, ), prometheus.GaugeValue}, logger: logger, + config: config, }, nil } @@ -135,7 +137,7 @@ func (c *tcpStatCollector) Update(ch chan<- prometheus.Metric) error { } // if enabled ipv6 system - if _, hasIPv6 := os.Stat(procFilePath("net/tcp6")); hasIPv6 == nil { + if _, hasIPv6 := os.Stat(c.config.Path.procFilePath("net/tcp6")); hasIPv6 == nil { tcp6Stats, err := getTCPStats(syscall.AF_INET6) if err != nil { return fmt.Errorf("couldn't get tcp6stats: %w", err) diff --git a/collector/textfile.go b/collector/textfile.go index 48133f7c98..f60fff8771 100644 --- a/collector/textfile.go +++ b/collector/textfile.go @@ -24,7 +24,6 @@ import ( "strings" "time" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" @@ -33,8 +32,7 @@ import ( ) var ( - textFileDirectory = kingpin.Flag("collector.textfile.directory", "Directory to read text files with metrics from.").Default("").String() - mtimeDesc = prometheus.NewDesc( + mtimeDesc = prometheus.NewDesc( "node_textfile_mtime_seconds", "Unixtime mtime of textfiles successfully read.", []string{"file"}, @@ -55,9 +53,9 @@ func init() { // NewTextFileCollector returns a new Collector exposing metrics read from files // in the given textfile directory. -func NewTextFileCollector(logger log.Logger) (Collector, error) { +func NewTextFileCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { c := &textFileCollector{ - path: *textFileDirectory, + path: *config.TextFile.Directory, logger: logger, } return c, nil diff --git a/collector/thermal_darwin.go b/collector/thermal_darwin.go index 25673dcc4d..71835e0f26 100644 --- a/collector/thermal_darwin.go +++ b/collector/thermal_darwin.go @@ -67,7 +67,7 @@ func init() { } // NewThermCollector returns a new Collector exposing current CPU power levels. -func NewThermCollector(logger log.Logger) (Collector, error) { +func NewThermCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &thermCollector{ cpuSchedulerLimit: typedDesc{ desc: prometheus.NewDesc( diff --git a/collector/thermal_zone_linux.go b/collector/thermal_zone_linux.go index 6eff27321a..748a823a78 100644 --- a/collector/thermal_zone_linux.go +++ b/collector/thermal_zone_linux.go @@ -43,8 +43,8 @@ func init() { } // NewThermalZoneCollector returns a new Collector exposing kernel/system statistics. -func NewThermalZoneCollector(logger log.Logger) (Collector, error) { - fs, err := sysfs.NewFS(*sysPath) +func NewThermalZoneCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := sysfs.NewFS(*config.Path.SysPath) if err != nil { return nil, fmt.Errorf("failed to open sysfs: %w", err) } diff --git a/collector/time.go b/collector/time.go index 31a6e74e24..63d5868dc5 100644 --- a/collector/time.go +++ b/collector/time.go @@ -30,6 +30,7 @@ type timeCollector struct { clocksourcesAvailable typedDesc clocksourceCurrent typedDesc logger log.Logger + config *NodeCollectorConfig } func init() { @@ -38,7 +39,7 @@ func init() { // NewTimeCollector returns a new Collector exposing the current system time in // seconds since epoch. -func NewTimeCollector(logger log.Logger) (Collector, error) { +func NewTimeCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { const subsystem = "time" return &timeCollector{ now: typedDesc{prometheus.NewDesc( @@ -62,6 +63,7 @@ func NewTimeCollector(logger log.Logger) (Collector, error) { []string{"device", "clocksource"}, nil, ), prometheus.GaugeValue}, logger: logger, + config: config, }, nil } diff --git a/collector/time_linux.go b/collector/time_linux.go index dd4afe7592..760cf8fd5a 100644 --- a/collector/time_linux.go +++ b/collector/time_linux.go @@ -26,7 +26,7 @@ import ( ) func (c *timeCollector) update(ch chan<- prometheus.Metric) error { - fs, err := sysfs.NewFS(*sysPath) + fs, err := sysfs.NewFS(*c.config.Path.SysPath) if err != nil { return fmt.Errorf("failed to open procfs: %w", err) } diff --git a/collector/timex.go b/collector/timex.go index c444d3ea14..f4d03d2389 100644 --- a/collector/timex.go +++ b/collector/timex.go @@ -66,7 +66,7 @@ func init() { } // NewTimexCollector returns a new Collector exposing adjtime(3) stats. -func NewTimexCollector(logger log.Logger) (Collector, error) { +func NewTimexCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { const subsystem = "timex" return &timexCollector{ diff --git a/collector/udp_queues_linux.go b/collector/udp_queues_linux.go index 3fac869198..1ea8c39cb2 100644 --- a/collector/udp_queues_linux.go +++ b/collector/udp_queues_linux.go @@ -40,8 +40,8 @@ func init() { } // NewUDPqueuesCollector returns a new Collector exposing network udp queued bytes. -func NewUDPqueuesCollector(logger log.Logger) (Collector, error) { - fs, err := procfs.NewFS(*procPath) +func NewUDPqueuesCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := procfs.NewFS(*config.Path.ProcPath) if err != nil { return nil, fmt.Errorf("failed to open procfs: %w", err) } diff --git a/collector/uname.go b/collector/uname.go index 76e66b7e33..ba28b4d38d 100644 --- a/collector/uname.go +++ b/collector/uname.go @@ -53,7 +53,7 @@ func init() { } // NewUnameCollector returns new unameCollector. -func newUnameCollector(logger log.Logger) (Collector, error) { +func newUnameCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &unameCollector{logger}, nil } diff --git a/collector/vmstat_linux.go b/collector/vmstat_linux.go index cde2df5da5..134362ced9 100644 --- a/collector/vmstat_linux.go +++ b/collector/vmstat_linux.go @@ -24,7 +24,6 @@ import ( "strconv" "strings" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" ) @@ -33,30 +32,28 @@ const ( vmStatSubsystem = "vmstat" ) -var ( - vmStatFields = kingpin.Flag("collector.vmstat.fields", "Regexp of fields to return for vmstat collector.").Default("^(oom_kill|pgpg|pswp|pg.*fault).*").String() -) - type vmStatCollector struct { fieldPattern *regexp.Regexp logger log.Logger + config *NodeCollectorConfig } func init() { - registerCollector("vmstat", defaultEnabled, NewvmStatCollector) + registerCollector(vmStatSubsystem, defaultEnabled, NewvmStatCollector) } // NewvmStatCollector returns a new Collector exposing vmstat stats. -func NewvmStatCollector(logger log.Logger) (Collector, error) { - pattern := regexp.MustCompile(*vmStatFields) +func NewvmStatCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + pattern := regexp.MustCompile(*config.VmStat.Fields) return &vmStatCollector{ fieldPattern: pattern, logger: logger, + config: config, }, nil } func (c *vmStatCollector) Update(ch chan<- prometheus.Metric) error { - file, err := os.Open(procFilePath("vmstat")) + file, err := os.Open(c.config.Path.procFilePath("vmstat")) if err != nil { return err } diff --git a/collector/wifi_linux.go b/collector/wifi_linux.go index aff8eb2d36..85cdab17cf 100644 --- a/collector/wifi_linux.go +++ b/collector/wifi_linux.go @@ -23,7 +23,6 @@ import ( "os" "path/filepath" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/mdlayher/wifi" @@ -46,12 +45,9 @@ type wifiCollector struct { stationBeaconLossTotal *prometheus.Desc logger log.Logger + config *NodeCollectorConfig } -var ( - collectorWifi = kingpin.Flag("collector.wifi.fixtures", "test fixtures to use for wifi collector metrics").Default("").String() -) - func init() { registerCollector("wifi", defaultDisabled, NewWifiCollector) } @@ -67,7 +63,7 @@ type wifiStater interface { } // NewWifiCollector returns a new Collector exposing Wifi statistics. -func NewWifiCollector(logger log.Logger) (Collector, error) { +func NewWifiCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { const ( subsystem = "wifi" ) @@ -161,11 +157,12 @@ func NewWifiCollector(logger log.Logger) (Collector, error) { nil, ), logger: logger, + config: config, }, nil } func (c *wifiCollector) Update(ch chan<- prometheus.Metric) error { - stat, err := newWifiStater(*collectorWifi) + stat, err := newWifiStater(*c.config.Wifi.Fixtures) if err != nil { // Cannot access wifi metrics, report no error. if errors.Is(err, os.ErrNotExist) { diff --git a/collector/xfs_linux.go b/collector/xfs_linux.go index bb25acab9f..b6e6010dda 100644 --- a/collector/xfs_linux.go +++ b/collector/xfs_linux.go @@ -35,8 +35,8 @@ func init() { } // NewXFSCollector returns a new Collector exposing XFS statistics. -func NewXFSCollector(logger log.Logger) (Collector, error) { - fs, err := xfs.NewFS(*procPath, *sysPath) +func NewXFSCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := xfs.NewFS(*config.Path.ProcPath, *config.Path.SysPath) if err != nil { return nil, fmt.Errorf("failed to open sysfs: %w", err) } diff --git a/collector/zfs.go b/collector/zfs.go index df1a97aec3..082f8f2147 100644 --- a/collector/zfs.go +++ b/collector/zfs.go @@ -40,10 +40,11 @@ type zfsCollector struct { linuxZpoolStatePath string linuxPathMap map[string]string logger log.Logger + config *NodeCollectorConfig } // NewZFSCollector returns a new Collector exposing ZFS statistics. -func NewZFSCollector(logger log.Logger) (Collector, error) { +func NewZFSCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &zfsCollector{ linuxProcpathBase: "spl/kstat/zfs", linuxZpoolIoPath: "/*/io", @@ -63,6 +64,7 @@ func NewZFSCollector(logger log.Logger) (Collector, error) { "zfs_zil": "zil", }, logger: logger, + config: config, }, nil } diff --git a/collector/zfs_freebsd.go b/collector/zfs_freebsd.go index 0e4d969275..0416c9ca63 100644 --- a/collector/zfs_freebsd.go +++ b/collector/zfs_freebsd.go @@ -18,6 +18,7 @@ package collector import ( "fmt" + "strings" "github.com/go-kit/log" "github.com/go-kit/log/level" @@ -36,10 +37,10 @@ const ( ) func init() { - registerCollector("zfs", defaultEnabled, NewZfsCollector) + registerCollector(zfsCollectorSubsystem, defaultEnabled, NewZfsCollector) } -func NewZfsCollector(logger log.Logger) (Collector, error) { +func NewZfsCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &zfsCollector{ sysctls: []bsdSysctl{ { @@ -336,11 +337,11 @@ func (c *zfsCollector) parseFreeBSDPoolObjsetStats() error { for dataset, _ := range zfsDatasets { if strings.HasSuffix(dataset, ".dataset_name") { - zfsDatasetNames = append(zfsDatasetNames, strings.SplitAfter(dataset, ".")[3]) + zfsDatasetsNames = append(zfsDatasetsNames, strings.SplitAfter(dataset, ".")[3]) } } - for zpoolDataset := range zfsDatasetsNames { + for _, zpoolDataset := range zfsDatasetsNames { zfsDatasetLabels := map[string]string{ "dataset": zpoolDataset, "zpool": strings.SplitAfter(zpoolDataset, "/")[0], diff --git a/collector/zfs_linux.go b/collector/zfs_linux.go index e7be4a9836..464ea2f131 100644 --- a/collector/zfs_linux.go +++ b/collector/zfs_linux.go @@ -45,12 +45,12 @@ const ( var zfsPoolStatesName = []string{"online", "degraded", "faulted", "offline", "removed", "unavail", "suspended"} func (c *zfsCollector) openProcFile(path string) (*os.File, error) { - file, err := os.Open(procFilePath(path)) + file, err := os.Open(c.config.Path.procFilePath(path)) if err != nil { // file not found error can occur if: // 1. zfs module is not loaded // 2. zfs version does not have the feature with metrics -- ok to ignore - level.Debug(c.logger).Log("msg", "Cannot open file for reading", "path", procFilePath(path)) + level.Debug(c.logger).Log("msg", "Cannot open file for reading", "path", c.config.Path.procFilePath(path)) return nil, errZFSNotAvailable } return file, nil @@ -69,7 +69,7 @@ func (c *zfsCollector) updateZfsStats(subsystem string, ch chan<- prometheus.Met } func (c *zfsCollector) updatePoolStats(ch chan<- prometheus.Metric) error { - zpoolPaths, err := filepath.Glob(procFilePath(filepath.Join(c.linuxProcpathBase, c.linuxZpoolIoPath))) + zpoolPaths, err := filepath.Glob(c.config.Path.procFilePath(filepath.Join(c.linuxProcpathBase, c.linuxZpoolIoPath))) if err != nil { return err } @@ -91,7 +91,7 @@ func (c *zfsCollector) updatePoolStats(ch chan<- prometheus.Metric) error { } } - zpoolObjsetPaths, err := filepath.Glob(procFilePath(filepath.Join(c.linuxProcpathBase, c.linuxZpoolObjsetPath))) + zpoolObjsetPaths, err := filepath.Glob(c.config.Path.procFilePath(filepath.Join(c.linuxProcpathBase, c.linuxZpoolObjsetPath))) if err != nil { return err } @@ -113,7 +113,7 @@ func (c *zfsCollector) updatePoolStats(ch chan<- prometheus.Metric) error { } } - zpoolStatePaths, err := filepath.Glob(procFilePath(filepath.Join(c.linuxProcpathBase, c.linuxZpoolStatePath))) + zpoolStatePaths, err := filepath.Glob(c.config.Path.procFilePath(filepath.Join(c.linuxProcpathBase, c.linuxZpoolStatePath))) if err != nil { return err } diff --git a/collector/zfs_solaris.go b/collector/zfs_solaris.go index 52f2500f25..d78cc796bc 100644 --- a/collector/zfs_solaris.go +++ b/collector/zfs_solaris.go @@ -62,10 +62,10 @@ const ( ) func init() { - registerCollector("zfs", defaultEnabled, NewZfsCollector) + registerCollector(zfsCollectorSubsystem, defaultEnabled, NewZfsCollector) } -func NewZfsCollector(logger log.Logger) (Collector, error) { +func NewZfsCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { return &zfsCollector{ abdstatsLinearCount: prometheus.NewDesc( prometheus.BuildFQName(namespace, zfsCollectorSubsystem, "abdstats_linear_count_total"), diff --git a/collector/zoneinfo_linux.go b/collector/zoneinfo_linux.go index 8f7e35d9f1..73793dd516 100644 --- a/collector/zoneinfo_linux.go +++ b/collector/zoneinfo_linux.go @@ -33,12 +33,12 @@ type zoneinfoCollector struct { } func init() { - registerCollector("zoneinfo", defaultDisabled, NewZoneinfoCollector) + registerCollector(zoneinfoSubsystem, defaultDisabled, NewZoneinfoCollector) } // NewZoneinfoCollector returns a new Collector exposing zone stats. -func NewZoneinfoCollector(logger log.Logger) (Collector, error) { - fs, err := procfs.NewFS(*procPath) +func NewZoneinfoCollector(config *NodeCollectorConfig, logger log.Logger) (Collector, error) { + fs, err := procfs.NewFS(*config.Path.ProcPath) if err != nil { return nil, fmt.Errorf("failed to open procfs: %w", err) } diff --git a/kingpinconfig/flags.go b/kingpinconfig/flags.go new file mode 100644 index 0000000000..626678d47f --- /dev/null +++ b/kingpinconfig/flags.go @@ -0,0 +1,172 @@ +// Copyright 2023 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package kingpinconfig + +import ( + "github.com/alecthomas/kingpin/v2" + "github.com/prometheus/node_exporter/collector" + "github.com/prometheus/procfs" +) + +func AddFlags(a *kingpin.Application) *collector.NodeCollectorConfig { + config := &collector.NodeCollectorConfig{} + + config.Arp.DeviceInclude = a.Flag("collector.arp.device-include", "Regexp of arp devices to include (mutually exclusive to device-exclude).").String() + config.Arp.DeviceExclude = a.Flag("collector.arp.device-exclude", "Regexp of arp devices to exclude (mutually exclusive to device-include).").String() + config.Arp.Netlink = a.Flag("collector.arp.netlink", "Use netlink to gather stats instead of /proc/net/arp.").Default("true").Bool() + + config.Bcache.PriorityStats = a.Flag("collector.bcache.priorityStats", "Expose expensive priority stats.").Bool() + + config.CPU.EnableCPUGuest = a.Flag("collector.cpu.guest", "Enables metric node_cpu_guest_seconds_total").Default("true").Bool() + config.CPU.EnableCPUInfo = a.Flag("collector.cpu.info", "Enables metric cpu_info").Bool() + config.CPU.FlagsInclude = a.Flag("collector.cpu.info.flags-include", "Filter the `flags` field in cpuInfo with a value that must be a regular expression").String() + config.CPU.BugsInclude = a.Flag("collector.cpu.info.bugs-include", "Filter the `bugs` field in cpuInfo with a value that must be a regular expression").String() + + config.DiskstatsDeviceFilter.DeviceExclude = a.Flag( + "collector.diskstats.device-exclude", + "Regexp of diskstats devices to exclude (mutually exclusive to device-include).", + ).PreAction(func(c *kingpin.ParseContext) error { + config.DiskstatsDeviceFilter.DeviceExcludeSet = true + return nil + }).String() + config.DiskstatsDeviceFilter.OldDeviceExclude = a.Flag( + "collector.diskstats.ignored-devices", + "DEPRECATED: Use collector.diskstats.device-exclude", + ).Hidden().String() + config.DiskstatsDeviceFilter.DeviceInclude = a.Flag("collector.diskstats.device-include", "Regexp of diskstats devices to include (mutually exclusive to device-exclude).").String() + + config.Ethtool.DeviceInclude = a.Flag("collector.ethtool.device-include", "Regexp of ethtool devices to include (mutually exclusive to device-exclude).").String() + config.Ethtool.DeviceExclude = a.Flag("collector.ethtool.device-exclude", "Regexp of ethtool devices to exclude (mutually exclusive to device-include).").String() + config.Ethtool.IncludedMetrics = a.Flag("collector.ethtool.metrics-include", "Regexp of ethtool stats to include.").Default(".*").String() + + config.Filesystem.MountPointsExclude = a.Flag( + "collector.filesystem.mount-points-exclude", + "Regexp of mount points to exclude for filesystem collector.", + ).PreAction(func(c *kingpin.ParseContext) error { + config.Filesystem.MountPointsExcludeSet = true + return nil + }).String() + config.Filesystem.OldMountPointsExcluded = a.Flag( + "collector.filesystem.ignored-mount-points", + "Regexp of mount points to ignore for filesystem collector.", + ).Hidden().String() + + config.Filesystem.FSTypesExclude = a.Flag( + "collector.filesystem.fs-types-exclude", + "Regexp of filesystem types to exclude for filesystem collector.", + ).PreAction(func(c *kingpin.ParseContext) error { + config.Filesystem.FSTypesExcludeSet = true + return nil + }).String() + config.Filesystem.OldFSTypesExcluded = a.Flag( + "collector.filesystem.ignored-fs-types", + "Regexp of filesystem types to ignore for filesystem collector.", + ).Hidden().String() + config.Filesystem.MountTimeout = a.Flag("collector.filesystem.mount-timeout", + "how long to wait for a mount to respond before marking it as stale"). + Hidden().Default("5s").Duration() + config.Filesystem.StatWorkerCount = a.Flag("collector.filesystem.stat-workers", + "how many stat calls to process simultaneously"). + Hidden().Default("4").Int() + + config.HwMon.ChipInclude = a.Flag("collector.hwmon.chip-include", "Regexp of hwmon chip to include (mutually exclusive to device-exclude).").String() + config.HwMon.ChipExclude = a.Flag("collector.hwmon.chip-exclude", "Regexp of hwmon chip to exclude (mutually exclusive to device-include).").String() + + config.IPVS.Labels = a.Flag("collector.ipvs.backend-labels", "Comma separated list for IPVS backend stats labels.").PreAction(func(c *kingpin.ParseContext) error { + config.IPVS.LabelsSet = true + return nil + }).String() + + config.NetClass.IgnoredDevices = a.Flag("collector.netclass.ignored-devices", "Regexp of net devices to ignore for netclass collector.").Default("^$").String() + config.NetClass.InvalidSpeed = a.Flag("collector.netclass.ignore-invalid-speed", "Ignore devices where the speed is invalid. This will be the default behavior in 2.x.").Bool() + config.NetClass.Netlink = a.Flag("collector.netclass.netlink", "Use netlink to gather stats instead of /proc/net/dev.").Default("false").Bool() + config.NetClass.RTNLWithStats = a.Flag("collector.netclass_rtnl.with-stats", "Expose the statistics for each network device, replacing netdev collector.").Bool() + + config.NetDev.DeviceInclude = a.Flag("collector.netdev.device-include", "Regexp of net devices to include (mutually exclusive to device-exclude).").String() + config.NetDev.OldDeviceInclude = a.Flag("collector.netdev.device-whitelist", "DEPRECATED: Use collector.netdev.device-include").Hidden().String() + config.NetDev.DeviceExclude = a.Flag("collector.netdev.device-exclude", "Regexp of net devices to exclude (mutually exclusive to device-include).").String() + config.NetDev.OldDeviceExclude = a.Flag("collector.netdev.device-blacklist", "DEPRECATED: Use collector.netdev.device-exclude").Hidden().String() + config.NetDev.AddressInfo = a.Flag("collector.netdev.address-info", "Collect address-info for every device").Bool() + config.NetDev.DetailedMetrics = a.Flag("collector.netdev.enable-detailed-metrics", "Use (incompatible) metric names that provide more detailed stats on Linux").Bool() + config.NetDev.Netlink = a.Flag("collector.netdev.netlink", "Use netlink to gather stats instead of /proc/net/dev.").Default("true").Bool() + + config.NetStat.Fields = a.Flag("collector.netstat.fields", "Regexp of fields to return for netstat collector.").Default("^(.*_(InErrors|InErrs)|Ip_Forwarding|Ip(6|Ext)_(InOctets|OutOctets)|Icmp6?_(InMsgs|OutMsgs)|TcpExt_(Listen.*|Syncookies.*|TCPSynRetrans|TCPTimeouts)|Tcp_(ActiveOpens|InSegs|OutSegs|OutRsts|PassiveOpens|RetransSegs|CurrEstab)|Udp6?_(InDatagrams|OutDatagrams|NoPorts|RcvbufErrors|SndbufErrors))$").String() + + config.NTP.Server = a.Flag("collector.ntp.server", "NTP server to use for ntp collector").Default("127.0.0.1").String() + config.NTP.ServerPort = a.Flag("collector.ntp.server-port", "UDP port number to connect to on NTP server").Default("123").Int() + config.NTP.ProtocolVersion = a.Flag("collector.ntp.protocol-version", "NTP protocol version").Default("4").Int() + config.NTP.ServerIsLocal = a.Flag("collector.ntp.server-is-local", "Certify that collector.ntp.server address is not a public ntp server").Default("false").Bool() + config.NTP.IPTTL = a.Flag("collector.ntp.ip-ttl", "IP TTL to use while sending NTP query").Default("1").Int() + // 3.46608s ~ 1.5s + PHI * (1 << maxPoll), where 1.5s is MAXDIST from ntp.org, it is 1.0 in RFC5905 + // max-distance option is used as-is without phi*(1<