diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 8d8a6145..4cd52d1e 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -100,5 +100,5 @@ jobs: - name: golangci-lint uses: golangci/golangci-lint-action@v6 with: - version: v1.59 - args: "--timeout=5m" \ No newline at end of file + version: v1.60 + args: "--timeout=5m --max-same-issues=0" \ No newline at end of file diff --git a/.golangci.yaml b/.golangci.yaml index ffec5f4d..9aaffccf 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -10,6 +10,7 @@ linters: - err113 - exhaustive - exhaustruct + - exportloopref - fatcontext - funlen - gochecknoglobals @@ -33,6 +34,10 @@ linters: - maintidx linters-settings: + gosec: + excludes: + - G115 # integer overflow conversion + gci: sections: - prefix(github.com/prometheus-community/windows_exporter/pkg/initiate) diff --git a/exporter.go b/exporter.go index 45e52a7a..493ad40c 100644 --- a/exporter.go +++ b/exporter.go @@ -32,7 +32,6 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/log/flag" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus-community/windows_exporter/pkg/utils" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/common/version" "github.com/prometheus/exporter-toolkit/web" webflag "github.com/prometheus/exporter-toolkit/web/kingpinflag" @@ -88,7 +87,7 @@ func main() { "config.file", "YAML configuration file to use. Values set in this file will be overridden by CLI flags.", ).String() - insecure_skip_verify = app.Flag( + insecureSkipVerify = app.Flag( "config.file.insecure-skip-verify", "Skip TLS verification in loading YAML configuration.", ).Default("false").Bool() @@ -148,7 +147,7 @@ func main() { _ = level.Debug(logger).Log("msg", "Logging has Started") if *configFile != "" { - resolver, err := config.NewResolver(*configFile, logger, *insecure_skip_verify) + resolver, err := config.NewResolver(*configFile, logger, *insecureSkipVerify) if err != nil { _ = level.Error(logger).Log("msg", "could not load config file", "err", err) os.Exit(1) @@ -196,11 +195,6 @@ func main() { } } - if err = wmi.InitWbem(logger); err != nil { - _ = level.Error(logger).Log("err", err) - os.Exit(1) - } - enabledCollectorList := utils.ExpandEnabledCollectors(*enabledCollectors) collectors.Enable(enabledCollectorList) diff --git a/pkg/collector/ad/ad.go b/pkg/collector/ad/ad.go index 6c02a57f..b0f43db4 100644 --- a/pkg/collector/ad/ad.go +++ b/pkg/collector/ad/ad.go @@ -9,8 +9,8 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "ad" @@ -21,7 +21,8 @@ var ConfigDefaults = Config{} // A Collector is a Prometheus Collector for WMI Win32_PerfRawData_DirectoryServices_DirectoryServices metrics. type Collector struct { - config Config + config Config + wmiClient *wmi.Client addressBookClientSessions *prometheus.Desc addressBookOperationsTotal *prometheus.Desc @@ -115,7 +116,13 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error { + if wmiClient == nil || wmiClient.SWbemServicesClient == nil { + return errors.New("wmiClient or SWbemServicesClient is nil") + } + + c.wmiClient = wmiClient + c.addressBookOperationsTotal = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "address_book_operations_total"), "", @@ -497,7 +504,7 @@ func (c *Collector) Build(_ log.Logger) error { // to the provided prometheus Metric channel. func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error { logger = log.With(logger, "collector", Name) - if err := c.collect(logger, ch); err != nil { + if err := c.collect(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting ad metrics", "err", err) return err } @@ -656,10 +663,9 @@ type Win32_PerfRawData_DirectoryServices_DirectoryServices struct { TransitivesuboperationsPersec uint32 } -func (c *Collector) collect(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collect(ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_DirectoryServices_DirectoryServices - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_DirectoryServices_DirectoryServices", &dst); err != nil { return err } if len(dst) == 0 { diff --git a/pkg/collector/adcs/adcs.go b/pkg/collector/adcs/adcs.go index d0a35e33..2adb710b 100644 --- a/pkg/collector/adcs/adcs.go +++ b/pkg/collector/adcs/adcs.go @@ -13,6 +13,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus-community/windows_exporter/pkg/utils" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "adcs" @@ -67,7 +68,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error { c.requestsPerSecond = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "requests_total"), "Total certificate requests processed", diff --git a/pkg/collector/adfs/adfs.go b/pkg/collector/adfs/adfs.go index 71db7c23..9ff0c20b 100644 --- a/pkg/collector/adfs/adfs.go +++ b/pkg/collector/adfs/adfs.go @@ -10,6 +10,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/perflib" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "adfs" @@ -94,7 +95,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error { c.adLoginConnectionFailures = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "ad_login_connection_failures_total"), "Total number of connection failures to an Active Directory domain controller", diff --git a/pkg/collector/cache/cache.go b/pkg/collector/cache/cache.go index 8c52f429..a3507168 100644 --- a/pkg/collector/cache/cache.go +++ b/pkg/collector/cache/cache.go @@ -10,6 +10,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/perflib" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "cache" @@ -81,7 +82,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error { c.asyncCopyReadsTotal = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "async_copy_reads_total"), "(AsyncCopyReadsTotal)", diff --git a/pkg/collector/collector.go b/pkg/collector/collector.go index 5269b484..ee9b4fc1 100644 --- a/pkg/collector/collector.go +++ b/pkg/collector/collector.go @@ -4,6 +4,7 @@ package collector import ( "errors" + "fmt" "slices" "strings" @@ -63,10 +64,11 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/collector/vmware_blast" "github.com/prometheus-community/windows_exporter/pkg/perflib" "github.com/prometheus-community/windows_exporter/pkg/types" + "github.com/yusufpapurcu/wmi" ) // NewWithFlags To be called by the exporter for collector initialization before running kingpin.Parse. -func NewWithFlags(app *kingpin.Application) Collectors { +func NewWithFlags(app *kingpin.Application) *Collectors { collectors := map[string]Collector{} for name, builder := range BuildersWithFlags { @@ -76,16 +78,10 @@ func NewWithFlags(app *kingpin.Application) Collectors { return New(collectors) } -func NewBuilderWithFlags[C Collector](fn BuilderWithFlags[C]) BuilderWithFlags[Collector] { - return func(app *kingpin.Application) Collector { - return fn(app) - } -} - // NewWithConfig To be called by the external libraries for collector initialization without running kingpin.Parse // //goland:noinspection GoUnusedExportedFunction -func NewWithConfig(config Config) Collectors { +func NewWithConfig(config Config) *Collectors { collectors := map[string]Collector{} collectors[ad.Name] = ad.New(&config.AD) collectors[adcs.Name] = adcs.New(&config.ADCS) @@ -144,9 +140,12 @@ func NewWithConfig(config Config) Collectors { } // New To be called by the external libraries for collector initialization. -func New(collectors Map) Collectors { - return Collectors{ +func New(collectors Map) *Collectors { + return &Collectors{ collectors: collectors, + wmiClient: &wmi.Client{ + AllowMissingFields: true, + }, } } @@ -192,9 +191,14 @@ func (c *Collectors) Enable(enabledCollectors []string) { func (c *Collectors) Build(logger log.Logger) error { var err error + c.wmiClient.SWbemServicesClient, err = wmi.InitializeSWbemServices(c.wmiClient) + if err != nil { + return fmt.Errorf("initialize SWbemServices: %w", err) + } + for _, collector := range c.collectors { - if err = collector.Build(logger); err != nil { - return err + if err = collector.Build(logger, c.wmiClient); err != nil { + return fmt.Errorf("error build collector %s: %w", collector.GetName(), err) } } @@ -221,5 +225,11 @@ func (c *Collectors) Close() error { } } + if c.wmiClient != nil && c.wmiClient.SWbemServicesClient != nil { + if err := c.wmiClient.SWbemServicesClient.Close(); err != nil { + errs = append(errs, err) + } + } + return errors.Join(errs...) } diff --git a/pkg/collector/container/container.go b/pkg/collector/container/container.go index d5cf8ee7..e547f3e4 100644 --- a/pkg/collector/container/container.go +++ b/pkg/collector/container/container.go @@ -12,6 +12,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/perflib" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "container" @@ -84,7 +85,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error { c.containerAvailable = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "available"), "Available", diff --git a/pkg/collector/cpu/cpu.go b/pkg/collector/cpu/cpu.go index 0fb586a5..11158902 100644 --- a/pkg/collector/cpu/cpu.go +++ b/pkg/collector/cpu/cpu.go @@ -11,6 +11,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus-community/windows_exporter/pkg/winversion" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "cpu" @@ -58,7 +59,7 @@ func (c *Collector) GetName() string { } func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) { - if winversion.WindowsVersionFloat > 6.05 { + if winversion.WindowsVersionFloat() > 6.05 { return []string{"Processor Information"}, nil } return []string{"Processor"}, nil @@ -68,7 +69,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error { c.cStateSecondsTotal = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "cstate_seconds_total"), "Time spent in low-power idle state", @@ -100,7 +101,7 @@ func (c *Collector) Build(_ log.Logger) error { // 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. - if winversion.WindowsVersionFloat < 6.05 { + if winversion.WindowsVersionFloat() < 6.05 { return nil } @@ -188,7 +189,7 @@ func (c *Collector) Build(_ log.Logger) error { func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error { logger = log.With(logger, "collector", Name) - if winversion.WindowsVersionFloat > 6.05 { + if winversion.WindowsVersionFloat() > 6.05 { return c.CollectFull(ctx, logger, ch) } diff --git a/pkg/collector/cpu_info/cpu_info.go b/pkg/collector/cpu_info/cpu_info.go index 9aafd8ba..5de9dfb2 100644 --- a/pkg/collector/cpu_info/cpu_info.go +++ b/pkg/collector/cpu_info/cpu_info.go @@ -11,8 +11,8 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const ( @@ -29,7 +29,8 @@ var ConfigDefaults = Config{} type Collector struct { config Config - cpuInfo *prometheus.Desc + wmiClient *wmi.Client + cpuInfo *prometheus.Desc } func New(config *Config) *Collector { @@ -60,7 +61,12 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error { + if wmiClient == nil || wmiClient.SWbemServicesClient == nil { + return errors.New("wmiClient or SWbemServicesClient is nil") + } + + c.wmiClient = wmiClient c.cpuInfo = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, "", Name), "Labelled CPU information as provided by Win32_Processor", @@ -105,7 +111,7 @@ func (c *Collector) collect(ch chan<- prometheus.Metric) error { // We use a static query here because the provided methods in wmi.go all issue a SELECT *; // This results in the time-consuming LoadPercentage field being read which seems to measure each CPU // serially over a 1 second interval, so the scrape time is at least 1s * num_sockets - if err := wmi.Query(win32ProcessorQuery, &dst); err != nil { + if err := c.wmiClient.Query(win32ProcessorQuery, &dst); err != nil { return err } if len(dst) == 0 { diff --git a/pkg/collector/cs/cs.go b/pkg/collector/cs/cs.go index 4068fbd1..8e14cce8 100644 --- a/pkg/collector/cs/cs.go +++ b/pkg/collector/cs/cs.go @@ -9,6 +9,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/headers/sysinfoapi" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "cs" @@ -54,7 +55,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error { c.logicalProcessors = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "logical_processors"), "ComputerSystem.NumberOfLogicalProcessors", diff --git a/pkg/collector/dfsr/dfsr.go b/pkg/collector/dfsr/dfsr.go index 621e6392..f56430f7 100644 --- a/pkg/collector/dfsr/dfsr.go +++ b/pkg/collector/dfsr/dfsr.go @@ -12,6 +12,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/perflib" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "dfsr" @@ -152,7 +153,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(logger log.Logger) error { +func (c *Collector) Build(logger log.Logger, _ *wmi.Client) error { logger = log.With(logger, "collector", Name) _ = level.Info(logger).Log("msg", "dfsr collector is in an experimental state! Metrics for this collector have not been tested.") diff --git a/pkg/collector/dhcp/dhcp.go b/pkg/collector/dhcp/dhcp.go index 42b2c080..49789ca8 100644 --- a/pkg/collector/dhcp/dhcp.go +++ b/pkg/collector/dhcp/dhcp.go @@ -8,6 +8,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/perflib" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "dhcp" @@ -75,7 +76,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error { c.packetsReceivedTotal = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "packets_received_total"), "Total number of packets received by the DHCP server (PacketsReceivedTotal)", diff --git a/pkg/collector/diskdrive/diskdrive.go b/pkg/collector/diskdrive/diskdrive.go index d3950830..b89c543b 100644 --- a/pkg/collector/diskdrive/diskdrive.go +++ b/pkg/collector/diskdrive/diskdrive.go @@ -10,8 +10,8 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const ( @@ -25,7 +25,8 @@ var ConfigDefaults = Config{} // A Collector is a Prometheus Collector for a few WMI metrics in Win32_DiskDrive. type Collector struct { - config Config + config Config + wmiClient *wmi.Client availability *prometheus.Desc diskInfo *prometheus.Desc @@ -62,7 +63,12 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error { + if wmiClient == nil || wmiClient.SWbemServicesClient == nil { + return errors.New("wmiClient or SWbemServicesClient is nil") + } + + c.wmiClient = wmiClient c.diskInfo = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "info"), "General drive information", @@ -167,7 +173,7 @@ func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- func (c *Collector) collect(ch chan<- prometheus.Metric) error { var dst []win32_DiskDrive - if err := wmi.Query(win32DiskQuery, &dst); err != nil { + if err := c.wmiClient.Query(win32DiskQuery, &dst); err != nil { return err } if len(dst) == 0 { diff --git a/pkg/collector/dns/dns.go b/pkg/collector/dns/dns.go index ea7744cf..851c65ef 100644 --- a/pkg/collector/dns/dns.go +++ b/pkg/collector/dns/dns.go @@ -9,8 +9,8 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "dns" @@ -21,7 +21,8 @@ var ConfigDefaults = Config{} // A Collector is a Prometheus Collector for WMI Win32_PerfRawData_DNS_DNS metrics. type Collector struct { - config Config + config Config + wmiClient *wmi.Client dynamicUpdatesFailures *prometheus.Desc dynamicUpdatesQueued *prometheus.Desc @@ -75,7 +76,13 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error { + if wmiClient == nil || wmiClient.SWbemServicesClient == nil { + return errors.New("wmiClient or SWbemServicesClient is nil") + } + + c.wmiClient = wmiClient + c.zoneTransferRequestsReceived = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "zone_transfer_requests_received_total"), "Number of zone transfer requests (AXFR/IXFR) received by the master DNS server", @@ -215,7 +222,7 @@ func (c *Collector) Build(_ log.Logger) error { // to the provided prometheus Metric channel. func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error { logger = log.With(logger, "collector", Name) - if err := c.collect(logger, ch); err != nil { + if err := c.collect(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting dns metrics", "err", err) return err } @@ -268,10 +275,9 @@ type Win32_PerfRawData_DNS_DNS struct { ZoneTransferSOARequestSent uint32 } -func (c *Collector) collect(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collect(ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_DNS_DNS - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_DNS_DNS", &dst); err != nil { return err } if len(dst) == 0 { diff --git a/pkg/collector/exchange/exchange.go b/pkg/collector/exchange/exchange.go index 02ec1859..22585607 100644 --- a/pkg/collector/exchange/exchange.go +++ b/pkg/collector/exchange/exchange.go @@ -13,6 +13,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/perflib" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "exchange" @@ -176,7 +177,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error { // desc creates a new prometheus description desc := func(metricName string, description string, labels ...string) *prometheus.Desc { return prometheus.NewDesc( diff --git a/pkg/collector/fsrmquota/fsrmquota.go b/pkg/collector/fsrmquota/fsrmquota.go index 8c5c8d3b..6eddd0d0 100644 --- a/pkg/collector/fsrmquota/fsrmquota.go +++ b/pkg/collector/fsrmquota/fsrmquota.go @@ -3,13 +3,15 @@ package fsrmquota import ( + "errors" + "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus-community/windows_exporter/pkg/utils" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "fsrmquota" @@ -19,7 +21,8 @@ type Config struct{} var ConfigDefaults = Config{} type Collector struct { - config Config + config Config + wmiClient *wmi.Client quotasCount *prometheus.Desc peakUsage *prometheus.Desc @@ -61,7 +64,13 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error { + if wmiClient == nil || wmiClient.SWbemServicesClient == nil { + return errors.New("wmiClient or SWbemServicesClient is nil") + } + + c.wmiClient = wmiClient + c.quotasCount = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "count"), "Number of Quotas", @@ -123,7 +132,7 @@ func (c *Collector) Build(_ log.Logger) error { // to the provided prometheus Metric channel. func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error { logger = log.With(logger, "collector", Name) - if err := c.collect(logger, ch); err != nil { + if err := c.collect(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting fsrmquota metrics", "err", err) return err } @@ -147,13 +156,11 @@ type MSFT_FSRMQuota struct { SoftLimit bool } -func (c *Collector) collect(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collect(ch chan<- prometheus.Metric) error { var dst []MSFT_FSRMQuota - q := wmi.QueryAll(&dst, logger) - var count int - if err := wmi.QueryNamespace(q, &dst, "root/microsoft/windows/fsrm"); err != nil { + if err := c.wmiClient.Query("SELECT * FROM MSFT_FSRMQuota", &dst, nil, "root/microsoft/windows/fsrm"); err != nil { return err } diff --git a/pkg/collector/handler.go b/pkg/collector/handler.go index 8e085836..6f1e6cd0 100644 --- a/pkg/collector/handler.go +++ b/pkg/collector/handler.go @@ -64,7 +64,7 @@ func (c *Collectors) BuildServeHTTP(logger log.Logger, disableExporterMetrics bo if err != nil { _ = level.Warn(logger).Log("msg", "Couldn't create filtered metrics handler", "err", err) w.WriteHeader(http.StatusBadRequest) - w.Write([]byte(fmt.Sprintf("Couldn't create filtered metrics handler: %s", err))) //nolint:errcheck + _, _ = w.Write([]byte(fmt.Sprintf("Couldn't create filtered metrics handler: %s", err))) return } diff --git a/pkg/collector/hyperv/hyperv.go b/pkg/collector/hyperv/hyperv.go index 56beba58..fe76bc09 100644 --- a/pkg/collector/hyperv/hyperv.go +++ b/pkg/collector/hyperv/hyperv.go @@ -3,6 +3,7 @@ package hyperv import ( + "errors" "fmt" "strings" @@ -10,8 +11,8 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "hyperv" @@ -22,7 +23,8 @@ var ConfigDefaults = Config{} // Collector is a Prometheus Collector for hyper-v. type Collector struct { - config Config + config Config + wmiClient *wmi.Client // Win32_PerfRawData_VmmsVirtualMachineStats_HyperVVirtualMachineHealthSummary healthCritical *prometheus.Desc @@ -167,7 +169,13 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error { + if wmiClient == nil || wmiClient.SWbemServicesClient == nil { + return errors.New("wmiClient or SWbemServicesClient is nil") + } + + c.wmiClient = wmiClient + buildSubsystemName := func(component string) string { return "hyperv_" + component } c.healthCritical = prometheus.NewDesc( @@ -749,22 +757,22 @@ func (c *Collector) Build(_ log.Logger) error { // to the provided prometheus Metric channel. func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error { logger = log.With(logger, "collector", Name) - if err := c.collectVmHealth(logger, ch); err != nil { + if err := c.collectVmHealth(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting hyperV health status metrics", "err", err) return err } - if err := c.collectVmVid(logger, ch); err != nil { + if err := c.collectVmVid(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting hyperV pages metrics", "err", err) return err } - if err := c.collectVmHv(logger, ch); err != nil { + if err := c.collectVmHv(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting hyperV hv status metrics", "err", err) return err } - if err := c.collectVmProcessor(logger, ch); err != nil { + if err := c.collectVmProcessor(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting hyperV processor metrics", "err", err) return err } @@ -784,27 +792,27 @@ func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- return err } - if err := c.collectVmSwitch(logger, ch); err != nil { + if err := c.collectVmSwitch(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting hyperV switch metrics", "err", err) return err } - if err := c.collectVmEthernet(logger, ch); err != nil { + if err := c.collectVmEthernet(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting hyperV ethernet metrics", "err", err) return err } - if err := c.collectVmStorage(logger, ch); err != nil { + if err := c.collectVmStorage(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting hyperV virtual storage metrics", "err", err) return err } - if err := c.collectVmNetwork(logger, ch); err != nil { + if err := c.collectVmNetwork(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting hyperV virtual network metrics", "err", err) return err } - if err := c.collectVmMemory(logger, ch); err != nil { + if err := c.collectVmMemory(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting hyperV virtual memory metrics", "err", err) return err } @@ -818,10 +826,9 @@ type Win32_PerfRawData_VmmsVirtualMachineStats_HyperVVirtualMachineHealthSummary HealthOk uint32 } -func (c *Collector) collectVmHealth(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectVmHealth(ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_VmmsVirtualMachineStats_HyperVVirtualMachineHealthSummary - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_VmmsVirtualMachineStats_HyperVVirtualMachineHealthSummary", &dst); err != nil { return err } @@ -850,10 +857,9 @@ type Win32_PerfRawData_VidPerfProvider_HyperVVMVidPartition struct { RemotePhysicalPages uint64 } -func (c *Collector) collectVmVid(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectVmVid(ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_VidPerfProvider_HyperVVMVidPartition - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_VidPerfProvider_HyperVVMVidPartition", &dst); err != nil { return err } @@ -913,10 +919,9 @@ type Win32_PerfRawData_HvStats_HyperVHypervisorRootPartition struct { VirtualTLBPages uint64 } -func (c *Collector) collectVmHv(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectVmHv(ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_HvStats_HyperVHypervisorRootPartition - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_HvStats_HyperVHypervisorRootPartition", &dst); err != nil { return err } @@ -1050,10 +1055,9 @@ type Win32_PerfRawData_HvStats_HyperVHypervisor struct { VirtualProcessors uint64 } -func (c *Collector) collectVmProcessor(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectVmProcessor(ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_HvStats_HyperVHypervisor - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_HvStats_HyperVHypervisor", &dst); err != nil { return err } @@ -1084,8 +1088,7 @@ type Win32_PerfRawData_HvStats_HyperVHypervisorLogicalProcessor struct { func (c *Collector) collectHostLPUsage(logger log.Logger, ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_HvStats_HyperVHypervisorLogicalProcessor - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_HvStats_HyperVHypervisorLogicalProcessor", &dst); err != nil { return err } @@ -1138,8 +1141,7 @@ type Win32_PerfRawData_HvStats_HyperVHypervisorRootVirtualProcessor struct { func (c *Collector) collectHostCpuUsage(logger log.Logger, ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_HvStats_HyperVHypervisorRootVirtualProcessor - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_HvStats_HyperVHypervisorRootVirtualProcessor", &dst); err != nil { return err } @@ -1206,8 +1208,7 @@ type Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor struct { func (c *Collector) collectVmCpuUsage(logger log.Logger, ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor", &dst); err != nil { return err } @@ -1297,10 +1298,9 @@ type Win32_PerfRawData_NvspSwitchStats_HyperVVirtualSwitch struct { PurgedMacAddressesPersec uint64 } -func (c *Collector) collectVmSwitch(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectVmSwitch(ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_NvspSwitchStats_HyperVVirtualSwitch - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_NvspSwitchStats_HyperVVirtualSwitch", &dst); err != nil { return err } @@ -1462,10 +1462,9 @@ type Win32_PerfRawData_EthernetPerfProvider_HyperVLegacyNetworkAdapter struct { FramesSentPersec uint64 } -func (c *Collector) collectVmEthernet(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectVmEthernet(ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_EthernetPerfProvider_HyperVLegacyNetworkAdapter - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_EthernetPerfProvider_HyperVLegacyNetworkAdapter", &dst); err != nil { return err } @@ -1531,10 +1530,9 @@ type Win32_PerfRawData_Counters_HyperVVirtualStorageDevice struct { WriteOperationsPerSec uint64 } -func (c *Collector) collectVmStorage(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectVmStorage(ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_Counters_HyperVVirtualStorageDevice - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_Counters_HyperVVirtualStorageDevice", &dst); err != nil { return err } @@ -1600,10 +1598,9 @@ type Win32_PerfRawData_NvspNicStats_HyperVVirtualNetworkAdapter struct { PacketsSentPersec uint64 } -func (c *Collector) collectVmNetwork(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectVmNetwork(ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_NvspNicStats_HyperVVirtualNetworkAdapter - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_NvspNicStats_HyperVVirtualNetworkAdapter", &dst); err != nil { return err } @@ -1673,10 +1670,9 @@ type Win32_PerfRawData_BalancerStats_HyperVDynamicMemoryVM struct { RemovedMemory uint64 } -func (c *Collector) collectVmMemory(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectVmMemory(ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_BalancerStats_HyperVDynamicMemoryVM - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_BalancerStats_HyperVDynamicMemoryVM", &dst); err != nil { return err } diff --git a/pkg/collector/iis/iis.go b/pkg/collector/iis/iis.go index db40ccc4..cc7d43de 100644 --- a/pkg/collector/iis/iis.go +++ b/pkg/collector/iis/iis.go @@ -14,6 +14,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/perflib" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" "golang.org/x/sys/windows/registry" ) @@ -262,7 +263,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(logger log.Logger) error { +func (c *Collector) Build(logger log.Logger, _ *wmi.Client) error { logger = log.With(logger, "collector", Name) c.iisVersion = getIISVersion(logger) diff --git a/pkg/collector/license/license.go b/pkg/collector/license/license.go index 692d7048..74abb3e4 100644 --- a/pkg/collector/license/license.go +++ b/pkg/collector/license/license.go @@ -9,6 +9,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/headers/slc" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "license" @@ -60,7 +61,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error { c.licenseStatus = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "status"), "Status of windows license", diff --git a/pkg/collector/logical_disk/logical_disk.go b/pkg/collector/logical_disk/logical_disk.go index 6e86c61a..b12a9658 100644 --- a/pkg/collector/logical_disk/logical_disk.go +++ b/pkg/collector/logical_disk/logical_disk.go @@ -16,6 +16,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/perflib" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" "golang.org/x/sys/windows" ) @@ -131,7 +132,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error { c.information = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "info"), "A metric with a constant '1' value labeled with logical disk information", diff --git a/pkg/collector/logon/logon.go b/pkg/collector/logon/logon.go index e8e9258e..4bed7291 100644 --- a/pkg/collector/logon/logon.go +++ b/pkg/collector/logon/logon.go @@ -9,8 +9,8 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "logon" @@ -21,7 +21,8 @@ var ConfigDefaults = Config{} // A Collector is a Prometheus Collector for WMI metrics. type Collector struct { - config Config + config Config + wmiClient *wmi.Client logonType *prometheus.Desc } @@ -54,7 +55,12 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error { + if wmiClient == nil || wmiClient.SWbemServicesClient == nil { + return errors.New("wmiClient or SWbemServicesClient is nil") + } + + c.wmiClient = wmiClient c.logonType = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "logon_type"), "Number of active logon sessions (LogonSession.LogonType)", @@ -68,7 +74,7 @@ func (c *Collector) Build(_ log.Logger) error { // to the provided prometheus Metric channel. func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error { logger = log.With(logger, "collector", Name) - if err := c.collect(logger, ch); err != nil { + if err := c.collect(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting user metrics", "err", err) return err } @@ -81,10 +87,9 @@ type Win32_LogonSession struct { LogonType uint32 } -func (c *Collector) collect(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collect(ch chan<- prometheus.Metric) error { var dst []Win32_LogonSession - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_LogonSession", &dst); err != nil { return err } if len(dst) == 0 { diff --git a/pkg/collector/map.go b/pkg/collector/map.go index 2a6d08a1..715a579d 100644 --- a/pkg/collector/map.go +++ b/pkg/collector/map.go @@ -1,6 +1,7 @@ package collector import ( + "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/pkg/collector/ad" "github.com/prometheus-community/windows_exporter/pkg/collector/adcs" "github.com/prometheus-community/windows_exporter/pkg/collector/adfs" @@ -56,6 +57,12 @@ import ( "golang.org/x/exp/maps" ) +func NewBuilderWithFlags[C Collector](fn BuilderWithFlags[C]) BuilderWithFlags[Collector] { + return func(app *kingpin.Application) Collector { + return fn(app) + } +} + var BuildersWithFlags = map[string]BuilderWithFlags[Collector]{ ad.Name: NewBuilderWithFlags(ad.NewWithFlags), adcs.Name: NewBuilderWithFlags(adcs.NewWithFlags), diff --git a/pkg/collector/memory/memory.go b/pkg/collector/memory/memory.go index ca9d6bbf..96157f53 100644 --- a/pkg/collector/memory/memory.go +++ b/pkg/collector/memory/memory.go @@ -12,6 +12,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/perflib" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "memory" @@ -86,7 +87,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error { c.availableBytes = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "available_bytes"), "The amount of physical memory immediately available for allocation to a process or for system use. It is equal to the sum of memory assigned to"+ diff --git a/pkg/collector/mscluster/mscluster.go b/pkg/collector/mscluster/mscluster.go index 50e5580a..16b99930 100644 --- a/pkg/collector/mscluster/mscluster.go +++ b/pkg/collector/mscluster/mscluster.go @@ -10,6 +10,7 @@ import ( "github.com/go-kit/log" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "mscluster" @@ -30,7 +31,8 @@ var ConfigDefaults = Config{ // A Collector is a Prometheus Collector for WMI MSCluster_Cluster metrics. type Collector struct { - config Config + config Config + wmiClient *wmi.Client // cluster clusterAddEvictDelay *prometheus.Desc @@ -219,11 +221,17 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error { if len(c.config.CollectorsEnabled) == 0 { return nil } + if wmiClient == nil || wmiClient.SWbemServicesClient == nil { + return errors.New("wmiClient or SWbemServicesClient is nil") + } + + c.wmiClient = wmiClient + if slices.Contains(c.config.CollectorsEnabled, "cluster") { c.buildCluster() } @@ -249,8 +257,7 @@ func (c *Collector) Build(_ log.Logger) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error { - logger = log.With(logger, "collector", Name) +func (c *Collector) Collect(_ *types.ScrapeContext, _ log.Logger, ch chan<- prometheus.Metric) error { if len(c.config.CollectorsEnabled) == 0 { return nil } @@ -262,31 +269,31 @@ func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- ) if slices.Contains(c.config.CollectorsEnabled, "cluster") { - if err = c.collectCluster(logger, ch); err != nil { + if err = c.collectCluster(ch); err != nil { errs = append(errs, fmt.Errorf("failed to collect cluster metrics: %w", err)) } } if slices.Contains(c.config.CollectorsEnabled, "network") { - if err = c.collectNetwork(logger, ch); err != nil { + if err = c.collectNetwork(ch); err != nil { errs = append(errs, fmt.Errorf("failed to collect network metrics: %w", err)) } } if slices.Contains(c.config.CollectorsEnabled, "node") { - if nodeNames, err = c.collectNode(logger, ch); err != nil { + if nodeNames, err = c.collectNode(ch); err != nil { errs = append(errs, fmt.Errorf("failed to collect node metrics: %w", err)) } } if slices.Contains(c.config.CollectorsEnabled, "resource") { - if err = c.collectResource(logger, ch, nodeNames); err != nil { + if err = c.collectResource(ch, nodeNames); err != nil { errs = append(errs, fmt.Errorf("failed to collect resource metrics: %w", err)) } } if slices.Contains(c.config.CollectorsEnabled, "resourcegroup") { - if err = c.collectResourceGroup(logger, ch, nodeNames); err != nil { + if err = c.collectResourceGroup(ch, nodeNames); err != nil { errs = append(errs, fmt.Errorf("failed to collect resource group metrics: %w", err)) } } diff --git a/pkg/collector/mscluster/mscluster_cluster.go b/pkg/collector/mscluster/mscluster_cluster.go index 38ea1575..9e1c4cc3 100644 --- a/pkg/collector/mscluster/mscluster_cluster.go +++ b/pkg/collector/mscluster/mscluster_cluster.go @@ -1,9 +1,7 @@ package mscluster import ( - "github.com/go-kit/log" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" ) @@ -558,10 +556,9 @@ func (c *Collector) buildCluster() { ) } -func (c *Collector) collectCluster(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectCluster(ch chan<- prometheus.Metric) error { var dst []msClusterCluster - q := wmi.QueryAllForClass(&dst, "MSCluster_Cluster", logger) - if err := wmi.QueryNamespace(q, &dst, "root/MSCluster"); err != nil { + if err := c.wmiClient.Query("SELECT * FROM MSCluster_Cluster", &dst, nil, "root/MSCluster"); err != nil { return err } diff --git a/pkg/collector/mscluster/mscluster_network.go b/pkg/collector/mscluster/mscluster_network.go index 024b1a72..dce24022 100644 --- a/pkg/collector/mscluster/mscluster_network.go +++ b/pkg/collector/mscluster/mscluster_network.go @@ -1,9 +1,7 @@ package mscluster import ( - "github.com/go-kit/log" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" ) @@ -56,11 +54,10 @@ func (c *Collector) buildNetwork() { // Collect sends the metric values for each metric // to the provided prometheus metric channel. -func (c *Collector) collectNetwork(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectNetwork(ch chan<- prometheus.Metric) error { var dst []msClusterNetwork - q := wmi.QueryAllForClass(&dst, "MSCluster_Network", logger) - if err := wmi.QueryNamespace(q, &dst, "root/MSCluster"); err != nil { + if err := c.wmiClient.Query("SELECT * FROM MSCluster_Network", &dst, nil, "root/MSCluster"); err != nil { return err } diff --git a/pkg/collector/mscluster/mscluster_node.go b/pkg/collector/mscluster/mscluster_node.go index ec7942ef..5c7ddf14 100644 --- a/pkg/collector/mscluster/mscluster_node.go +++ b/pkg/collector/mscluster/mscluster_node.go @@ -1,9 +1,7 @@ package mscluster import ( - "github.com/go-kit/log" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" ) @@ -119,11 +117,10 @@ func (c *Collector) buildNode() { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) collectNode(logger log.Logger, ch chan<- prometheus.Metric) ([]string, error) { +func (c *Collector) collectNode(ch chan<- prometheus.Metric) ([]string, error) { var dst []msClusterNode - q := wmi.QueryAllForClass(&dst, "MSCluster_Node", logger) - if err := wmi.QueryNamespace(q, &dst, "root/MSCluster"); err != nil { + if err := c.wmiClient.Query("SELECT * FROM MSCluster_Node", &dst, nil, "root/MSCluster"); err != nil { return nil, err } diff --git a/pkg/collector/mscluster/mscluster_resource.go b/pkg/collector/mscluster/mscluster_resource.go index 323c3a01..d32efca3 100644 --- a/pkg/collector/mscluster/mscluster_resource.go +++ b/pkg/collector/mscluster/mscluster_resource.go @@ -1,9 +1,7 @@ package mscluster import ( - "github.com/go-kit/log" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" ) @@ -148,11 +146,10 @@ func (c *Collector) buildResource() { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) collectResource(logger log.Logger, ch chan<- prometheus.Metric, nodeNames []string) error { +func (c *Collector) collectResource(ch chan<- prometheus.Metric, nodeNames []string) error { var dst []msClusterResource - q := wmi.QueryAllForClass(&dst, "MSCluster_Resource", logger) - if err := wmi.QueryNamespace(q, &dst, "root/MSCluster"); err != nil { + if err := c.wmiClient.Query("SELECT * FROM MSCluster_Resource", &dst, nil, "root/MSCluster"); err != nil { return err } diff --git a/pkg/collector/mscluster/mscluster_resourcegroup.go b/pkg/collector/mscluster/mscluster_resourcegroup.go index 78030f05..b40f7c4d 100644 --- a/pkg/collector/mscluster/mscluster_resourcegroup.go +++ b/pkg/collector/mscluster/mscluster_resourcegroup.go @@ -1,9 +1,7 @@ package mscluster import ( - "github.com/go-kit/log" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" ) @@ -125,11 +123,10 @@ func (c *Collector) buildResourceGroup() { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) collectResourceGroup(logger log.Logger, ch chan<- prometheus.Metric, nodeNames []string) error { +func (c *Collector) collectResourceGroup(ch chan<- prometheus.Metric, nodeNames []string) error { var dst []msClusterResourceGroup - q := wmi.QueryAllForClass(&dst, "MSCluster_ResourceGroup", logger) - if err := wmi.QueryNamespace(q, &dst, "root/MSCluster"); err != nil { + if err := c.wmiClient.Query("SELECT * FROM MSCluster_ResourceGroup", &dst, nil, "root/MSCluster"); err != nil { return err } diff --git a/pkg/collector/msmq/msmq.go b/pkg/collector/msmq/msmq.go index 74e7a167..b2043da7 100644 --- a/pkg/collector/msmq/msmq.go +++ b/pkg/collector/msmq/msmq.go @@ -3,6 +3,7 @@ package msmq import ( + "errors" "strings" "github.com/alecthomas/kingpin/v2" @@ -10,8 +11,8 @@ import ( "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus-community/windows_exporter/pkg/utils" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "msmq" @@ -26,7 +27,8 @@ var ConfigDefaults = Config{ // A Collector is a Prometheus Collector for WMI Win32_PerfRawData_MSMQ_MSMQQueue metrics. type Collector struct { - config Config + config Config + wmiClient *wmi.Client bytesInJournalQueue *prometheus.Desc bytesInQueue *prometheus.Desc @@ -74,9 +76,15 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(logger log.Logger) error { +func (c *Collector) Build(logger log.Logger, wmiClient *wmi.Client) error { logger = log.With(logger, "collector", Name) + if wmiClient == nil || wmiClient.SWbemServicesClient == nil { + return errors.New("wmiClient or SWbemServicesClient is nil") + } + + c.wmiClient = wmiClient + if *c.config.QueryWhereClause == "" { _ = level.Warn(logger).Log("msg", "No where-clause specified for msmq collector. This will generate a very large number of metrics!") } @@ -112,7 +120,7 @@ func (c *Collector) Build(logger log.Logger) error { // to the provided prometheus Metric channel. func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error { logger = log.With(logger, "collector", Name) - if err := c.collect(logger, ch); err != nil { + if err := c.collect(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting msmq metrics", "err", err) return err } @@ -128,11 +136,15 @@ type msmqQueue struct { MessagesInQueue uint64 } -func (c *Collector) collect(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collect(ch chan<- prometheus.Metric) error { var dst []msmqQueue - q := wmi.QueryAllForClassWhere(&dst, "Win32_PerfRawData_MSMQ_MSMQQueue", *c.config.QueryWhereClause, logger) - if err := wmi.Query(q, &dst); err != nil { + query := "SELECT * FROM Win32_PerfRawData_MSMQ_MSMQQueue" + if *c.config.QueryWhereClause != "" { + query += " WHERE " + *c.config.QueryWhereClause + } + + if err := c.wmiClient.Query(query, &dst); err != nil { return err } diff --git a/pkg/collector/mssql/mssql.go b/pkg/collector/mssql/mssql.go index 580acbef..4bb97585 100644 --- a/pkg/collector/mssql/mssql.go +++ b/pkg/collector/mssql/mssql.go @@ -17,6 +17,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/perflib" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" "golang.org/x/sys/windows/registry" ) @@ -494,7 +495,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error { // Result must order, to prevent test failures. sort.Strings(c.config.CollectorsEnabled) diff --git a/pkg/collector/net/net.go b/pkg/collector/net/net.go index 9aa7f050..983134cb 100644 --- a/pkg/collector/net/net.go +++ b/pkg/collector/net/net.go @@ -12,6 +12,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/perflib" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "net" @@ -115,7 +116,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error { c.bytesReceivedTotal = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "bytes_received_total"), "(Network.BytesReceivedPerSec)", diff --git a/pkg/collector/netframework_clrexceptions/netframework_clrexceptions.go b/pkg/collector/netframework_clrexceptions/netframework_clrexceptions.go index 1e9933d2..8543a880 100644 --- a/pkg/collector/netframework_clrexceptions/netframework_clrexceptions.go +++ b/pkg/collector/netframework_clrexceptions/netframework_clrexceptions.go @@ -3,12 +3,14 @@ package netframework_clrexceptions import ( + "errors" + "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "netframework_clrexceptions" @@ -19,7 +21,8 @@ var ConfigDefaults = Config{} // A Collector is a Prometheus Collector for WMI Win32_PerfRawData_NETFramework_NETCLRExceptions metrics. type Collector struct { - config Config + config Config + wmiClient *wmi.Client numberOfExceptionsThrown *prometheus.Desc numberOfFilters *prometheus.Desc @@ -55,7 +58,12 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error { + if wmiClient == nil || wmiClient.SWbemServicesClient == nil { + return errors.New("wmiClient or SWbemServicesClient is nil") + } + + c.wmiClient = wmiClient c.numberOfExceptionsThrown = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "exceptions_thrown_total"), "Displays the total number of exceptions thrown since the application started. This includes both .NET exceptions and unmanaged exceptions that are converted into .NET exceptions.", @@ -87,7 +95,7 @@ func (c *Collector) Build(_ log.Logger) error { // to the provided prometheus Metric channel. func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error { logger = log.With(logger, "collector", Name) - if err := c.collect(logger, ch); err != nil { + if err := c.collect(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting win32_perfrawdata_netframework_netclrexceptions metrics", "err", err) return err } @@ -104,10 +112,9 @@ type Win32_PerfRawData_NETFramework_NETCLRExceptions struct { ThrowToCatchDepthPersec uint32 } -func (c *Collector) collect(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collect(ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_NETFramework_NETCLRExceptions - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRExceptions", &dst); err != nil { return err } diff --git a/pkg/collector/netframework_clrinterop/netframework_clrinterop.go b/pkg/collector/netframework_clrinterop/netframework_clrinterop.go index bec6f6af..e1ad3a47 100644 --- a/pkg/collector/netframework_clrinterop/netframework_clrinterop.go +++ b/pkg/collector/netframework_clrinterop/netframework_clrinterop.go @@ -3,12 +3,14 @@ package netframework_clrinterop import ( + "errors" + "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "netframework_clrinterop" @@ -19,7 +21,8 @@ var ConfigDefaults = Config{} // A Collector is a Prometheus Collector for WMI Win32_PerfRawData_NETFramework_NETCLRInterop metrics. type Collector struct { - config Config + config Config + wmiClient *wmi.Client numberOfCCWs *prometheus.Desc numberOfMarshalling *prometheus.Desc @@ -54,7 +57,12 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error { + if wmiClient == nil || wmiClient.SWbemServicesClient == nil { + return errors.New("wmiClient or SWbemServicesClient is nil") + } + + c.wmiClient = wmiClient c.numberOfCCWs = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "com_callable_wrappers_total"), "Displays the current number of COM callable wrappers (CCWs). A CCW is a proxy for a managed object being referenced from an unmanaged COM client.", @@ -80,7 +88,7 @@ func (c *Collector) Build(_ log.Logger) error { // to the provided prometheus Metric channel. func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error { logger = log.With(logger, "collector", Name) - if err := c.collect(logger, ch); err != nil { + if err := c.collect(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting win32_perfrawdata_netframework_netclrinterop metrics", "err", err) return err } @@ -97,10 +105,9 @@ type Win32_PerfRawData_NETFramework_NETCLRInterop struct { NumberofTLBimportsPersec uint32 } -func (c *Collector) collect(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collect(ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_NETFramework_NETCLRInterop - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRInterop", &dst); err != nil { return err } diff --git a/pkg/collector/netframework_clrjit/netframework_clrjit.go b/pkg/collector/netframework_clrjit/netframework_clrjit.go index 2ee83c5e..7037f22f 100644 --- a/pkg/collector/netframework_clrjit/netframework_clrjit.go +++ b/pkg/collector/netframework_clrjit/netframework_clrjit.go @@ -7,8 +7,8 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "netframework_clrjit" @@ -19,7 +19,8 @@ var ConfigDefaults = Config{} // A Collector is a Prometheus Collector for WMI Win32_PerfRawData_NETFramework_NETCLRJit metrics. type Collector struct { - config Config + config Config + wmiClient *wmi.Client numberOfMethodsJitted *prometheus.Desc timeInJit *prometheus.Desc @@ -55,7 +56,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error { c.numberOfMethodsJitted = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "jit_methods_total"), "Displays the total number of methods JIT-compiled since the application started. This counter does not include pre-JIT-compiled methods.", @@ -87,7 +88,7 @@ func (c *Collector) Build(_ log.Logger) error { // to the provided prometheus Metric channel. func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error { logger = log.With(logger, "collector", Name) - if err := c.collect(logger, ch); err != nil { + if err := c.collect(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting win32_perfrawdata_netframework_netclrjit metrics", "err", err) return err } @@ -106,10 +107,9 @@ type Win32_PerfRawData_NETFramework_NETCLRJit struct { TotalNumberofILBytesJitted uint32 } -func (c *Collector) collect(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collect(ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_NETFramework_NETCLRJit - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRJit", &dst); err != nil { return err } diff --git a/pkg/collector/netframework_clrloading/netframework_clrloading.go b/pkg/collector/netframework_clrloading/netframework_clrloading.go index a1d2de06..923c046e 100644 --- a/pkg/collector/netframework_clrloading/netframework_clrloading.go +++ b/pkg/collector/netframework_clrloading/netframework_clrloading.go @@ -3,12 +3,14 @@ package netframework_clrloading import ( + "errors" + "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "netframework_clrloading" @@ -19,7 +21,8 @@ var ConfigDefaults = Config{} // A Collector is a Prometheus Collector for WMI Win32_PerfRawData_NETFramework_NETCLRLoading metrics. type Collector struct { - config Config + config Config + wmiClient *wmi.Client bytesInLoaderHeap *prometheus.Desc currentAppDomains *prometheus.Desc @@ -60,7 +63,13 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error { + if wmiClient == nil || wmiClient.SWbemServicesClient == nil { + return errors.New("wmiClient or SWbemServicesClient is nil") + } + + c.wmiClient = wmiClient + c.bytesInLoaderHeap = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "loader_heap_size_bytes"), "Displays the current size, in bytes, of the memory committed by the class loader across all application domains. Committed memory is the physical space reserved in the disk paging file.", @@ -122,7 +131,7 @@ func (c *Collector) Build(_ log.Logger) error { // to the provided prometheus Metric channel. func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error { logger = log.With(logger, "collector", Name) - if err := c.collect(logger, ch); err != nil { + if err := c.collect(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting win32_perfrawdata_netframework_netclrloading metrics", "err", err) return err } @@ -150,10 +159,9 @@ type Win32_PerfRawData_NETFramework_NETCLRLoading struct { TotalNumberofLoadFailures uint32 } -func (c *Collector) collect(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collect(ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_NETFramework_NETCLRLoading - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRLoading", &dst); err != nil { return err } diff --git a/pkg/collector/netframework_clrlocksandthreads/netframework_clrlocksandthreads.go b/pkg/collector/netframework_clrlocksandthreads/netframework_clrlocksandthreads.go index 1a96e067..a0073b78 100644 --- a/pkg/collector/netframework_clrlocksandthreads/netframework_clrlocksandthreads.go +++ b/pkg/collector/netframework_clrlocksandthreads/netframework_clrlocksandthreads.go @@ -3,12 +3,14 @@ package netframework_clrlocksandthreads import ( + "errors" + "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "netframework_clrlocksandthreads" @@ -19,7 +21,8 @@ var ConfigDefaults = Config{} // A Collector is a Prometheus Collector for WMI Win32_PerfRawData_NETFramework_NETCLRLocksAndThreads metrics. type Collector struct { - config Config + config Config + wmiClient *wmi.Client currentQueueLength *prometheus.Desc numberOfCurrentLogicalThreads *prometheus.Desc @@ -58,7 +61,13 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error { + if wmiClient == nil || wmiClient.SWbemServicesClient == nil { + return errors.New("wmiClient or SWbemServicesClient is nil") + } + + c.wmiClient = wmiClient + c.currentQueueLength = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "current_queue_length"), "Displays the total number of threads that are currently waiting to acquire a managed lock in the application.", @@ -108,7 +117,7 @@ func (c *Collector) Build(_ log.Logger) error { // to the provided prometheus Metric channel. func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error { logger = log.With(logger, "collector", Name) - if err := c.collect(logger, ch); err != nil { + if err := c.collect(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting win32_perfrawdata_netframework_netclrlocksandthreads metrics", "err", err) return err } @@ -130,10 +139,9 @@ type Win32_PerfRawData_NETFramework_NETCLRLocksAndThreads struct { TotalNumberofContentions uint32 } -func (c *Collector) collect(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collect(ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_NETFramework_NETCLRLocksAndThreads - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRLocksAndThreads", &dst); err != nil { return err } diff --git a/pkg/collector/netframework_clrmemory/netframework_clrmemory.go b/pkg/collector/netframework_clrmemory/netframework_clrmemory.go index 5a3932c8..dc6b3b2f 100644 --- a/pkg/collector/netframework_clrmemory/netframework_clrmemory.go +++ b/pkg/collector/netframework_clrmemory/netframework_clrmemory.go @@ -3,12 +3,14 @@ package netframework_clrmemory import ( + "errors" + "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "netframework_clrmemory" @@ -19,7 +21,8 @@ var ConfigDefaults = Config{} // A Collector is a Prometheus Collector for WMI Win32_PerfRawData_NETFramework_NETCLRMemory metrics. type Collector struct { - config Config + config Config + wmiClient *wmi.Client allocatedBytes *prometheus.Desc finalizationSurvivors *prometheus.Desc @@ -63,7 +66,13 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error { + if wmiClient == nil || wmiClient.SWbemServicesClient == nil { + return errors.New("wmiClient or SWbemServicesClient is nil") + } + + c.wmiClient = wmiClient + c.allocatedBytes = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "allocated_bytes_total"), "Displays the total number of bytes allocated on the garbage collection heap.", @@ -143,7 +152,7 @@ func (c *Collector) Build(_ log.Logger) error { // to the provided prometheus Metric channel. func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error { logger = log.With(logger, "collector", Name) - if err := c.collect(logger, ch); err != nil { + if err := c.collect(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting win32_perfrawdata_netframework_netclrmemory metrics", "err", err) return err } @@ -184,10 +193,9 @@ type Win32_PerfRawData_NETFramework_NETCLRMemory struct { PromotedMemoryfromGen1 uint64 } -func (c *Collector) collect(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collect(ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_NETFramework_NETCLRMemory - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRMemory", &dst); err != nil { return err } diff --git a/pkg/collector/netframework_clrremoting/netframework_clrremoting.go b/pkg/collector/netframework_clrremoting/netframework_clrremoting.go index b8179907..81d36cb9 100644 --- a/pkg/collector/netframework_clrremoting/netframework_clrremoting.go +++ b/pkg/collector/netframework_clrremoting/netframework_clrremoting.go @@ -3,12 +3,14 @@ package netframework_clrremoting import ( + "errors" + "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "netframework_clrremoting" @@ -19,7 +21,8 @@ var ConfigDefaults = Config{} // A Collector is a Prometheus Collector for WMI Win32_PerfRawData_NETFramework_NETCLRRemoting metrics. type Collector struct { - config Config + config Config + wmiClient *wmi.Client channels *prometheus.Desc contextBoundClassesLoaded *prometheus.Desc @@ -57,7 +60,13 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error { + if wmiClient == nil || wmiClient.SWbemServicesClient == nil { + return errors.New("wmiClient or SWbemServicesClient is nil") + } + + c.wmiClient = wmiClient + c.channels = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "channels_total"), "Displays the total number of remoting channels registered across all application domains since application started.", @@ -101,7 +110,7 @@ func (c *Collector) Build(_ log.Logger) error { // to the provided prometheus Metric channel. func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error { logger = log.With(logger, "collector", Name) - if err := c.collect(logger, ch); err != nil { + if err := c.collect(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting win32_perfrawdata_netframework_netclrremoting metrics", "err", err) return err } @@ -120,10 +129,9 @@ type Win32_PerfRawData_NETFramework_NETCLRRemoting struct { TotalRemoteCalls uint32 } -func (c *Collector) collect(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collect(ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_NETFramework_NETCLRRemoting - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRRemoting", &dst); err != nil { return err } diff --git a/pkg/collector/netframework_clrsecurity/netframework_clrsecurity.go b/pkg/collector/netframework_clrsecurity/netframework_clrsecurity.go index 46369057..76cf5050 100644 --- a/pkg/collector/netframework_clrsecurity/netframework_clrsecurity.go +++ b/pkg/collector/netframework_clrsecurity/netframework_clrsecurity.go @@ -3,12 +3,14 @@ package netframework_clrsecurity import ( + "errors" + "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "netframework_clrsecurity" @@ -19,7 +21,8 @@ var ConfigDefaults = Config{} // A Collector is a Prometheus Collector for WMI Win32_PerfRawData_NETFramework_NETCLRSecurity metrics. type Collector struct { - config Config + config Config + wmiClient *wmi.Client numberLinkTimeChecks *prometheus.Desc timeInRTChecks *prometheus.Desc @@ -55,7 +58,12 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error { + if wmiClient == nil || wmiClient.SWbemServicesClient == nil { + return errors.New("wmiClient or SWbemServicesClient is nil") + } + + c.wmiClient = wmiClient c.numberLinkTimeChecks = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "link_time_checks_total"), "Displays the total number of link-time code access security checks since the application started.", @@ -87,7 +95,7 @@ func (c *Collector) Build(_ log.Logger) error { // to the provided prometheus Metric channel. func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error { logger = log.With(logger, "collector", Name) - if err := c.collect(logger, ch); err != nil { + if err := c.collect(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting win32_perfrawdata_netframework_netclrsecurity metrics", "err", err) return err } @@ -105,10 +113,9 @@ type Win32_PerfRawData_NETFramework_NETCLRSecurity struct { TotalRuntimeChecks uint32 } -func (c *Collector) collect(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collect(ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_NETFramework_NETCLRSecurity - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRSecurity", &dst); err != nil { return err } diff --git a/pkg/collector/nps/nps.go b/pkg/collector/nps/nps.go index 002aee12..78f6b231 100644 --- a/pkg/collector/nps/nps.go +++ b/pkg/collector/nps/nps.go @@ -1,14 +1,15 @@ package nps import ( + "errors" "fmt" "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "nps" @@ -19,7 +20,8 @@ var ConfigDefaults = Config{} // Collector is a Prometheus Collector for WMI Win32_PerfRawData_IAS_NPSAuthenticationServer and Win32_PerfRawData_IAS_NPSAccountingServer metrics. type Collector struct { - config Config + config Config + wmiClient *wmi.Client accessAccepts *prometheus.Desc accessChallenges *prometheus.Desc @@ -77,7 +79,12 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error { + if wmiClient == nil || wmiClient.SWbemServicesClient == nil { + return errors.New("wmiClient or SWbemServicesClient is nil") + } + + c.wmiClient = wmiClient c.accessAccepts = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "access_accepts"), "(AccessAccepts)", @@ -236,11 +243,11 @@ func (c *Collector) Build(_ log.Logger) error { // to the provided prometheus Metric channel. func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error { logger = log.With(logger, "collector", Name) - if err := c.CollectAccept(logger, ch); err != nil { + if err := c.CollectAccept(ch); err != nil { _ = level.Error(logger).Log("msg", fmt.Sprintf("failed collecting NPS accept data: %s", err)) return err } - if err := c.CollectAccounting(logger, ch); err != nil { + if err := c.CollectAccounting(ch); err != nil { _ = level.Error(logger).Log("msg", fmt.Sprintf("failed collecting NPS accounting data: %s", err)) return err } @@ -286,10 +293,9 @@ type Win32_PerfRawData_IAS_NPSAccountingServer struct { // CollectAccept sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) CollectAccept(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) CollectAccept(ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_IAS_NPSAuthenticationServer - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_IAS_NPSAuthenticationServer", &dst); err != nil { return err } @@ -374,10 +380,9 @@ func (c *Collector) CollectAccept(logger log.Logger, ch chan<- prometheus.Metric return nil } -func (c *Collector) CollectAccounting(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) CollectAccounting(ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_IAS_NPSAccountingServer - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_IAS_NPSAccountingServer", &dst); err != nil { return err } diff --git a/pkg/collector/os/os.go b/pkg/collector/os/os.go index b6cf064e..531010c7 100644 --- a/pkg/collector/os/os.go +++ b/pkg/collector/os/os.go @@ -21,6 +21,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/perflib" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" "golang.org/x/sys/windows/registry" ) @@ -83,7 +84,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error { c.osInformation = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "info"), "OperatingSystem.Caption, OperatingSystem.Version", diff --git a/pkg/collector/physical_disk/physical_disk.go b/pkg/collector/physical_disk/physical_disk.go index 37d094d7..d762fcd5 100644 --- a/pkg/collector/physical_disk/physical_disk.go +++ b/pkg/collector/physical_disk/physical_disk.go @@ -13,6 +13,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/perflib" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "physical_disk" @@ -113,7 +114,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error { c.requestsQueued = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "requests_queued"), "The number of requests queued to the disk (PhysicalDisk.CurrentDiskQueueLength)", diff --git a/pkg/collector/printer/printer.go b/pkg/collector/printer/printer.go index a9b274a2..b3b1d61b 100644 --- a/pkg/collector/printer/printer.go +++ b/pkg/collector/printer/printer.go @@ -3,6 +3,7 @@ package printer import ( + "errors" "fmt" "regexp" "strings" @@ -11,8 +12,8 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "printer" @@ -39,7 +40,8 @@ var ConfigDefaults = Config{ } type Collector struct { - config Config + config Config + wmiClient *wmi.Client printerStatus *prometheus.Desc printerJobStatus *prometheus.Desc @@ -106,7 +108,13 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error { + if wmiClient == nil || wmiClient.SWbemServicesClient == nil { + return errors.New("wmiClient or SWbemServicesClient is nil") + } + + c.wmiClient = wmiClient + c.printerJobStatus = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "job_status"), "A counter of printer jobs by status", @@ -147,12 +155,12 @@ type wmiPrintJob struct { func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error { logger = log.With(logger, "collector", Name) - if err := c.collectPrinterStatus(logger, ch); err != nil { + if err := c.collectPrinterStatus(ch); err != nil { _ = level.Error(logger).Log("msg", "failed to collect printer status metrics", "err", err) return err } - if err := c.collectPrinterJobStatus(logger, ch); err != nil { + if err := c.collectPrinterJobStatus(ch); err != nil { _ = level.Error(logger).Log("msg", "failed to collect printer job status metrics", "err", err) return err } @@ -160,11 +168,9 @@ func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- return nil } -func (c *Collector) collectPrinterStatus(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectPrinterStatus(ch chan<- prometheus.Metric) error { var printers []wmiPrinter - - q := wmi.QueryAllForClass(&printers, "win32_Printer", logger) - if err := wmi.Query(q, &printers); err != nil { + if err := c.wmiClient.Query("SELECT * FROM win32_Printer", &printers); err != nil { return err } @@ -200,11 +206,9 @@ func (c *Collector) collectPrinterStatus(logger log.Logger, ch chan<- prometheus return nil } -func (c *Collector) collectPrinterJobStatus(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectPrinterJobStatus(ch chan<- prometheus.Metric) error { var printJobs []wmiPrintJob - - q := wmi.QueryAllForClass(&printJobs, "win32_PrintJob", logger) - if err := wmi.Query(q, &printJobs); err != nil { + if err := c.wmiClient.Query("SELECT * FROM win32_PrintJob", &printJobs); err != nil { return err } diff --git a/pkg/collector/process/process.go b/pkg/collector/process/process.go index b7ce22bf..980de07c 100644 --- a/pkg/collector/process/process.go +++ b/pkg/collector/process/process.go @@ -15,8 +15,8 @@ import ( "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/perflib" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" "golang.org/x/sys/windows" ) @@ -37,7 +37,8 @@ var ConfigDefaults = Config{ } type Collector struct { - config Config + config Config + wmiClient *wmi.Client lookupCache map[string]string @@ -136,9 +137,15 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(logger log.Logger) error { +func (c *Collector) Build(logger log.Logger, wmiClient *wmi.Client) error { logger = log.With(logger, "collector", Name) + if wmiClient == nil || wmiClient.SWbemServicesClient == nil { + return errors.New("wmiClient or SWbemServicesClient is nil") + } + + c.wmiClient = wmiClient + if c.config.ProcessInclude.String() == "^(?:.*)$" && c.config.ProcessExclude.String() == "^(?:)$" { _ = level.Warn(logger).Log("msg", "No filters specified for process collector. This will generate a very large number of metrics!") } @@ -291,8 +298,7 @@ func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan var workerProcesses []WorkerProcess if c.config.EnableWorkerProcess { - queryWorkerProcess := wmi.QueryAllForClass(&workerProcesses, "WorkerProcess", logger) - if err := wmi.QueryNamespace(queryWorkerProcess, &workerProcesses, "root\\WebAdministration"); err != nil { + if err := c.wmiClient.Query("SELECT * FROM WorkerProcess", &workerProcesses, nil, "root\\WebAdministration"); err != nil { _ = level.Debug(logger).Log("msg", "Could not query WebAdministration namespace for IIS worker processes", "err", err) } } diff --git a/pkg/collector/remote_fx/remote_fx.go b/pkg/collector/remote_fx/remote_fx.go index d02acee1..146a129c 100644 --- a/pkg/collector/remote_fx/remote_fx.go +++ b/pkg/collector/remote_fx/remote_fx.go @@ -12,6 +12,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus-community/windows_exporter/pkg/utils" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "remote_fx" @@ -81,7 +82,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(log.Logger, *wmi.Client) error { // net c.baseTCPRTT = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "net_base_tcp_rtt_seconds"), diff --git a/pkg/collector/scheduled_task/scheduled_task.go b/pkg/collector/scheduled_task/scheduled_task.go index 019cdf44..c53598b5 100644 --- a/pkg/collector/scheduled_task/scheduled_task.go +++ b/pkg/collector/scheduled_task/scheduled_task.go @@ -16,6 +16,7 @@ import ( "github.com/go-ole/go-ole/oleutil" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "scheduled_task" @@ -136,7 +137,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error { c.lastResult = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "last_result"), "The result that was returned the last time the registered task was run", diff --git a/pkg/collector/service/service.go b/pkg/collector/service/service.go index 1bb141ca..8442569a 100644 --- a/pkg/collector/service/service.go +++ b/pkg/collector/service/service.go @@ -15,8 +15,8 @@ import ( "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus-community/windows_exporter/pkg/utils" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" "golang.org/x/sys/windows" "golang.org/x/sys/windows/svc/mgr" ) @@ -41,6 +41,8 @@ type Collector struct { useAPI *bool v2 *bool + wmiClient *wmi.Client + Information *prometheus.Desc State *prometheus.Desc StartMode *prometheus.Desc @@ -90,7 +92,13 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(logger log.Logger) error { +func (c *Collector) Build(logger log.Logger, wmiClient *wmi.Client) error { + if wmiClient == nil || wmiClient.SWbemServicesClient == nil { + return errors.New("wmiClient or SWbemServicesClient is nil") + } + + c.wmiClient = wmiClient + logger = log.With(logger, "collector", Name) if utils.IsEmpty(c.serviceWhereClause) { @@ -150,7 +158,7 @@ func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- _ = level.Error(logger).Log("msg", "failed collecting API service metrics:", "err", err) } default: - if err = c.collectWMI(logger, ch); err != nil { + if err = c.collectWMI(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting WMI service metrics:", "err", err) } } @@ -220,10 +228,15 @@ var ( } ) -func (c *Collector) collectWMI(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectWMI(ch chan<- prometheus.Metric) error { var dst []Win32_Service - q := wmi.QueryAllWhere(&dst, *c.serviceWhereClause, logger) //nolint:staticcheck - if err := wmi.Query(q, &dst); err != nil { + query := "SELECT * FROM Win32_Service" + + if *c.serviceWhereClause != "" { + query += " WHERE " + *c.serviceWhereClause + } + + if err := c.wmiClient.Query(query, &dst); err != nil { return err } for _, service := range dst { diff --git a/pkg/collector/smb/smb.go b/pkg/collector/smb/smb.go index baee2049..e2437110 100644 --- a/pkg/collector/smb/smb.go +++ b/pkg/collector/smb/smb.go @@ -11,6 +11,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/perflib" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "smb" @@ -56,7 +57,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error { // desc creates a new prometheus description desc := func(metricName string, description string, labels ...string) *prometheus.Desc { return prometheus.NewDesc( diff --git a/pkg/collector/smbclient/smbclient.go b/pkg/collector/smbclient/smbclient.go index 459d9e41..4a8e4f61 100644 --- a/pkg/collector/smbclient/smbclient.go +++ b/pkg/collector/smbclient/smbclient.go @@ -11,6 +11,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/perflib" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const ( @@ -78,7 +79,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error { // desc creates a new prometheus description desc := func(metricName string, description string, labels []string) *prometheus.Desc { return prometheus.NewDesc( diff --git a/pkg/collector/smtp/smtp.go b/pkg/collector/smtp/smtp.go index 1db47a9f..1134ea26 100644 --- a/pkg/collector/smtp/smtp.go +++ b/pkg/collector/smtp/smtp.go @@ -12,6 +12,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/perflib" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "smtp" @@ -141,7 +142,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(logger log.Logger) error { +func (c *Collector) Build(logger log.Logger, _ *wmi.Client) error { logger = log.With(logger, "collector", Name) _ = level.Info(logger).Log("msg", "smtp collector is in an experimental state! Metrics for this collector have not been tested.") diff --git a/pkg/collector/system/system.go b/pkg/collector/system/system.go index 611794f3..15620d53 100644 --- a/pkg/collector/system/system.go +++ b/pkg/collector/system/system.go @@ -9,6 +9,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/perflib" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "system" @@ -57,7 +58,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error { c.contextSwitchesTotal = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "context_switches_total"), "Total number of context switches (WMI source: PerfOS_System.ContextSwitchesPersec)", diff --git a/pkg/collector/tcp/tcp.go b/pkg/collector/tcp/tcp.go index c7229bfa..e2110089 100644 --- a/pkg/collector/tcp/tcp.go +++ b/pkg/collector/tcp/tcp.go @@ -9,6 +9,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/perflib" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "tcp" @@ -60,7 +61,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error { c.connectionFailures = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "connection_failures_total"), "(TCP.ConnectionFailures)", diff --git a/pkg/collector/teradici_pcoip/teradici_pcoip.go b/pkg/collector/teradici_pcoip/teradici_pcoip.go index 11c3caa4..a2ab5ce6 100644 --- a/pkg/collector/teradici_pcoip/teradici_pcoip.go +++ b/pkg/collector/teradici_pcoip/teradici_pcoip.go @@ -9,8 +9,8 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "teradici_pcoip" @@ -26,7 +26,8 @@ var ConfigDefaults = Config{} // win32_PerfRawData_TeradiciPerf_PCoIPSessionNetworkStatistics // win32_PerfRawData_TeradiciPerf_PCoIPSessionUsbStatistics. type Collector struct { - config Config + config Config + wmiClient *wmi.Client audioBytesReceived *prometheus.Desc audioBytesSent *prometheus.Desc @@ -99,10 +100,16 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(logger log.Logger) error { +func (c *Collector) Build(logger log.Logger, wmiClient *wmi.Client) error { _ = level.Warn(logger). Log("msg", "teradici_pcoip collector is deprecated and will be removed in the future.", "collector", Name) + if wmiClient == nil || wmiClient.SWbemServicesClient == nil { + return errors.New("wmiClient or SWbemServicesClient is nil") + } + + c.wmiClient = wmiClient + c.audioBytesReceived = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "audio_bytes_received_total"), "(AudioBytesReceived)", @@ -336,23 +343,23 @@ func (c *Collector) Build(logger log.Logger) error { // to the provided prometheus Metric channel. func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error { logger = log.With(logger, "collector", Name) - if err := c.collectAudio(logger, ch); err != nil { + if err := c.collectAudio(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting teradici session audio metrics", "err", err) return err } - if err := c.collectGeneral(logger, ch); err != nil { + if err := c.collectGeneral(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting teradici session general metrics", "err", err) return err } - if err := c.collectImaging(logger, ch); err != nil { + if err := c.collectImaging(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting teradici session imaging metrics", "err", err) return err } - if err := c.collectNetwork(logger, ch); err != nil { + if err := c.collectNetwork(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting teradici session network metrics", "err", err) return err } - if err := c.collectUsb(logger, ch); err != nil { + if err := c.collectUsb(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting teradici session USB metrics", "err", err) return err } @@ -411,10 +418,9 @@ type win32_PerfRawData_TeradiciPerf_PCoIPSessionUsbStatistics struct { USBTXBWKBitPerSec uint64 } -func (c *Collector) collectAudio(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectAudio(ch chan<- prometheus.Metric) error { var dst []win32_PerfRawData_TeradiciPerf_PCoIPSessionAudioStatistics - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_TeradiciPerf_PCoIPSessionAudioStatistics", &dst); err != nil { return err } if len(dst) == 0 { @@ -454,10 +460,9 @@ func (c *Collector) collectAudio(logger log.Logger, ch chan<- prometheus.Metric) return nil } -func (c *Collector) collectGeneral(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectGeneral(ch chan<- prometheus.Metric) error { var dst []win32_PerfRawData_TeradiciPerf_PCoIPSessionGeneralStatistics - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_TeradiciPerf_PCoIPSessionGeneralStatistics", &dst); err != nil { return err } if len(dst) == 0 { @@ -509,10 +514,9 @@ func (c *Collector) collectGeneral(logger log.Logger, ch chan<- prometheus.Metri return nil } -func (c *Collector) collectImaging(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectImaging(ch chan<- prometheus.Metric) error { var dst []win32_PerfRawData_TeradiciPerf_PCoIPSessionImagingStatistics - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_TeradiciPerf_PCoIPSessionImagingStatistics", &dst); err != nil { return err } if len(dst) == 0 { @@ -588,10 +592,9 @@ func (c *Collector) collectImaging(logger log.Logger, ch chan<- prometheus.Metri return nil } -func (c *Collector) collectNetwork(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectNetwork(ch chan<- prometheus.Metric) error { var dst []win32_PerfRawData_TeradiciPerf_PCoIPSessionNetworkStatistics - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_TeradiciPerf_PCoIPSessionNetworkStatistics", &dst); err != nil { return err } if len(dst) == 0 { @@ -661,10 +664,9 @@ func (c *Collector) collectNetwork(logger log.Logger, ch chan<- prometheus.Metri return nil } -func (c *Collector) collectUsb(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectUsb(ch chan<- prometheus.Metric) error { var dst []win32_PerfRawData_TeradiciPerf_PCoIPSessionUsbStatistics - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_TeradiciPerf_PCoIPSessionUsbStatistics", &dst); err != nil { return err } if len(dst) == 0 { diff --git a/pkg/collector/terminal_services/terminal_services.go b/pkg/collector/terminal_services/terminal_services.go index d6658b3d..3d591a72 100644 --- a/pkg/collector/terminal_services/terminal_services.go +++ b/pkg/collector/terminal_services/terminal_services.go @@ -15,8 +15,8 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/headers/wtsapi32" "github.com/prometheus-community/windows_exporter/pkg/perflib" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const ( @@ -32,10 +32,9 @@ type Win32_ServerFeature struct { ID uint32 } -func isConnectionBrokerServer(logger log.Logger) bool { +func isConnectionBrokerServer(logger log.Logger, wmiClient *wmi.Client) bool { var dst []Win32_ServerFeature - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := wmiClient.Query("SELECT * FROM Win32_ServerFeature", &dst); err != nil { return false } for _, d := range dst { @@ -111,10 +110,10 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(logger log.Logger) error { +func (c *Collector) Build(logger log.Logger, wmiClient *wmi.Client) error { logger = log.With(logger, "collector", Name) - c.connectionBrokerEnabled = isConnectionBrokerServer(logger) + c.connectionBrokerEnabled = isConnectionBrokerServer(logger, wmiClient) c.sessionInfo = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "session_info"), diff --git a/pkg/collector/textfile/textfile.go b/pkg/collector/textfile/textfile.go index 1d64ac22..c424550a 100644 --- a/pkg/collector/textfile/textfile.go +++ b/pkg/collector/textfile/textfile.go @@ -34,6 +34,7 @@ import ( "github.com/prometheus/client_golang/prometheus" dto "github.com/prometheus/client_model/go" "github.com/prometheus/common/expfmt" + "github.com/yusufpapurcu/wmi" ) const Name = "textfile" @@ -104,7 +105,7 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(logger log.Logger) error { +func (c *Collector) Build(logger log.Logger, _ *wmi.Client) error { _ = level.Info(logger). Log("msg", "textfile Collector directories: "+strings.Join(c.config.TextFileDirectories, ","), "collector", Name) diff --git a/pkg/collector/textfile/textfile_test.go b/pkg/collector/textfile/textfile_test.go index 144a9e01..5ff3007d 100644 --- a/pkg/collector/textfile/textfile_test.go +++ b/pkg/collector/textfile/textfile_test.go @@ -98,7 +98,7 @@ func TestDuplicateMetricEntry(t *testing.T) { Metric: []*dto.Metric{&metric1, &metric2}, } - duplicateFamily := []*dto.MetricFamily{} + var duplicateFamily []*dto.MetricFamily duplicateFamily = append(duplicateFamily, &duplicate) // Ensure detection for duplicate metrics diff --git a/pkg/collector/thermalzone/thermalzone.go b/pkg/collector/thermalzone/thermalzone.go index 3ac746ed..1a73dac5 100644 --- a/pkg/collector/thermalzone/thermalzone.go +++ b/pkg/collector/thermalzone/thermalzone.go @@ -9,8 +9,8 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "thermalzone" @@ -21,7 +21,8 @@ var ConfigDefaults = Config{} // A Collector is a Prometheus Collector for WMI Win32_PerfRawData_Counters_ThermalZoneInformation metrics. type Collector struct { - config Config + config Config + wmiClient *wmi.Client percentPassiveLimit *prometheus.Desc temperature *prometheus.Desc @@ -56,7 +57,12 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error { + if wmiClient == nil || wmiClient.SWbemServicesClient == nil { + return errors.New("wmiClient or SWbemServicesClient is nil") + } + + c.wmiClient = wmiClient c.temperature = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "temperature_celsius"), "(Temperature)", @@ -88,7 +94,7 @@ func (c *Collector) Build(_ log.Logger) error { // to the provided prometheus Metric channel. func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error { logger = log.With(logger, "collector", Name) - if err := c.collect(logger, ch); err != nil { + if err := c.collect(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting thermalzone metrics", "err", err) return err } @@ -105,16 +111,15 @@ type Win32_PerfRawData_Counters_ThermalZoneInformation struct { ThrottleReasons uint32 } -func (c *Collector) collect(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collect(ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_Counters_ThermalZoneInformation - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_Counters_ThermalZoneInformation", &dst); err != nil { return err } // ThermalZone collector has been known to 'successfully' return an empty result. if len(dst) == 0 { - return errors.New("Empty results set for collector") + return errors.New("empty results set for collector") } for _, info := range dst { diff --git a/pkg/collector/time/time.go b/pkg/collector/time/time.go index dbc09033..6a8cce7f 100644 --- a/pkg/collector/time/time.go +++ b/pkg/collector/time/time.go @@ -12,6 +12,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus-community/windows_exporter/pkg/winversion" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "time" @@ -60,9 +61,9 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { - if winversion.WindowsVersionFloat <= 6.1 { - return errors.New("Windows version older than Server 2016 detected. The time collector will not run and should be disabled via CLI flags or configuration file") +func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error { + if winversion.WindowsVersionFloat() <= 6.1 { + return errors.New("windows version older than Server 2016 detected. The time collector will not run and should be disabled via CLI flags or configuration file") } c.clockFrequencyAdjustmentPPBTotal = prometheus.NewDesc( diff --git a/pkg/collector/types.go b/pkg/collector/types.go index eee2e6cf..ff9fb8fc 100644 --- a/pkg/collector/types.go +++ b/pkg/collector/types.go @@ -5,10 +5,12 @@ import ( "github.com/go-kit/log" "github.com/prometheus-community/windows_exporter/pkg/types" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) type Collectors struct { collectors Map + wmiClient *wmi.Client perfCounterQuery string } @@ -19,7 +21,7 @@ type ( // Collector interface that a collector has to implement. type Collector interface { - Build(logger log.Logger) error + Build(logger log.Logger, wmiClient *wmi.Client) error // Close closes the collector Close() error // GetName get the name of the collector diff --git a/pkg/collector/vmware/vmware.go b/pkg/collector/vmware/vmware.go index 8d5e6357..bcb4ad68 100644 --- a/pkg/collector/vmware/vmware.go +++ b/pkg/collector/vmware/vmware.go @@ -10,8 +10,8 @@ import ( "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/perflib" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "vmware" @@ -22,7 +22,8 @@ var ConfigDefaults = Config{} // A Collector is a Prometheus Collector for WMI Win32_PerfRawData_vmGuestLib_VMem/Win32_PerfRawData_vmGuestLib_VCPU metrics. type Collector struct { - config Config + config Config + wmiClient *wmi.Client memActive *prometheus.Desc memBallooned *prometheus.Desc @@ -74,7 +75,13 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(_ log.Logger) error { +func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error { + if wmiClient == nil || wmiClient.SWbemServicesClient == nil { + return errors.New("wmiClient or SWbemServicesClient is nil") + } + + c.wmiClient = wmiClient + c.memActive = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "mem_active_bytes"), "(MemActiveMB)", @@ -197,11 +204,11 @@ func (c *Collector) Build(_ log.Logger) error { // to the provided prometheus Metric channel. func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error { logger = log.With(logger, "collector", Name) - if err := c.collectMem(logger, ch); err != nil { + if err := c.collectMem(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting vmware memory metrics", "err", err) return err } - if err := c.collectCpu(logger, ch); err != nil { + if err := c.collectCpu(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting vmware cpu metrics", "err", err) return err } @@ -233,10 +240,9 @@ type Win32_PerfRawData_vmGuestLib_VCPU struct { HostProcessorSpeedMHz uint64 } -func (c *Collector) collectMem(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectMem(ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_vmGuestLib_VMem - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_vmGuestLib_VMem", &dst); err != nil { return err } if len(dst) == 0 { @@ -322,10 +328,9 @@ func mbToBytes(mb uint64) float64 { return float64(mb * 1024 * 1024) } -func (c *Collector) collectCpu(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectCpu(ch chan<- prometheus.Metric) error { var dst []Win32_PerfRawData_vmGuestLib_VCPU - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_vmGuestLib_VCPU", &dst); err != nil { return err } if len(dst) == 0 { diff --git a/pkg/collector/vmware_blast/vmware_blast.go b/pkg/collector/vmware_blast/vmware_blast.go index f3211859..c9ce63a1 100644 --- a/pkg/collector/vmware_blast/vmware_blast.go +++ b/pkg/collector/vmware_blast/vmware_blast.go @@ -3,12 +3,14 @@ package vmware_blast import ( + "errors" + "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/types" - "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" + "github.com/yusufpapurcu/wmi" ) const Name = "vmware_blast" @@ -32,7 +34,8 @@ var ConfigDefaults = Config{} // win32_PerfRawData_Counters_VMwareBlastWindowsMediaMMRCounters type Collector struct { - config Config + config Config + wmiClient *wmi.Client audioReceivedBytes *prometheus.Desc audioReceivedPackets *prometheus.Desc @@ -144,10 +147,16 @@ func (c *Collector) Close() error { return nil } -func (c *Collector) Build(logger log.Logger) error { +func (c *Collector) Build(logger log.Logger, wmiClient *wmi.Client) error { _ = level.Warn(logger). Log("msg", "vmware_blast collector is deprecated and will be removed in the future.", "collector", Name) + if wmiClient == nil || wmiClient.SWbemServicesClient == nil { + return errors.New("wmiClient or SWbemServicesClient is nil") + } + + c.wmiClient = wmiClient + c.audioReceivedBytes = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "audio_received_bytes_total"), "(AudioReceivedBytes)", @@ -580,51 +589,51 @@ func (c *Collector) Build(logger log.Logger) error { // to the provided prometheus Metric channel. func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error { logger = log.With(logger, "collector", Name) - if err := c.collectAudio(logger, ch); err != nil { + if err := c.collectAudio(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting vmware blast audio metrics", "err", err) return err } - if err := c.collectCdr(logger, ch); err != nil { + if err := c.collectCdr(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting vmware blast CDR metrics", "err", err) return err } - if err := c.collectClipboard(logger, ch); err != nil { + if err := c.collectClipboard(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting vmware blast clipboard metrics", "err", err) return err } - if err := c.collectHtml5Mmr(logger, ch); err != nil { + if err := c.collectHtml5Mmr(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting vmware blast HTML5 MMR metrics", "err", err) return err } - if err := c.collectImaging(logger, ch); err != nil { + if err := c.collectImaging(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting vmware blast imaging metrics", "err", err) return err } - if err := c.collectRtav(logger, ch); err != nil { + if err := c.collectRtav(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting vmware blast RTAV metrics", "err", err) return err } - if err := c.collectSerialPortandScanner(logger, ch); err != nil { + if err := c.collectSerialPortandScanner(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting vmware blast serial port and scanner metrics", "err", err) return err } - if err := c.collectSession(logger, ch); err != nil { + if err := c.collectSession(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting vmware blast metrics", "err", err) return err } - if err := c.collectSkypeforBusinessControl(logger, ch); err != nil { + if err := c.collectSkypeforBusinessControl(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting vmware blast skype for business control metrics", "err", err) return err } - if err := c.collectThinPrint(logger, ch); err != nil { + if err := c.collectThinPrint(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting vmware blast thin print metrics", "err", err) return err } - if err := c.collectUsb(logger, ch); err != nil { + if err := c.collectUsb(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting vmware blast USB metrics", "err", err) return err } - if err := c.collectWindowsMediaMmr(logger, ch); err != nil { + if err := c.collectWindowsMediaMmr(ch); err != nil { _ = level.Error(logger).Log("msg", "failed collecting vmware blast windows media MMR metrics", "err", err) return err } @@ -736,10 +745,9 @@ type win32_PerfRawData_Counters_VMwareBlastWindowsMediaMMRCounters struct { TransmittedPackets uint32 } -func (c *Collector) collectAudio(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectAudio(ch chan<- prometheus.Metric) error { var dst []win32_PerfRawData_Counters_VMwareBlastAudioCounters - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_Counters_VMwareBlastAudioCounters", &dst); err != nil { return err } @@ -775,10 +783,9 @@ func (c *Collector) collectAudio(logger log.Logger, ch chan<- prometheus.Metric) return nil } -func (c *Collector) collectCdr(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectCdr(ch chan<- prometheus.Metric) error { var dst []win32_PerfRawData_Counters_VMwareBlastCDRCounters - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_Counters_VMwareBlastCDRCounters", &dst); err != nil { return err } @@ -814,10 +821,9 @@ func (c *Collector) collectCdr(logger log.Logger, ch chan<- prometheus.Metric) e return nil } -func (c *Collector) collectClipboard(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectClipboard(ch chan<- prometheus.Metric) error { var dst []win32_PerfRawData_Counters_VMwareBlastClipboardCounters - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_Counters_VMwareBlastClipboardCounters", &dst); err != nil { return err } @@ -853,10 +859,9 @@ func (c *Collector) collectClipboard(logger log.Logger, ch chan<- prometheus.Met return nil } -func (c *Collector) collectHtml5Mmr(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectHtml5Mmr(ch chan<- prometheus.Metric) error { var dst []win32_PerfRawData_Counters_VMwareBlastHTML5MMRcounters - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_Counters_VMwareBlastHTML5MMRcounters", &dst); err != nil { return err } @@ -892,10 +897,9 @@ func (c *Collector) collectHtml5Mmr(logger log.Logger, ch chan<- prometheus.Metr return nil } -func (c *Collector) collectImaging(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectImaging(ch chan<- prometheus.Metric) error { var dst []win32_PerfRawData_Counters_VMwareBlastImagingCounters - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_Counters_VMwareBlastImagingCounters", &dst); err != nil { return err } @@ -979,10 +983,9 @@ func (c *Collector) collectImaging(logger log.Logger, ch chan<- prometheus.Metri return nil } -func (c *Collector) collectRtav(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectRtav(ch chan<- prometheus.Metric) error { var dst []win32_PerfRawData_Counters_VMwareBlastRTAVCounters - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_Counters_VMwareBlastRTAVCounters", &dst); err != nil { return err } @@ -1018,10 +1021,9 @@ func (c *Collector) collectRtav(logger log.Logger, ch chan<- prometheus.Metric) return nil } -func (c *Collector) collectSerialPortandScanner(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectSerialPortandScanner(ch chan<- prometheus.Metric) error { var dst []win32_PerfRawData_Counters_VMwareBlastSerialPortandScannerCounters - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_Counters_VMwareBlastSerialPortandScannerCounters", &dst); err != nil { return err } @@ -1057,10 +1059,9 @@ func (c *Collector) collectSerialPortandScanner(logger log.Logger, ch chan<- pro return nil } -func (c *Collector) collectSession(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectSession(ch chan<- prometheus.Metric) error { var dst []win32_PerfRawData_Counters_VMwareBlastSessionCounters - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_Counters_VMwareBlastSessionCounters", &dst); err != nil { return err } @@ -1174,10 +1175,9 @@ func (c *Collector) collectSession(logger log.Logger, ch chan<- prometheus.Metri return nil } -func (c *Collector) collectSkypeforBusinessControl(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectSkypeforBusinessControl(ch chan<- prometheus.Metric) error { var dst []win32_PerfRawData_Counters_VMwareBlastSkypeforBusinessControlCounters - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_Counters_VMwareBlastSkypeforBusinessControlCounters", &dst); err != nil { return err } @@ -1213,10 +1213,9 @@ func (c *Collector) collectSkypeforBusinessControl(logger log.Logger, ch chan<- return nil } -func (c *Collector) collectThinPrint(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectThinPrint(ch chan<- prometheus.Metric) error { var dst []win32_PerfRawData_Counters_VMwareBlastThinPrintCounters - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_Counters_VMwareBlastThinPrintCounters", &dst); err != nil { return err } @@ -1252,10 +1251,9 @@ func (c *Collector) collectThinPrint(logger log.Logger, ch chan<- prometheus.Met return nil } -func (c *Collector) collectUsb(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectUsb(ch chan<- prometheus.Metric) error { var dst []win32_PerfRawData_Counters_VMwareBlastUSBCounters - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_Counters_VMwareBlastUSBCounters", &dst); err != nil { return err } @@ -1291,10 +1289,9 @@ func (c *Collector) collectUsb(logger log.Logger, ch chan<- prometheus.Metric) e return nil } -func (c *Collector) collectWindowsMediaMmr(logger log.Logger, ch chan<- prometheus.Metric) error { +func (c *Collector) collectWindowsMediaMmr(ch chan<- prometheus.Metric) error { var dst []win32_PerfRawData_Counters_VMwareBlastWindowsMediaMMRCounters - q := wmi.QueryAll(&dst, logger) - if err := wmi.Query(q, &dst); err != nil { + if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_Counters_VMwareBlastWindowsMediaMMRCounters", &dst); err != nil { return err } diff --git a/pkg/headers/kernel32/kernel32.go b/pkg/headers/kernel32/kernel32.go index cee36766..f0b37f91 100644 --- a/pkg/headers/kernel32/kernel32.go +++ b/pkg/headers/kernel32/kernel32.go @@ -43,7 +43,7 @@ type DynamicTimezoneInformation struct { func GetDynamicTimeZoneInformation() (DynamicTimezoneInformation, error) { var tzi DynamicTimezoneInformation - r0, _, err := syscall.SyscallN(procGetDynamicTimeZoneInformationSys.Addr(), uintptr(unsafe.Pointer(&tzi))) + r0, _, err := procGetDynamicTimeZoneInformationSys.Call(uintptr(unsafe.Pointer(&tzi))) if uint32(r0) == 0xffffffff { return tzi, err } diff --git a/pkg/headers/netapi32/netapi32.go b/pkg/headers/netapi32/netapi32.go index 0076e2cc..b471ead0 100644 --- a/pkg/headers/netapi32/netapi32.go +++ b/pkg/headers/netapi32/netapi32.go @@ -45,16 +45,16 @@ var NetApiStatus = map[uint32]string{ 2351: "NERR_InvalidComputer", // This operation is only allowed on the primary domain controller of the domain. 2226: "NERR_NotPrimary", - /// This operation is not allowed on this special group. + // This operation is not allowed on this special group. 2234: "NERR_SpeGroupOp", - /// This operation is not allowed on the last administrative account. + // This operation is not allowed on the last administrative account. 2452: "NERR_LastAdmin", - /// The password parameter is invalid. + // The password parameter is invalid. 2203: "NERR_BadPassword", - /// The password does not meet the password policy requirements. - /// Check the minimum password length, password complexity and password history requirements. + // The password does not meet the password policy requirements. + // Check the minimum password length, password complexity and password history requirements. 2245: "NERR_PasswordTooShort", - /// The user name could not be found. + // The user name could not be found. 2221: "NERR_UserNotFound", // Errors 5: "ERROR_ACCESS_DENIED", diff --git a/pkg/headers/slc/slc.go b/pkg/headers/slc/slc.go index f13cef46..dca2f354 100644 --- a/pkg/headers/slc/slc.go +++ b/pkg/headers/slc/slc.go @@ -12,7 +12,8 @@ var ( procSLIsWindowsGenuineLocal = slc.NewProc("SLIsWindowsGenuineLocal") ) -// Define SL_GENUINE_STATE enumeration +// SL_GENUINE_STATE enumeration +// // https://learn.microsoft.com/en-us/windows/win32/api/slpublic/ne-slpublic-sl_genuine_state type SL_GENUINE_STATE uint32 diff --git a/pkg/utils/collector.go b/pkg/utils/collector.go index 9812fd49..76671293 100644 --- a/pkg/utils/collector.go +++ b/pkg/utils/collector.go @@ -3,24 +3,11 @@ package utils import ( - "slices" - "sort" "strings" "github.com/prometheus-community/windows_exporter/pkg/types" ) -// ExpandEnabledChildCollectors used by more complex Collectors where user input specifies enabled child Collectors. -// Splits provided child Collectors and deduplicate. -func ExpandEnabledChildCollectors(enabled string) []string { - result := slices.Compact(strings.Split(enabled, ",")) - - // Result must order, to prevent test failures. - sort.Strings(result) - - return result -} - func ExpandEnabledCollectors(enabled string) []string { expanded := strings.ReplaceAll(enabled, types.DefaultCollectorsPlaceholder, types.DefaultCollectors) separated := strings.Split(expanded, ",") diff --git a/pkg/utils/collector_test.go b/pkg/utils/collector_test.go index c246fefa..9865d7b6 100644 --- a/pkg/utils/collector_test.go +++ b/pkg/utils/collector_test.go @@ -1,7 +1,6 @@ package utils_test import ( - "reflect" "sort" "strings" "testing" @@ -10,38 +9,6 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/utils" ) -func TestExpandChildCollectors(t *testing.T) { - t.Parallel() - - cases := []struct { - name string - input string - expectedOutput []string - }{ - { - name: "simple", - input: "testing1,testing2,testing3", - expectedOutput: []string{"testing1", "testing2", "testing3"}, - }, - { - name: "duplicate", - input: "testing1,testing2,testing2,testing3", - expectedOutput: []string{"testing1", "testing2", "testing3"}, - }, - } - - for _, c := range cases { - t.Run(c.name, func(t *testing.T) { - t.Parallel() - - output := utils.ExpandEnabledChildCollectors(c.input) - if !reflect.DeepEqual(output, c.expectedOutput) { - t.Errorf("Output mismatch, expected %+v, got %+v", c.expectedOutput, output) - } - }) - } -} - func TestExpandEnabled(t *testing.T) { t.Parallel() diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 6619e4bb..0bc79e7a 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -13,10 +13,6 @@ func BoolToFloat(b bool) float64 { return 0.0 } -func HasValue(v *string) bool { - return !IsEmpty(v) -} - func IsEmpty(v *string) bool { return v == nil || *v == "" } diff --git a/pkg/winversion/main.go b/pkg/winversion/main.go index 0b878b84..1d75f99a 100644 --- a/pkg/winversion/main.go +++ b/pkg/winversion/main.go @@ -5,43 +5,39 @@ package winversion import ( "fmt" "strconv" + "sync" "golang.org/x/sys/windows/registry" ) -var ( - WindowsVersion string - WindowsVersionFloat float64 -) - -//nolint:gochecknoinits -func init() { - var err error - WindowsVersion, WindowsVersionFloat, err = GetWindowsVersion() +var WindowsVersionFloat = sync.OnceValue[float64](func() float64 { + version, err := getWindowsVersion() if err != nil { panic(err) } -} + + return version +}) // GetWindowsVersion reads the version number of the OS from the Registry // See https://docs.microsoft.com/en-us/windows/desktop/sysinfo/operating-system-version -func GetWindowsVersion() (string, float64, error) { +func getWindowsVersion() (float64, error) { reg, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE) if err != nil { - return "", 0, fmt.Errorf("couldn't open registry: %w", err) + return 0, fmt.Errorf("couldn't open registry: %w", err) } defer reg.Close() windowsVersion, _, err := reg.GetStringValue("CurrentVersion") if err != nil { - return "", 0, fmt.Errorf("couldn't open registry: %w", err) + return 0, fmt.Errorf("couldn't open registry: %w", err) } windowsVersionFloat, err := strconv.ParseFloat(windowsVersion, 64) if err != nil { - return "", 0, fmt.Errorf("couldn't open registry: %w", err) + return 0, fmt.Errorf("couldn't open registry: %w", err) } - return windowsVersion, windowsVersionFloat, nil + return windowsVersionFloat, nil } diff --git a/pkg/wmi/wmi.go b/pkg/wmi/wmi.go deleted file mode 100644 index 168773af..00000000 --- a/pkg/wmi/wmi.go +++ /dev/null @@ -1,92 +0,0 @@ -package wmi - -import ( - "bytes" - "reflect" - - "github.com/go-kit/log" - "github.com/go-kit/log/level" - "github.com/yusufpapurcu/wmi" -) - -func InitWbem(logger log.Logger) error { - // This initialization prevents a memory leak on WMF 5+. See - // https://github.com/prometheus-community/windows_exporter/issues/77 and - // linked issues for details. - _ = level.Debug(logger).Log("msg", "Initializing SWbemServices") - s, err := wmi.InitializeSWbemServices(wmi.DefaultClient) - if err != nil { - return err - } - wmi.DefaultClient.AllowMissingFields = true - wmi.DefaultClient.SWbemServicesClient = s - - return nil -} - -func className(src interface{}) string { - s := reflect.Indirect(reflect.ValueOf(src)) - t := s.Type() - if s.Kind() == reflect.Slice { - t = t.Elem() - } - return t.Name() -} - -func Query(query string, dst interface{}, connectServerArgs ...interface{}) error { - return wmi.Query(query, dst, connectServerArgs...) -} - -func QueryNamespace(query string, dst interface{}, namespace string) error { - return wmi.QueryNamespace(query, dst, namespace) -} - -// QueryAll returns a query string that selects all fields from the given -// struct type. -// Deprecated: Use QueryAllForClass instead. -func QueryAll(src interface{}, logger log.Logger) string { - var b bytes.Buffer - b.WriteString("SELECT * FROM ") - b.WriteString(className(src)) - - _ = level.Debug(logger).Log("msg", "Generated WMI query "+b.String()) - return b.String() -} - -func QueryAllForClass(_ interface{}, class string, logger log.Logger) string { - var b bytes.Buffer - b.WriteString("SELECT * FROM ") - b.WriteString(class) - - _ = level.Debug(logger).Log("msg", "Generated WMI query "+b.String()) - return b.String() -} - -// Deprecated: Use QueryAllForClassWhere instead. -func QueryAllWhere(src interface{}, where string, logger log.Logger) string { - var b bytes.Buffer - b.WriteString("SELECT * FROM ") - b.WriteString(className(src)) - - if where != "" { - b.WriteString(" WHERE ") - b.WriteString(where) - } - - _ = level.Debug(logger).Log("msg", "Generated WMI query "+b.String()) - return b.String() -} - -func QueryAllForClassWhere(_ interface{}, class string, where string, logger log.Logger) string { - var b bytes.Buffer - b.WriteString("SELECT * FROM ") - b.WriteString(class) - - if where != "" { - b.WriteString(" WHERE ") - b.WriteString(where) - } - - _ = level.Debug(logger).Log("msg", "Generated WMI query "+b.String()) - return b.String() -} diff --git a/pkg/wmi/wmi_test.go b/pkg/wmi/wmi_test.go deleted file mode 100644 index b701f044..00000000 --- a/pkg/wmi/wmi_test.go +++ /dev/null @@ -1,121 +0,0 @@ -package wmi - -import ( - "testing" - - "github.com/go-kit/log" -) - -type fakeWmiClass struct { - Name string - SomeProperty int -} - -var ( - mapQueryAll = func(src interface{}, _ string, _ string) string { - return QueryAll(src, log.NewNopLogger()) - } - mapQueryAllWhere = func(src interface{}, _ string, where string) string { - return QueryAllWhere(src, where, log.NewNopLogger()) - } - mapQueryAllForClass = func(src interface{}, class string, _ string) string { - return QueryAllForClass(src, class, log.NewNopLogger()) - } - mapQueryAllForClassWhere = func(src interface{}, class string, where string) string { - return QueryAllForClassWhere(src, class, where, log.NewNopLogger()) - } -) - -type queryFunc func(src interface{}, class string, where string) string - -func TestCreateQuery(t *testing.T) { - t.Parallel() - - cases := []struct { - desc string - dst interface{} - class string - where string - queryFunc queryFunc - expected string - }{ - { - desc: "queryAll on single instance", - dst: fakeWmiClass{}, - queryFunc: mapQueryAll, - expected: "SELECT * FROM fakeWmiClass", - }, - { - desc: "queryAll on slice", - dst: []fakeWmiClass{}, - queryFunc: mapQueryAll, - expected: "SELECT * FROM fakeWmiClass", - }, - { - desc: "queryAllWhere on single instance", - dst: fakeWmiClass{}, - where: "foo = bar", - queryFunc: mapQueryAllWhere, - expected: "SELECT * FROM fakeWmiClass WHERE foo = bar", - }, - { - desc: "queryAllWhere on slice", - dst: []fakeWmiClass{}, - where: "foo = bar", - queryFunc: mapQueryAllWhere, - expected: "SELECT * FROM fakeWmiClass WHERE foo = bar", - }, - { - desc: "queryAllWhere on single instance with empty where", - dst: fakeWmiClass{}, - queryFunc: mapQueryAllWhere, - expected: "SELECT * FROM fakeWmiClass", - }, - { - desc: "queryAllForClass on single instance", - dst: fakeWmiClass{}, - class: "someClass", - queryFunc: mapQueryAllForClass, - expected: "SELECT * FROM someClass", - }, - { - desc: "queryAllForClass on slice", - dst: []fakeWmiClass{}, - class: "someClass", - queryFunc: mapQueryAllForClass, - expected: "SELECT * FROM someClass", - }, - { - desc: "queryAllForClassWhere on single instance", - dst: fakeWmiClass{}, - class: "someClass", - where: "foo = bar", - queryFunc: mapQueryAllForClassWhere, - expected: "SELECT * FROM someClass WHERE foo = bar", - }, - { - desc: "queryAllForClassWhere on slice", - dst: []fakeWmiClass{}, - class: "someClass", - where: "foo = bar", - queryFunc: mapQueryAllForClassWhere, - expected: "SELECT * FROM someClass WHERE foo = bar", - }, - { - desc: "queryAllForClassWhere on single instance with empty where", - dst: fakeWmiClass{}, - class: "someClass", - queryFunc: mapQueryAllForClassWhere, - expected: "SELECT * FROM someClass", - }, - } - for _, c := range cases { - t.Run(c.desc, func(t *testing.T) { - t.Parallel() - - if q := c.queryFunc(c.dst, c.class, c.where); q != c.expected { - t.Errorf("Case %q failed: Expected %q, got %q", c.desc, c.expected, q) - } - }) - } -}