From 21a02c4fbec4304f883ed7957bd81045d2f0c133 Mon Sep 17 00:00:00 2001 From: Calle Pettersson Date: Sun, 9 Feb 2020 21:09:26 +0100 Subject: [PATCH] Only query the perflib objects we need --- collector/ad.go | 2 +- collector/adfs.go | 2 +- collector/collector.go | 43 ++++++++++++++++++-- collector/container.go | 2 +- collector/cpu.go | 11 ++++- collector/cs.go | 2 +- collector/dns.go | 2 +- collector/hyperv.go | 2 +- collector/iis.go | 2 +- collector/logical_disk.go | 2 +- collector/logon.go | 2 +- collector/memory.go | 2 +- collector/msmq.go | 2 +- collector/mssql.go | 2 +- collector/net.go | 2 +- collector/netframework_clrexceptions.go | 2 +- collector/netframework_clrinterop.go | 2 +- collector/netframework_clrjit.go | 2 +- collector/netframework_clrloading.go | 2 +- collector/netframework_clrlocksandthreads.go | 2 +- collector/netframework_clrmemory.go | 2 +- collector/netframework_clrremoting.go | 2 +- collector/netframework_clrsecurity.go | 2 +- collector/os.go | 2 +- collector/perflib.go | 11 ++++- collector/process.go | 2 +- collector/service.go | 2 +- collector/system.go | 2 +- collector/tcp.go | 2 +- collector/textfile.go | 2 +- collector/thermalzone.go | 2 +- collector/vmware.go | 2 +- exporter.go | 31 +++++--------- 33 files changed, 97 insertions(+), 57 deletions(-) diff --git a/collector/ad.go b/collector/ad.go index 914bf222..6a01944d 100644 --- a/collector/ad.go +++ b/collector/ad.go @@ -11,7 +11,7 @@ import ( ) func init() { - Factories["ad"] = NewADCollector + registerCollector("ad", NewADCollector) } // A ADCollector is a Prometheus collector for WMI Win32_PerfRawData_DirectoryServices_DirectoryServices metrics diff --git a/collector/adfs.go b/collector/adfs.go index ad2a2a4f..b81d0672 100644 --- a/collector/adfs.go +++ b/collector/adfs.go @@ -7,7 +7,7 @@ import ( ) func init() { - Factories["adfs"] = newADFSCollector + registerCollector("adfs", newADFSCollector) } type adfsCollector struct { diff --git a/collector/collector.go b/collector/collector.go index 3cdac9a7..edcb880b 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -2,6 +2,7 @@ package collector import ( "strconv" + "strings" "github.com/leoluk/perflib_exporter/perflib" "github.com/prometheus/client_golang/prometheus" @@ -47,8 +48,41 @@ func getWindowsVersion() float64 { return currentv_flt } -// Factories ... -var Factories = make(map[string]func() (Collector, error)) +type collectorBuilder func() (Collector, error) + +var ( + builders = make(map[string]collectorBuilder) + perfCounterDependencies = make(map[string]string) +) + +func registerCollector(name string, builder collectorBuilder, perfCounterNames ...string) { + builders[name] = builder + perfIndicies := make([]string, 0, len(perfCounterNames)) + for _, cn := range perfCounterNames { + perfIndicies = append(perfIndicies, MapCounterToIndex(cn)) + } + perfCounterDependencies[name] = strings.Join(perfIndicies, " ") +} + +func Available() []string { + cs := make([]string, 0, len(builders)) + for c := range builders { + cs = append(cs, c) + } + return cs +} +func Build(collector string) (Collector, error) { + return builders[collector]() +} +func getPerfQuery(collectors []string) string { + parts := make([]string, 0, len(collectors)) + for _, c := range collectors { + if p := perfCounterDependencies[c]; p != "" { + parts = append(parts, p) + } + } + return strings.Join(parts, " ") +} // Collector is the interface a collector has to implement. type Collector interface { @@ -61,8 +95,9 @@ type ScrapeContext struct { } // PrepareScrapeContext creates a ScrapeContext to be used during a single scrape -func PrepareScrapeContext() (*ScrapeContext, error) { - objs, err := getPerflibSnapshot() +func PrepareScrapeContext(collectors []string) (*ScrapeContext, error) { + q := getPerfQuery(collectors) // TODO: Memoize + objs, err := getPerflibSnapshot(q) if err != nil { return nil, err } diff --git a/collector/container.go b/collector/container.go index ab4d5f87..8d2ef192 100644 --- a/collector/container.go +++ b/collector/container.go @@ -9,7 +9,7 @@ import ( ) func init() { - Factories["container"] = NewContainerMetricsCollector + registerCollector("container", NewContainerMetricsCollector) } // A ContainerMetricsCollector is a Prometheus collector for containers metrics diff --git a/collector/cpu.go b/collector/cpu.go index 8aa7fa15..0e3e9f09 100644 --- a/collector/cpu.go +++ b/collector/cpu.go @@ -9,7 +9,14 @@ import ( ) func init() { - Factories["cpu"] = newCPUCollector + var deps string + // See below for 6.05 magic value + if getWindowsVersion() > 6.05 { + deps = "Processor Information" + } else { + deps = "Processor" + } + registerCollector("cpu", newCPUCollector, deps) } type cpuCollectorBasic struct { @@ -38,7 +45,7 @@ func newCPUCollector() (Collector, error) { version := getWindowsVersion() // For Windows 2008 (version 6.0) or earlier we only have the "Processor" // class. As of Windows 2008 R2 (version 6.1) the more detailed - // "ProcessorInformation" set is available (although some of the counters + // "Processor Information" set is available (although some of the counters // are added in later versions, so we aren't guaranteed to get all of // them). // Value 6.05 was selected to split between Windows versions. diff --git a/collector/cs.go b/collector/cs.go index 6c4ada3b..a07a24c7 100644 --- a/collector/cs.go +++ b/collector/cs.go @@ -11,7 +11,7 @@ import ( ) func init() { - Factories["cs"] = NewCSCollector + registerCollector("cs", NewCSCollector) } // A CSCollector is a Prometheus collector for WMI metrics diff --git a/collector/dns.go b/collector/dns.go index 6e7684b8..f869827b 100644 --- a/collector/dns.go +++ b/collector/dns.go @@ -11,7 +11,7 @@ import ( ) func init() { - Factories["dns"] = NewDNSCollector + registerCollector("dns", NewDNSCollector) } // A DNSCollector is a Prometheus collector for WMI Win32_PerfRawData_DNS_DNS metrics diff --git a/collector/hyperv.go b/collector/hyperv.go index c0b63778..d0bf01b1 100644 --- a/collector/hyperv.go +++ b/collector/hyperv.go @@ -11,7 +11,7 @@ import ( ) func init() { - Factories["hyperv"] = NewHyperVCollector + registerCollector("hyperv", NewHyperVCollector) } // HyperVCollector is a Prometheus collector for hyper-v diff --git a/collector/iis.go b/collector/iis.go index 1914c3f1..b1b0ebe0 100644 --- a/collector/iis.go +++ b/collector/iis.go @@ -16,7 +16,7 @@ import ( ) func init() { - Factories["iis"] = NewIISCollector + registerCollector("iis", NewIISCollector) } type simple_version struct { diff --git a/collector/logical_disk.go b/collector/logical_disk.go index a1378462..d6e391de 100644 --- a/collector/logical_disk.go +++ b/collector/logical_disk.go @@ -12,7 +12,7 @@ import ( ) func init() { - Factories["logical_disk"] = NewLogicalDiskCollector + registerCollector("logical_disk", NewLogicalDiskCollector, "LogicalDisk") } var ( diff --git a/collector/logon.go b/collector/logon.go index 009e5c10..d6a4919a 100644 --- a/collector/logon.go +++ b/collector/logon.go @@ -11,7 +11,7 @@ import ( ) func init() { - Factories["logon"] = NewLogonCollector + registerCollector("logon", NewLogonCollector) } // A LogonCollector is a Prometheus collector for WMI metrics diff --git a/collector/memory.go b/collector/memory.go index d6ba2baf..29aecf7f 100644 --- a/collector/memory.go +++ b/collector/memory.go @@ -11,7 +11,7 @@ import ( ) func init() { - Factories["memory"] = NewMemoryCollector + registerCollector("memory", NewMemoryCollector, "Memory") } // A MemoryCollector is a Prometheus collector for perflib Memory metrics diff --git a/collector/msmq.go b/collector/msmq.go index 2dd951e2..16572a8c 100644 --- a/collector/msmq.go +++ b/collector/msmq.go @@ -12,7 +12,7 @@ import ( ) func init() { - Factories["msmq"] = NewMSMQCollector + registerCollector("msmq", NewMSMQCollector) } var ( diff --git a/collector/mssql.go b/collector/mssql.go index 9b0d3744..71f1bd2c 100644 --- a/collector/mssql.go +++ b/collector/mssql.go @@ -127,7 +127,7 @@ func mssqlExpandEnabledCollectors(enabled string) []string { } func init() { - Factories["mssql"] = NewMSSQLCollector + registerCollector("mssql", NewMSSQLCollector) } // A MSSQLCollector is a Prometheus collector for various WMI Win32_PerfRawData_MSSQLSERVER_* metrics diff --git a/collector/net.go b/collector/net.go index eed3cfd9..4e1dc495 100644 --- a/collector/net.go +++ b/collector/net.go @@ -12,7 +12,7 @@ import ( ) func init() { - Factories["net"] = NewNetworkCollector + registerCollector("net", NewNetworkCollector, "Network Interface") } var ( diff --git a/collector/netframework_clrexceptions.go b/collector/netframework_clrexceptions.go index 8030761d..ffced912 100644 --- a/collector/netframework_clrexceptions.go +++ b/collector/netframework_clrexceptions.go @@ -9,7 +9,7 @@ import ( ) func init() { - Factories["netframework_clrexceptions"] = NewNETFramework_NETCLRExceptionsCollector + registerCollector("netframework_clrexceptions", NewNETFramework_NETCLRExceptionsCollector) } // A NETFramework_NETCLRExceptionsCollector is a Prometheus collector for WMI Win32_PerfRawData_NETFramework_NETCLRExceptions metrics diff --git a/collector/netframework_clrinterop.go b/collector/netframework_clrinterop.go index 8bfa2e72..78171919 100644 --- a/collector/netframework_clrinterop.go +++ b/collector/netframework_clrinterop.go @@ -9,7 +9,7 @@ import ( ) func init() { - Factories["netframework_clrinterop"] = NewNETFramework_NETCLRInteropCollector + registerCollector("netframework_clrinterop", NewNETFramework_NETCLRInteropCollector) } // A NETFramework_NETCLRInteropCollector is a Prometheus collector for WMI Win32_PerfRawData_NETFramework_NETCLRInterop metrics diff --git a/collector/netframework_clrjit.go b/collector/netframework_clrjit.go index 447a3f68..fb3d4c2a 100644 --- a/collector/netframework_clrjit.go +++ b/collector/netframework_clrjit.go @@ -9,7 +9,7 @@ import ( ) func init() { - Factories["netframework_clrjit"] = NewNETFramework_NETCLRJitCollector + registerCollector("netframework_clrjit", NewNETFramework_NETCLRJitCollector) } // A NETFramework_NETCLRJitCollector is a Prometheus collector for WMI Win32_PerfRawData_NETFramework_NETCLRJit metrics diff --git a/collector/netframework_clrloading.go b/collector/netframework_clrloading.go index ae91b95a..aba0921c 100644 --- a/collector/netframework_clrloading.go +++ b/collector/netframework_clrloading.go @@ -9,7 +9,7 @@ import ( ) func init() { - Factories["netframework_clrloading"] = NewNETFramework_NETCLRLoadingCollector + registerCollector("netframework_clrloading", NewNETFramework_NETCLRLoadingCollector) } // A NETFramework_NETCLRLoadingCollector is a Prometheus collector for WMI Win32_PerfRawData_NETFramework_NETCLRLoading metrics diff --git a/collector/netframework_clrlocksandthreads.go b/collector/netframework_clrlocksandthreads.go index 19b996fc..e446eaa2 100644 --- a/collector/netframework_clrlocksandthreads.go +++ b/collector/netframework_clrlocksandthreads.go @@ -9,7 +9,7 @@ import ( ) func init() { - Factories["netframework_clrlocksandthreads"] = NewNETFramework_NETCLRLocksAndThreadsCollector + registerCollector("netframework_clrlocksandthreads", NewNETFramework_NETCLRLocksAndThreadsCollector) } // A NETFramework_NETCLRLocksAndThreadsCollector is a Prometheus collector for WMI Win32_PerfRawData_NETFramework_NETCLRLocksAndThreads metrics diff --git a/collector/netframework_clrmemory.go b/collector/netframework_clrmemory.go index c2b9aca4..407edde8 100644 --- a/collector/netframework_clrmemory.go +++ b/collector/netframework_clrmemory.go @@ -9,7 +9,7 @@ import ( ) func init() { - Factories["netframework_clrmemory"] = NewNETFramework_NETCLRMemoryCollector + registerCollector("netframework_clrmemory", NewNETFramework_NETCLRMemoryCollector) } // A NETFramework_NETCLRMemoryCollector is a Prometheus collector for WMI Win32_PerfRawData_NETFramework_NETCLRMemory metrics diff --git a/collector/netframework_clrremoting.go b/collector/netframework_clrremoting.go index 44917ac1..9da318a7 100644 --- a/collector/netframework_clrremoting.go +++ b/collector/netframework_clrremoting.go @@ -9,7 +9,7 @@ import ( ) func init() { - Factories["netframework_clrremoting"] = NewNETFramework_NETCLRRemotingCollector + registerCollector("netframework_clrremoting", NewNETFramework_NETCLRRemotingCollector) } // A NETFramework_NETCLRRemotingCollector is a Prometheus collector for WMI Win32_PerfRawData_NETFramework_NETCLRRemoting metrics diff --git a/collector/netframework_clrsecurity.go b/collector/netframework_clrsecurity.go index f7a463cc..1ea0ded1 100644 --- a/collector/netframework_clrsecurity.go +++ b/collector/netframework_clrsecurity.go @@ -9,7 +9,7 @@ import ( ) func init() { - Factories["netframework_clrsecurity"] = NewNETFramework_NETCLRSecurityCollector + registerCollector("netframework_clrsecurity", NewNETFramework_NETCLRSecurityCollector) } // A NETFramework_NETCLRSecurityCollector is a Prometheus collector for WMI Win32_PerfRawData_NETFramework_NETCLRSecurity metrics diff --git a/collector/os.go b/collector/os.go index 50c82b62..45486ace 100644 --- a/collector/os.go +++ b/collector/os.go @@ -12,7 +12,7 @@ import ( ) func init() { - Factories["os"] = NewOSCollector + registerCollector("os", NewOSCollector) } // A OSCollector is a Prometheus collector for WMI metrics diff --git a/collector/perflib.go b/collector/perflib.go index 3b8af9fa..19ce2ad7 100644 --- a/collector/perflib.go +++ b/collector/perflib.go @@ -3,14 +3,21 @@ package collector import ( "fmt" "reflect" + "strconv" perflibCollector "github.com/leoluk/perflib_exporter/collector" "github.com/leoluk/perflib_exporter/perflib" "github.com/prometheus/common/log" ) -func getPerflibSnapshot() (map[string]*perflib.PerfObject, error) { - objects, err := perflib.QueryPerformanceData("Global") +var nametable = perflib.QueryNameTable("Counter 009") // Reads the names in English TODO: validate that the English names are always present + +func MapCounterToIndex(name string) string { + return strconv.Itoa(int(nametable.LookupIndex(name))) +} + +func getPerflibSnapshot(objNames string) (map[string]*perflib.PerfObject, error) { + objects, err := perflib.QueryPerformanceData(objNames) if err != nil { return nil, err } diff --git a/collector/process.go b/collector/process.go index bdcaffa3..c90807f4 100644 --- a/collector/process.go +++ b/collector/process.go @@ -13,7 +13,7 @@ import ( ) func init() { - Factories["process"] = NewProcessCollector + registerCollector("process", NewProcessCollector) } var ( diff --git a/collector/service.go b/collector/service.go index b195127d..37fc08b2 100644 --- a/collector/service.go +++ b/collector/service.go @@ -12,7 +12,7 @@ import ( ) func init() { - Factories["service"] = NewserviceCollector + registerCollector("service", NewserviceCollector) } var ( diff --git a/collector/system.go b/collector/system.go index 04bca150..a4eec8ab 100644 --- a/collector/system.go +++ b/collector/system.go @@ -8,7 +8,7 @@ import ( ) func init() { - Factories["system"] = NewSystemCollector + registerCollector("system", NewSystemCollector, "System") } // A SystemCollector is a Prometheus collector for WMI metrics diff --git a/collector/tcp.go b/collector/tcp.go index 3400fd59..0253907a 100644 --- a/collector/tcp.go +++ b/collector/tcp.go @@ -10,7 +10,7 @@ import ( ) func init() { - Factories["tcp"] = NewTCPCollector + registerCollector("tcp", NewTCPCollector) } // A TCPCollector is a Prometheus collector for WMI Win32_PerfRawData_Tcpip_TCPv4 metrics diff --git a/collector/textfile.go b/collector/textfile.go index 72cce988..bfd8c522 100644 --- a/collector/textfile.go +++ b/collector/textfile.go @@ -54,7 +54,7 @@ type textFileCollector struct { } func init() { - Factories["textfile"] = NewTextFileCollector + registerCollector("textfile", NewTextFileCollector) } // NewTextFileCollector returns a new Collector exposing metrics read from files diff --git a/collector/thermalzone.go b/collector/thermalzone.go index 6afde540..baf6ec8b 100644 --- a/collector/thermalzone.go +++ b/collector/thermalzone.go @@ -7,7 +7,7 @@ import ( ) func init() { - Factories["thermalzone"] = NewThermalZoneCollector + registerCollector("thermalzone", NewThermalZoneCollector) } // A thermalZoneCollector is a Prometheus collector for WMI Win32_PerfRawData_Counters_ThermalZoneInformation metrics diff --git a/collector/vmware.go b/collector/vmware.go index 37de16ab..acecbf1b 100644 --- a/collector/vmware.go +++ b/collector/vmware.go @@ -11,7 +11,7 @@ import ( ) func init() { - Factories["vmware"] = NewVmwareCollector + registerCollector("vmware", NewVmwareCollector) } // A VmwareCollector is a Prometheus collector for WMI Win32_PerfRawData_vmGuestLib_VMem/Win32_PerfRawData_vmGuestLib_VCPU metrics diff --git a/exporter.go b/exporter.go index 5ca3a036..70226cfb 100644 --- a/exporter.go +++ b/exporter.go @@ -97,7 +97,11 @@ func (coll WmiCollector) Collect(ch chan<- prometheus.Metric) { ) t := time.Now() - scrapeContext, err := collector.PrepareScrapeContext() + cs := make([]string, 0, len(coll.collectors)) + for name := range coll.collectors { + cs = append(cs, name) + } + scrapeContext, err := collector.PrepareScrapeContext(cs) ch <- prometheus.MustNewConstMetric( snapshotDuration, prometheus.GaugeValue, @@ -188,17 +192,6 @@ func (coll WmiCollector) Collect(ch chan<- prometheus.Metric) { l.Unlock() } -func filterAvailableCollectors(collectors string) string { - var availableCollectors []string - for _, c := range strings.Split(collectors, ",") { - _, ok := collector.Factories[c] - if ok { - availableCollectors = append(availableCollectors, c) - } - } - return strings.Join(availableCollectors, ",") -} - func execute(name string, c collector.Collector, ctx *collector.ScrapeContext, ch chan<- prometheus.Metric) collectorOutcome { t := time.Now() err := c.Collect(ctx, ch) @@ -239,16 +232,13 @@ func loadCollectors(list string) (map[string]collector.Collector, error) { enabled := expandEnabledCollectors(list) for _, name := range enabled { - fn, ok := collector.Factories[name] - if !ok { - return nil, fmt.Errorf("collector '%s' not available", name) - } - c, err := fn() + c, err := collector.Build(name) if err != nil { return nil, err } collectors[name] = c } + return collectors, nil } @@ -278,7 +268,7 @@ func main() { enabledCollectors = kingpin.Flag( "collectors.enabled", "Comma-separated list of collectors to use. Use '[defaults]' as a placeholder for all the collectors enabled by default."). - Default(filterAvailableCollectors(defaultCollectors)).String() + Default(defaultCollectors).String() printCollectors = kingpin.Flag( "collectors.print", "If true, print available collectors and exit.", @@ -295,8 +285,9 @@ func main() { kingpin.Parse() if *printCollectors { - collectorNames := make(sort.StringSlice, 0, len(collector.Factories)) - for n := range collector.Factories { + collectors := collector.Available() + collectorNames := make(sort.StringSlice, 0, len(collectors)) + for _, n := range collectors { collectorNames = append(collectorNames, n) } collectorNames.Sort()