diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index ca3c807f..00000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/internal/collector/ad/ad.go b/internal/collector/ad/ad.go index 43747d2c..7b3fe113 100644 --- a/internal/collector/ad/ad.go +++ b/internal/collector/ad/ad.go @@ -20,6 +20,7 @@ package ad import ( "fmt" "log/slog" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -518,7 +519,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { err := c.perfDataCollector.Collect(&c.perfDataObject) if err != nil { return fmt.Errorf("failed to collect DirectoryServices (AD) metrics: %w", err) diff --git a/internal/collector/adcs/adcs.go b/internal/collector/adcs/adcs.go index 849c25c9..e38a3508 100644 --- a/internal/collector/adcs/adcs.go +++ b/internal/collector/adcs/adcs.go @@ -20,6 +20,7 @@ package adcs import ( "fmt" "log/slog" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -173,7 +174,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { return nil } -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { err := c.perfDataCollector.Collect(&c.perfDataObject) if err != nil { return fmt.Errorf("failed to collect Certification Authority (ADCS) metrics: %w", err) diff --git a/internal/collector/adfs/adfs.go b/internal/collector/adfs/adfs.go index 079b02b0..591bedfa 100644 --- a/internal/collector/adfs/adfs.go +++ b/internal/collector/adfs/adfs.go @@ -21,6 +21,7 @@ import ( "fmt" "log/slog" "math" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -383,7 +384,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { return nil } -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { err := c.perfDataCollector.Collect(&c.perfDataObject) if err != nil { return fmt.Errorf("failed to collect ADFS metrics: %w", err) diff --git a/internal/collector/cache/cache.go b/internal/collector/cache/cache.go index f0a1294f..b4c52f01 100644 --- a/internal/collector/cache/cache.go +++ b/internal/collector/cache/cache.go @@ -20,6 +20,7 @@ package cache import ( "fmt" "log/slog" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -286,7 +287,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { } // Collect implements the Collector interface. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { err := c.perfDataCollector.Collect(&c.perfDataObject) if err != nil { return fmt.Errorf("failed to collect Cache metrics: %w", err) diff --git a/internal/collector/container/container.go b/internal/collector/container/container.go index 5b612979..4b57310f 100644 --- a/internal/collector/container/container.go +++ b/internal/collector/container/container.go @@ -26,6 +26,7 @@ import ( "os" "slices" "strings" + "time" "unsafe" "github.com/alecthomas/kingpin/v2" @@ -291,7 +292,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { errs := make([]error, 0) if slices.Contains(c.config.CollectorsEnabled, subCollectorHCS) { diff --git a/internal/collector/cpu/cpu.go b/internal/collector/cpu/cpu.go index 72a7606a..de575856 100644 --- a/internal/collector/cpu/cpu.go +++ b/internal/collector/cpu/cpu.go @@ -21,6 +21,7 @@ import ( "fmt" "log/slog" "sync" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -191,7 +192,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { return nil } -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { c.mu.Lock() // Lock is needed to prevent concurrent map access to c.processorRTCValues defer c.mu.Unlock() diff --git a/internal/collector/cpu_info/cpu_info.go b/internal/collector/cpu_info/cpu_info.go index 5964be7c..3190134b 100644 --- a/internal/collector/cpu_info/cpu_info.go +++ b/internal/collector/cpu_info/cpu_info.go @@ -23,6 +23,7 @@ import ( "log/slog" "strconv" "strings" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -151,7 +152,7 @@ func (c *Collector) Build(_ *slog.Logger, miSession *mi.Session) error { c.miSession = miSession var dst []miProcessor - if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, c.miQuery); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, c.miQuery, 0); err != nil { return fmt.Errorf("WMI query failed: %w", err) } @@ -176,9 +177,9 @@ type miProcessor struct { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error { var dst []miProcessor - if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, c.miQuery); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, c.miQuery, maxScrapeDuration); err != nil { return fmt.Errorf("WMI query failed: %w", err) } diff --git a/internal/collector/dfsr/dfsr.go b/internal/collector/dfsr/dfsr.go index 05ae82b4..ce7b0947 100644 --- a/internal/collector/dfsr/dfsr.go +++ b/internal/collector/dfsr/dfsr.go @@ -23,6 +23,7 @@ import ( "log/slog" "slices" "strings" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -480,7 +481,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { // Collect implements the Collector interface. // Sends metric values for each metric to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { errs := make([]error, 0) if slices.Contains(c.config.CollectorsEnabled, "connection") { diff --git a/internal/collector/dhcp/dhcp.go b/internal/collector/dhcp/dhcp.go index 3eff7ce5..a1fdf727 100644 --- a/internal/collector/dhcp/dhcp.go +++ b/internal/collector/dhcp/dhcp.go @@ -24,6 +24,7 @@ import ( "slices" "strconv" "strings" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/headers/dhcpsapi" @@ -387,7 +388,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { return nil } -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { var errs []error if slices.Contains(c.config.CollectorsEnabled, subCollectorServerMetrics) { diff --git a/internal/collector/diskdrive/diskdrive.go b/internal/collector/diskdrive/diskdrive.go index 74f986f9..c9d7d47b 100644 --- a/internal/collector/diskdrive/diskdrive.go +++ b/internal/collector/diskdrive/diskdrive.go @@ -22,6 +22,7 @@ import ( "fmt" "log/slog" "strings" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -127,7 +128,7 @@ func (c *Collector) Build(logger *slog.Logger, miSession *mi.Session) error { c.miSession = miSession var dst []diskDrive - if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, c.miQuery); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, c.miQuery, 0); err != nil { return fmt.Errorf("WMI query failed: %w", err) } @@ -188,9 +189,9 @@ var ( ) // Collect sends the metric values for each metric to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error { var dst []diskDrive - if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, c.miQuery); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, c.miQuery, maxScrapeDuration); err != nil { return fmt.Errorf("WMI query failed: %w", err) } diff --git a/internal/collector/dns/dns.go b/internal/collector/dns/dns.go index 5f6eec0a..eaa6cbd5 100644 --- a/internal/collector/dns/dns.go +++ b/internal/collector/dns/dns.go @@ -23,6 +23,7 @@ import ( "log/slog" "slices" "strings" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -320,12 +321,17 @@ func (c *Collector) buildErrorStatsCollector(miSession *mi.Session) error { c.miSession = miSession c.miQuery = query + var stats []Statistic + if err := c.miSession.Query(&stats, mi.NamespaceRootMicrosoftDNS, c.miQuery, 0); err != nil { + return fmt.Errorf("failed to query DNS statistics: %w", err) + } + return nil } // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error { errs := make([]error, 0) if slices.Contains(c.config.CollectorsEnabled, subCollectorMetrics) { @@ -335,7 +341,7 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) error { } if slices.Contains(c.config.CollectorsEnabled, subCollectorWMIStats) { - if err := c.collectErrorStats(ch); err != nil { + if err := c.collectErrorStats(ch, maxScrapeDuration); err != nil { errs = append(errs, fmt.Errorf("failed collecting WMI statistics: %w", err)) } } @@ -627,9 +633,9 @@ func (c *Collector) collectMetrics(ch chan<- prometheus.Metric) error { return nil } -func (c *Collector) collectErrorStats(ch chan<- prometheus.Metric) error { +func (c *Collector) collectErrorStats(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error { var stats []Statistic - if err := c.miSession.Query(&stats, mi.NamespaceRootMicrosoftDNS, c.miQuery); err != nil { + if err := c.miSession.Query(&stats, mi.NamespaceRootMicrosoftDNS, c.miQuery, maxScrapeDuration); err != nil { return fmt.Errorf("failed to query DNS statistics: %w", err) } diff --git a/internal/collector/exchange/exchange.go b/internal/collector/exchange/exchange.go index 84790b94..ee51e52a 100644 --- a/internal/collector/exchange/exchange.go +++ b/internal/collector/exchange/exchange.go @@ -24,6 +24,7 @@ import ( "os" "strings" "sync" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -252,7 +253,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { } // Collect collects exchange metrics and sends them to prometheus. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { errCh := make(chan error, len(c.collectorFns)) errs := make([]error, 0, len(c.collectorFns)) diff --git a/internal/collector/file/file.go b/internal/collector/file/file.go index f1b91c4f..7bcddd1d 100644 --- a/internal/collector/file/file.go +++ b/internal/collector/file/file.go @@ -25,6 +25,7 @@ import ( "path/filepath" "strings" "sync" + "time" "github.com/alecthomas/kingpin/v2" "github.com/bmatcuk/doublestar/v4" @@ -124,7 +125,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { wg := sync.WaitGroup{} for _, filePattern := range c.config.FilePatterns { diff --git a/internal/collector/fsrmquota/fsrmquota.go b/internal/collector/fsrmquota/fsrmquota.go index b1d6d30a..74e477bd 100644 --- a/internal/collector/fsrmquota/fsrmquota.go +++ b/internal/collector/fsrmquota/fsrmquota.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "log/slog" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -146,7 +147,7 @@ func (c *Collector) Build(_ *slog.Logger, miSession *mi.Session) error { ) var dst []msftFSRMQuota - if err := c.miSession.Query(&dst, mi.NamespaceRootWindowsFSRM, c.miQuery); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootWindowsFSRM, c.miQuery, 0); err != nil { return fmt.Errorf("WMI query failed: %w", err) } @@ -169,9 +170,9 @@ type msftFSRMQuota struct { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error { var dst []msftFSRMQuota - if err := c.miSession.Query(&dst, mi.NamespaceRootWindowsFSRM, c.miQuery); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootWindowsFSRM, c.miQuery, maxScrapeDuration); err != nil { return fmt.Errorf("WMI query failed: %w", err) } diff --git a/internal/collector/gpu/gpu.go b/internal/collector/gpu/gpu.go index 4a98e557..45fd2dcb 100644 --- a/internal/collector/gpu/gpu.go +++ b/internal/collector/gpu/gpu.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "log/slog" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/headers/cfgmgr32" @@ -314,7 +315,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { return errors.Join(errs...) } -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { errs := make([]error, 0) c.collectGpuInfo(ch) diff --git a/internal/collector/hyperv/hyperv.go b/internal/collector/hyperv/hyperv.go index 0dbbeeb9..b686746c 100644 --- a/internal/collector/hyperv/hyperv.go +++ b/internal/collector/hyperv/hyperv.go @@ -24,6 +24,7 @@ import ( "sort" "strings" "sync" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -281,7 +282,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { errCh := make(chan error, len(c.collectorFns)) errs := make([]error, 0, len(c.collectorFns)) diff --git a/internal/collector/iis/iis.go b/internal/collector/iis/iis.go index d47f60d9..30237cfb 100644 --- a/internal/collector/iis/iis.go +++ b/internal/collector/iis/iis.go @@ -24,6 +24,7 @@ import ( "regexp" "slices" "strings" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -251,7 +252,7 @@ func (c *Collector) getIISVersion() simpleVersion { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { ch <- prometheus.MustNewConstMetric( c.info, prometheus.GaugeValue, diff --git a/internal/collector/license/license.go b/internal/collector/license/license.go index d95b9c31..4649360b 100644 --- a/internal/collector/license/license.go +++ b/internal/collector/license/license.go @@ -19,6 +19,7 @@ package license import ( "log/slog" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/headers/slc" @@ -87,7 +88,7 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { status, err := slc.SLIsWindowsGenuineLocal() if err != nil { return err diff --git a/internal/collector/logical_disk/logical_disk.go b/internal/collector/logical_disk/logical_disk.go index 479cffd3..aaa8e5c0 100644 --- a/internal/collector/logical_disk/logical_disk.go +++ b/internal/collector/logical_disk/logical_disk.go @@ -29,6 +29,7 @@ import ( "slices" "strconv" "strings" + "time" "github.com/alecthomas/kingpin/v2" "github.com/go-ole/go-ole" @@ -361,7 +362,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { var info volumeInfo err := c.perfDataCollector.Collect(&c.perfDataObject) diff --git a/internal/collector/memory/memory.go b/internal/collector/memory/memory.go index fdb7fa62..40aed96c 100644 --- a/internal/collector/memory/memory.go +++ b/internal/collector/memory/memory.go @@ -24,6 +24,7 @@ import ( "errors" "fmt" "log/slog" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/headers/sysinfoapi" @@ -347,7 +348,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { errs := make([]error, 0) if err := c.collectPDH(ch); err != nil { diff --git a/internal/collector/mscluster/mscluster.go b/internal/collector/mscluster/mscluster.go index 87125173..f1b58c0d 100644 --- a/internal/collector/mscluster/mscluster.go +++ b/internal/collector/mscluster/mscluster.go @@ -24,6 +24,7 @@ import ( "slices" "strings" "sync" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -179,21 +180,21 @@ func (c *Collector) Build(_ *slog.Logger, miSession *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error { if len(c.config.CollectorsEnabled) == 0 { return nil } - errCh := make(chan error, 6) + errCh := make(chan error, 7) wg := sync.WaitGroup{} - wg.Add(6) + wg.Add(7) go func() { defer wg.Done() if slices.Contains(c.config.CollectorsEnabled, subCollectorCluster) { - if err := c.collectCluster(ch); err != nil { + if err := c.collectCluster(ch, maxScrapeDuration); err != nil { errCh <- fmt.Errorf("failed to collect cluster metrics: %w", err) } } @@ -203,7 +204,7 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) error { defer wg.Done() if slices.Contains(c.config.CollectorsEnabled, subCollectorNetwork) { - if err := c.collectNetwork(ch); err != nil { + if err := c.collectNetwork(ch, maxScrapeDuration); err != nil { errCh <- fmt.Errorf("failed to collect network metrics: %w", err) } } @@ -217,7 +218,7 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) error { if slices.Contains(c.config.CollectorsEnabled, subCollectorNode) { var err error - nodeNames, err = c.collectNode(ch) + nodeNames, err = c.collectNode(ch, maxScrapeDuration) if err != nil { errCh <- fmt.Errorf("failed to collect node metrics: %w", err) } @@ -227,7 +228,7 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) error { defer wg.Done() if slices.Contains(c.config.CollectorsEnabled, subCollectorResource) { - if err := c.collectResource(ch, nodeNames); err != nil { + if err := c.collectResource(ch, maxScrapeDuration, nodeNames); err != nil { errCh <- fmt.Errorf("failed to collect resource metrics: %w", err) } } @@ -237,7 +238,7 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) error { defer wg.Done() if slices.Contains(c.config.CollectorsEnabled, subCollectorResourceGroup) { - if err := c.collectResourceGroup(ch, nodeNames); err != nil { + if err := c.collectResourceGroup(ch, maxScrapeDuration, nodeNames); err != nil { errCh <- fmt.Errorf("failed to collect resource group metrics: %w", err) } } @@ -248,13 +249,17 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) error { defer wg.Done() if slices.Contains(c.config.CollectorsEnabled, subCollectorSharedVolumes) { - if err := c.collectSharedVolumes(ch); err != nil { + if err := c.collectSharedVolumes(ch, maxScrapeDuration); err != nil { errCh <- fmt.Errorf("failed to collect shared_volumes metrics: %w", err) } } + }() + + go func() { + defer wg.Done() if slices.Contains(c.config.CollectorsEnabled, subCollectorVirtualDisk) { - if err := c.collectVirtualDisk(ch); err != nil { + if err := c.collectVirtualDisk(ch, maxScrapeDuration); err != nil { errCh <- fmt.Errorf("failed to collect virtualdisk metrics: %w", err) } } diff --git a/internal/collector/mscluster/mscluster_cluster.go b/internal/collector/mscluster/mscluster_cluster.go index 648b2ea5..8da25575 100644 --- a/internal/collector/mscluster/mscluster_cluster.go +++ b/internal/collector/mscluster/mscluster_cluster.go @@ -19,6 +19,7 @@ package mscluster import ( "fmt" + "time" "github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/osversion" @@ -673,16 +674,16 @@ func (c *Collector) buildCluster() error { ) var dst []msClusterCluster - if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.clusterMIQuery); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.clusterMIQuery, 0); err != nil { return fmt.Errorf("WMI query failed: %w", err) } return nil } -func (c *Collector) collectCluster(ch chan<- prometheus.Metric) error { +func (c *Collector) collectCluster(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error { var dst []msClusterCluster - if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.clusterMIQuery); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.clusterMIQuery, maxScrapeDuration); err != nil { return fmt.Errorf("WMI query failed: %w", err) } diff --git a/internal/collector/mscluster/mscluster_network.go b/internal/collector/mscluster/mscluster_network.go index 3a34a8c7..4d5de8bb 100644 --- a/internal/collector/mscluster/mscluster_network.go +++ b/internal/collector/mscluster/mscluster_network.go @@ -19,6 +19,7 @@ package mscluster import ( "fmt" + "time" "github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/types" @@ -90,7 +91,7 @@ func (c *Collector) buildNetwork() error { var dst []msClusterNetwork - if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.networkMIQuery); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.networkMIQuery, 0); err != nil { return fmt.Errorf("WMI query failed: %w", err) } @@ -99,10 +100,10 @@ func (c *Collector) buildNetwork() error { // Collect sends the metric values for each metric // to the provided prometheus metric channel. -func (c *Collector) collectNetwork(ch chan<- prometheus.Metric) error { +func (c *Collector) collectNetwork(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error { var dst []msClusterNetwork - if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.networkMIQuery); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.networkMIQuery, maxScrapeDuration); err != nil { return fmt.Errorf("WMI query failed: %w", err) } diff --git a/internal/collector/mscluster/mscluster_node.go b/internal/collector/mscluster/mscluster_node.go index c5de0b89..39b3c839 100644 --- a/internal/collector/mscluster/mscluster_node.go +++ b/internal/collector/mscluster/mscluster_node.go @@ -19,6 +19,7 @@ package mscluster import ( "fmt" + "time" "github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/osversion" @@ -170,7 +171,7 @@ func (c *Collector) buildNode() error { var dst []msClusterNode - if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.nodeMIQuery); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.nodeMIQuery, 0); err != nil { return fmt.Errorf("WMI query failed: %w", err) } @@ -179,10 +180,10 @@ func (c *Collector) buildNode() error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) collectNode(ch chan<- prometheus.Metric) ([]string, error) { +func (c *Collector) collectNode(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) ([]string, error) { var dst []msClusterNode - if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.nodeMIQuery); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.nodeMIQuery, maxScrapeDuration); err != nil { return nil, fmt.Errorf("WMI query failed: %w", err) } diff --git a/internal/collector/mscluster/mscluster_resource.go b/internal/collector/mscluster/mscluster_resource.go index 8b2bc745..60219cd8 100644 --- a/internal/collector/mscluster/mscluster_resource.go +++ b/internal/collector/mscluster/mscluster_resource.go @@ -19,6 +19,7 @@ package mscluster import ( "fmt" + "time" "github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/types" @@ -194,7 +195,7 @@ func (c *Collector) buildResource() error { var dst []msClusterResource - if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.resourceMIQuery); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.resourceMIQuery, 0); err != nil { return fmt.Errorf("WMI query failed: %w", err) } @@ -203,10 +204,10 @@ func (c *Collector) buildResource() error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) collectResource(ch chan<- prometheus.Metric, nodeNames []string) error { +func (c *Collector) collectResource(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration, nodeNames []string) error { var dst []msClusterResource - if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.resourceMIQuery); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.resourceMIQuery, maxScrapeDuration); err != nil { return fmt.Errorf("WMI query failed: %w", err) } diff --git a/internal/collector/mscluster/mscluster_resourcegroup.go b/internal/collector/mscluster/mscluster_resourcegroup.go index 6c528c0b..f15e3512 100644 --- a/internal/collector/mscluster/mscluster_resourcegroup.go +++ b/internal/collector/mscluster/mscluster_resourcegroup.go @@ -19,6 +19,7 @@ package mscluster import ( "fmt" + "time" "github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/types" @@ -168,7 +169,7 @@ func (c *Collector) buildResourceGroup() error { var dst []msClusterResourceGroup - if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.resourceGroupMIQuery); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.resourceGroupMIQuery, 0); err != nil { return fmt.Errorf("WMI query failed: %w", err) } @@ -177,10 +178,10 @@ func (c *Collector) buildResourceGroup() error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) collectResourceGroup(ch chan<- prometheus.Metric, nodeNames []string) error { +func (c *Collector) collectResourceGroup(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration, nodeNames []string) error { var dst []msClusterResourceGroup - if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.resourceGroupMIQuery); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.resourceGroupMIQuery, maxScrapeDuration); err != nil { return fmt.Errorf("WMI query failed: %w", err) } diff --git a/internal/collector/mscluster/mscluster_shared_volumes.go b/internal/collector/mscluster/mscluster_shared_volumes.go index 13467fc2..e2354b84 100644 --- a/internal/collector/mscluster/mscluster_shared_volumes.go +++ b/internal/collector/mscluster/mscluster_shared_volumes.go @@ -20,6 +20,7 @@ package mscluster import ( "fmt" "strings" + "time" "github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/types" @@ -76,16 +77,16 @@ func (c *Collector) buildSharedVolumes() error { ) var dst []msClusterDiskPartition - if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.sharedVolumesMIQuery); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.sharedVolumesMIQuery, 0); err != nil { return fmt.Errorf("WMI query failed: %w", err) } return nil } -func (c *Collector) collectSharedVolumes(ch chan<- prometheus.Metric) error { +func (c *Collector) collectSharedVolumes(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error { var dst []msClusterDiskPartition - if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.sharedVolumesMIQuery); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootMSCluster, c.sharedVolumesMIQuery, maxScrapeDuration); err != nil { return fmt.Errorf("WMI query failed: %w", err) } diff --git a/internal/collector/mscluster/mscluster_virtualdisk.go b/internal/collector/mscluster/mscluster_virtualdisk.go index a00d0af4..4a90a087 100644 --- a/internal/collector/mscluster/mscluster_virtualdisk.go +++ b/internal/collector/mscluster/mscluster_virtualdisk.go @@ -19,6 +19,7 @@ package mscluster import ( "fmt" + "time" "github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/types" @@ -92,13 +93,19 @@ func (c *Collector) buildVirtualDisk() error { nil, ) + var dst []msftVirtualDisk + + if err := c.miSession.Query(&dst, mi.NamespaceRootStorage, c.virtualDiskMIQuery, 0); err != nil { + return fmt.Errorf("WMI query failed: %w", err) + } + return nil } -func (c *Collector) collectVirtualDisk(ch chan<- prometheus.Metric) error { +func (c *Collector) collectVirtualDisk(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error { var dst []msftVirtualDisk - if err := c.miSession.Query(&dst, mi.NamespaceRootStorage, c.virtualDiskMIQuery); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootStorage, c.virtualDiskMIQuery, maxScrapeDuration); err != nil { return fmt.Errorf("WMI query failed: %w", err) } diff --git a/internal/collector/msmq/msmq.go b/internal/collector/msmq/msmq.go index b776eae6..ba485011 100644 --- a/internal/collector/msmq/msmq.go +++ b/internal/collector/msmq/msmq.go @@ -20,6 +20,7 @@ package msmq import ( "fmt" "log/slog" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -113,7 +114,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { err := c.perfDataCollector.Collect(&c.perfDataObject) if err != nil { return fmt.Errorf("failed to collect MSMQ Queue metrics: %w", err) diff --git a/internal/collector/mssql/mssql.go b/internal/collector/mssql/mssql.go index 1a4a8fe3..4e50610c 100644 --- a/internal/collector/mssql/mssql.go +++ b/internal/collector/mssql/mssql.go @@ -274,7 +274,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { if len(c.mssqlInstances) == 0 { return fmt.Errorf("no SQL instances found: %w", pdh.ErrNoData) } diff --git a/internal/collector/net/net.go b/internal/collector/net/net.go index 25287227..bac69165 100644 --- a/internal/collector/net/net.go +++ b/internal/collector/net/net.go @@ -25,6 +25,7 @@ import ( "regexp" "slices" "strings" + "time" "unsafe" "github.com/alecthomas/kingpin/v2" @@ -295,7 +296,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { errs := make([]error, 0) if slices.Contains(c.config.CollectorsEnabled, subCollectorMetrics) { diff --git a/internal/collector/netframework/netframework.go b/internal/collector/netframework/netframework.go index e80cef01..7c1a7fd4 100644 --- a/internal/collector/netframework/netframework.go +++ b/internal/collector/netframework/netframework.go @@ -24,6 +24,7 @@ import ( "sort" "strings" "sync" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -66,7 +67,7 @@ type Collector struct { config Config miSession *mi.Session - collectorFns []func(ch chan<- prometheus.Metric) error + collectorFns []func(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error // clrexceptions numberOfExceptionsThrown *prometheus.Desc @@ -187,11 +188,11 @@ func (c *Collector) Build(_ *slog.Logger, miSession *mi.Session) error { c.miSession = miSession - c.collectorFns = make([]func(ch chan<- prometheus.Metric) error, 0, len(c.config.CollectorsEnabled)) + c.collectorFns = make([]func(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error, 0, len(c.config.CollectorsEnabled)) subCollectors := map[string]struct { build func() - collect func(ch chan<- prometheus.Metric) error + collect func(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error close func() }{ collectorClrExceptions: { @@ -246,7 +247,7 @@ func (c *Collector) Build(_ *slog.Logger, miSession *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error { errCh := make(chan error, len(c.collectorFns)) errs := make([]error, 0, len(c.collectorFns)) @@ -255,10 +256,10 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) error { for _, fn := range c.collectorFns { wg.Add(1) - go func(fn func(ch chan<- prometheus.Metric) error) { + go func(fn func(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error) { defer wg.Done() - if err := fn(ch); err != nil { + if err := fn(ch, maxScrapeDuration); err != nil { errCh <- err } }(fn) diff --git a/internal/collector/netframework/netframework_clrexceptions.go b/internal/collector/netframework/netframework_clrexceptions.go index 725eeb7a..129702a5 100644 --- a/internal/collector/netframework/netframework_clrexceptions.go +++ b/internal/collector/netframework/netframework_clrexceptions.go @@ -19,6 +19,7 @@ package netframework import ( "fmt" + "time" "github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/types" @@ -63,9 +64,9 @@ type Win32_PerfRawData_NETFramework_NETCLRExceptions struct { ThrowToCatchDepthPersec uint32 `mi:"ThrowToCatchDepthPersec"` } -func (c *Collector) collectClrExceptions(ch chan<- prometheus.Metric) error { +func (c *Collector) collectClrExceptions(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error { var dst []Win32_PerfRawData_NETFramework_NETCLRExceptions - if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRExceptions"))); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRExceptions")), maxScrapeDuration); err != nil { return fmt.Errorf("WMI query failed: %w", err) } diff --git a/internal/collector/netframework/netframework_clrinterop.go b/internal/collector/netframework/netframework_clrinterop.go index 0fe1808e..8e1184f6 100644 --- a/internal/collector/netframework/netframework_clrinterop.go +++ b/internal/collector/netframework/netframework_clrinterop.go @@ -19,6 +19,7 @@ package netframework import ( "fmt" + "time" "github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/types" @@ -57,9 +58,9 @@ type Win32_PerfRawData_NETFramework_NETCLRInterop struct { NumberofTLBimportsPersec uint32 `mi:"NumberofTLBimportsPersec"` } -func (c *Collector) collectClrInterop(ch chan<- prometheus.Metric) error { +func (c *Collector) collectClrInterop(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error { var dst []Win32_PerfRawData_NETFramework_NETCLRInterop - if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRInterop"))); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRInterop")), maxScrapeDuration); err != nil { return fmt.Errorf("WMI query failed: %w", err) } diff --git a/internal/collector/netframework/netframework_clrjit.go b/internal/collector/netframework/netframework_clrjit.go index c7a73578..d05345f7 100644 --- a/internal/collector/netframework/netframework_clrjit.go +++ b/internal/collector/netframework/netframework_clrjit.go @@ -19,6 +19,7 @@ package netframework import ( "fmt" + "time" "github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/types" @@ -65,9 +66,9 @@ type Win32_PerfRawData_NETFramework_NETCLRJit struct { TotalNumberofILBytesJitted uint32 `mi:"TotalNumberofILBytesJitted"` } -func (c *Collector) collectClrJIT(ch chan<- prometheus.Metric) error { +func (c *Collector) collectClrJIT(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error { var dst []Win32_PerfRawData_NETFramework_NETCLRJit - if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRJit"))); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRJit")), maxScrapeDuration); err != nil { return fmt.Errorf("WMI query failed: %w", err) } diff --git a/internal/collector/netframework/netframework_clrloading.go b/internal/collector/netframework/netframework_clrloading.go index bf0e84c2..40891194 100644 --- a/internal/collector/netframework/netframework_clrloading.go +++ b/internal/collector/netframework/netframework_clrloading.go @@ -19,6 +19,7 @@ package netframework import ( "fmt" + "time" "github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/types" @@ -104,9 +105,9 @@ type Win32_PerfRawData_NETFramework_NETCLRLoading struct { TotalNumberofLoadFailures uint32 `mi:"TotalNumberofLoadFailures"` } -func (c *Collector) collectClrLoading(ch chan<- prometheus.Metric) error { +func (c *Collector) collectClrLoading(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error { var dst []Win32_PerfRawData_NETFramework_NETCLRLoading - if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRLoading"))); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRLoading")), maxScrapeDuration); err != nil { return fmt.Errorf("WMI query failed: %w", err) } diff --git a/internal/collector/netframework/netframework_clrlocksandthreads.go b/internal/collector/netframework/netframework_clrlocksandthreads.go index 2f6e3566..197e4b08 100644 --- a/internal/collector/netframework/netframework_clrlocksandthreads.go +++ b/internal/collector/netframework/netframework_clrlocksandthreads.go @@ -19,6 +19,7 @@ package netframework import ( "fmt" + "time" "github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/types" @@ -86,9 +87,9 @@ type Win32_PerfRawData_NETFramework_NETCLRLocksAndThreads struct { TotalNumberofContentions uint32 `mi:"TotalNumberofContentions"` } -func (c *Collector) collectClrLocksAndThreads(ch chan<- prometheus.Metric) error { +func (c *Collector) collectClrLocksAndThreads(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error { var dst []Win32_PerfRawData_NETFramework_NETCLRLocksAndThreads - if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRLocksAndThreads"))); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRLocksAndThreads")), maxScrapeDuration); err != nil { return fmt.Errorf("WMI query failed: %w", err) } diff --git a/internal/collector/netframework/netframework_clrmemory.go b/internal/collector/netframework/netframework_clrmemory.go index f467601d..4a718886 100644 --- a/internal/collector/netframework/netframework_clrmemory.go +++ b/internal/collector/netframework/netframework_clrmemory.go @@ -20,6 +20,7 @@ package netframework import ( "fmt" "strconv" + "time" "github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/types" @@ -136,9 +137,9 @@ type Win32_PerfRawData_NETFramework_NETCLRMemory struct { PromotedMemoryfromGen1 uint64 `mi:"PromotedMemoryfromGen1"` } -func (c *Collector) collectClrMemory(ch chan<- prometheus.Metric) error { +func (c *Collector) collectClrMemory(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error { var dst []Win32_PerfRawData_NETFramework_NETCLRMemory - if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRMemory"))); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRMemory")), maxScrapeDuration); err != nil { return fmt.Errorf("WMI query failed: %w", err) } diff --git a/internal/collector/netframework/netframework_clrremoting.go b/internal/collector/netframework/netframework_clrremoting.go index cb99b3aa..27b8f983 100644 --- a/internal/collector/netframework/netframework_clrremoting.go +++ b/internal/collector/netframework/netframework_clrremoting.go @@ -19,6 +19,7 @@ package netframework import ( "fmt" + "time" "github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/types" @@ -77,9 +78,9 @@ type Win32_PerfRawData_NETFramework_NETCLRRemoting struct { TotalRemoteCalls uint32 `mi:"TotalRemoteCalls"` } -func (c *Collector) collectClrRemoting(ch chan<- prometheus.Metric) error { +func (c *Collector) collectClrRemoting(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error { var dst []Win32_PerfRawData_NETFramework_NETCLRRemoting - if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRRemoting"))); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRRemoting")), maxScrapeDuration); err != nil { return fmt.Errorf("WMI query failed: %w", err) } diff --git a/internal/collector/netframework/netframework_clrsecurity.go b/internal/collector/netframework/netframework_clrsecurity.go index bc044ee8..a25f7629 100644 --- a/internal/collector/netframework/netframework_clrsecurity.go +++ b/internal/collector/netframework/netframework_clrsecurity.go @@ -19,6 +19,7 @@ package netframework import ( "fmt" + "time" "github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/types" @@ -64,9 +65,9 @@ type Win32_PerfRawData_NETFramework_NETCLRSecurity struct { TotalRuntimeChecks uint32 `mi:"TotalRuntimeChecks"` } -func (c *Collector) collectClrSecurity(ch chan<- prometheus.Metric) error { +func (c *Collector) collectClrSecurity(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error { var dst []Win32_PerfRawData_NETFramework_NETCLRSecurity - if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRSecurity"))); err != nil { + if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * FROM Win32_PerfRawData_NETFramework_NETCLRSecurity")), maxScrapeDuration); err != nil { return fmt.Errorf("WMI query failed: %w", err) } diff --git a/internal/collector/nps/nps.go b/internal/collector/nps/nps.go index b688efbd..7fe86614 100644 --- a/internal/collector/nps/nps.go +++ b/internal/collector/nps/nps.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "log/slog" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -267,7 +268,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { errs := make([]error, 0) if err := c.collectAccept(ch); err != nil { diff --git a/internal/collector/os/os.go b/internal/collector/os/os.go index da630628..0b346c50 100644 --- a/internal/collector/os/os.go +++ b/internal/collector/os/os.go @@ -23,6 +23,7 @@ import ( "log/slog" "strconv" "strings" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/headers/sysinfoapi" @@ -133,7 +134,7 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { errs := make([]error, 0) ch <- prometheus.MustNewConstMetric( diff --git a/internal/collector/pagefile/pagefile.go b/internal/collector/pagefile/pagefile.go index d18269b6..3ee884e1 100644 --- a/internal/collector/pagefile/pagefile.go +++ b/internal/collector/pagefile/pagefile.go @@ -22,6 +22,7 @@ import ( "log/slog" "os" "strings" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/headers/psapi" @@ -102,7 +103,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { err := c.perfDataCollector.Collect(&c.perfDataObject) if err != nil { return fmt.Errorf("failed to collect Paging File metrics: %w", err) diff --git a/internal/collector/performancecounter/performancecounter.go b/internal/collector/performancecounter/performancecounter.go index c77cebe3..a26b3390 100644 --- a/internal/collector/performancecounter/performancecounter.go +++ b/internal/collector/performancecounter/performancecounter.go @@ -249,7 +249,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { var errs []error for _, perfDataObject := range c.objects { diff --git a/internal/collector/performancecounter/performancecounter_test_test.go b/internal/collector/performancecounter/performancecounter_test_test.go index a47038c3..2354c23b 100644 --- a/internal/collector/performancecounter/performancecounter_test_test.go +++ b/internal/collector/performancecounter/performancecounter_test_test.go @@ -42,7 +42,7 @@ func (a collectorAdapter) Describe(_ chan<- *prometheus.Desc) {} // Collect implements the prometheus.Collector interface. func (a collectorAdapter) Collect(ch chan<- prometheus.Metric) { - if err := a.Collector.Collect(ch); err != nil { + if err := a.Collector.Collect(ch, 0); err != nil { panic(fmt.Sprintf("failed to update collector: %v", err)) } } diff --git a/internal/collector/physical_disk/physical_disk.go b/internal/collector/physical_disk/physical_disk.go index 58eec2dd..1bf6f44f 100644 --- a/internal/collector/physical_disk/physical_disk.go +++ b/internal/collector/physical_disk/physical_disk.go @@ -22,6 +22,7 @@ import ( "log/slog" "regexp" "strings" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -225,7 +226,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { err := c.perfDataCollector.Collect(&c.perfDataObject) if err != nil { return fmt.Errorf("failed to collect PhysicalDisk metrics: %w", err) diff --git a/internal/collector/printer/printer.go b/internal/collector/printer/printer.go index d930fbb4..dbf28fd5 100644 --- a/internal/collector/printer/printer.go +++ b/internal/collector/printer/printer.go @@ -23,6 +23,7 @@ import ( "log/slog" "regexp" "strings" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -183,14 +184,14 @@ type wmiPrintJob struct { Status string `mi:"Status"` } -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error { var errs []error if err := c.collectPrinterStatus(ch); err != nil { errs = append(errs, fmt.Errorf("failed to collect printer status metrics: %w", err)) } - if err := c.collectPrinterJobStatus(ch); err != nil { + if err := c.collectPrinterJobStatus(ch, maxScrapeDuration); err != nil { errs = append(errs, fmt.Errorf("failed to collect printer job status metrics: %w", err)) } @@ -199,7 +200,7 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) error { func (c *Collector) collectPrinterStatus(ch chan<- prometheus.Metric) error { var printers []wmiPrinter - if err := c.miSession.Query(&printers, mi.NamespaceRootCIMv2, c.miQueryPrinter); err != nil { + if err := c.miSession.Query(&printers, mi.NamespaceRootCIMv2, c.miQueryPrinter, 0); err != nil { return fmt.Errorf("WMI query failed: %w", err) } @@ -235,9 +236,9 @@ func (c *Collector) collectPrinterStatus(ch chan<- prometheus.Metric) error { return nil } -func (c *Collector) collectPrinterJobStatus(ch chan<- prometheus.Metric) error { +func (c *Collector) collectPrinterJobStatus(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error { var printJobs []wmiPrintJob - if err := c.miSession.Query(&printJobs, mi.NamespaceRootCIMv2, c.miQueryPrinterJobs); err != nil { + if err := c.miSession.Query(&printJobs, mi.NamespaceRootCIMv2, c.miQueryPrinterJobs, maxScrapeDuration); err != nil { return fmt.Errorf("WMI query failed: %w", err) } diff --git a/internal/collector/process/process.go b/internal/collector/process/process.go index 5848cfb3..1b3d1a68 100644 --- a/internal/collector/process/process.go +++ b/internal/collector/process/process.go @@ -26,6 +26,7 @@ import ( "strconv" "strings" "sync" + "time" "unsafe" "github.com/alecthomas/kingpin/v2" @@ -332,7 +333,7 @@ func (c *Collector) Build(logger *slog.Logger, miSession *mi.Session) error { var workerProcesses []WorkerProcess - if err = c.miSession.Query(&workerProcesses, mi.NamespaceRootWebAdministration, c.workerProcessMIQueryQuery); err != nil { + if err = c.miSession.Query(&workerProcesses, mi.NamespaceRootWebAdministration, c.workerProcessMIQueryQuery, 0); err != nil { c.config.EnableWorkerProcess = false return fmt.Errorf("WMI query for collector.process.iis failed: %w", err) @@ -342,8 +343,8 @@ func (c *Collector) Build(logger *slog.Logger, miSession *mi.Session) error { return nil } -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { - return c.collect(ch) +func (c *Collector) Collect(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error { + return c.collect(ch, maxScrapeDuration) } // ref: https://github.com/microsoft/hcsshim/blob/8beabacfc2d21767a07c20f8dd5f9f3932dbf305/internal/uvm/stats.go#L25 diff --git a/internal/collector/process/process_worker.go b/internal/collector/process/process_worker.go index 03640d80..a7e6652b 100644 --- a/internal/collector/process/process_worker.go +++ b/internal/collector/process/process_worker.go @@ -39,7 +39,7 @@ type processWorkerRequest struct { workerProcesses []WorkerProcess } -func (c *Collector) collect(ch chan<- prometheus.Metric) error { +func (c *Collector) collect(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error { err := c.perfDataCollector.Collect(&c.perfDataObject) if err != nil { return fmt.Errorf("failed to collect metrics: %w", err) @@ -49,7 +49,7 @@ func (c *Collector) collect(ch chan<- prometheus.Metric) error { var workerProcesses []WorkerProcess if c.config.EnableWorkerProcess { - if err = c.miSession.Query(&workerProcesses, mi.NamespaceRootWebAdministration, c.workerProcessMIQueryQuery); err != nil { + if err = c.miSession.Query(&workerProcesses, mi.NamespaceRootWebAdministration, c.workerProcessMIQueryQuery, maxScrapeDuration); err != nil { err = fmt.Errorf("WMI query for collector.process.iis failed: %w", err) } } diff --git a/internal/collector/remote_fx/remote_fx.go b/internal/collector/remote_fx/remote_fx.go index d37970ef..b239285b 100644 --- a/internal/collector/remote_fx/remote_fx.go +++ b/internal/collector/remote_fx/remote_fx.go @@ -22,6 +22,7 @@ import ( "fmt" "log/slog" "strings" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -247,7 +248,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { errs := make([]error, 0) if err := c.collectRemoteFXNetworkCount(ch); err != nil { diff --git a/internal/collector/scheduled_task/scheduled_task.go b/internal/collector/scheduled_task/scheduled_task.go index 00e3c117..4e47fdd8 100644 --- a/internal/collector/scheduled_task/scheduled_task.go +++ b/internal/collector/scheduled_task/scheduled_task.go @@ -24,6 +24,7 @@ import ( "regexp" "runtime" "strings" + "time" "github.com/alecthomas/kingpin/v2" "github.com/go-ole/go-ole" @@ -173,7 +174,7 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error { return nil } -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { return c.collect(ch) } diff --git a/internal/collector/service/service.go b/internal/collector/service/service.go index e813efbc..5a1b8573 100644 --- a/internal/collector/service/service.go +++ b/internal/collector/service/service.go @@ -25,6 +25,7 @@ import ( "regexp" "strconv" "sync" + "time" "unsafe" "github.com/alecthomas/kingpin/v2" @@ -211,7 +212,7 @@ func (c *Collector) Close() error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { services, err := c.queryAllServices() if err != nil { return fmt.Errorf("failed to query all services: %w", err) diff --git a/internal/collector/smb/smb.go b/internal/collector/smb/smb.go index f4b6b38f..0d00f465 100644 --- a/internal/collector/smb/smb.go +++ b/internal/collector/smb/smb.go @@ -20,6 +20,7 @@ package smb import ( "fmt" "log/slog" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -138,7 +139,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { } // Collect collects smb metrics and sends them to prometheus. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { err := c.perfDataCollector.Collect(&c.perfDataObject) if err != nil { return fmt.Errorf("failed to collect SMB Server Shares metrics: %w", err) diff --git a/internal/collector/smbclient/smbclient.go b/internal/collector/smbclient/smbclient.go index 5d7ed56f..0fc522c1 100644 --- a/internal/collector/smbclient/smbclient.go +++ b/internal/collector/smbclient/smbclient.go @@ -21,6 +21,7 @@ import ( "fmt" "log/slog" "strings" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -199,7 +200,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { } // Collect collects smb client metrics and sends them to prometheus. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { err := c.perfDataCollector.Collect(&c.perfDataObject) if err != nil { return fmt.Errorf("failed to collect SMB Client Shares metrics: %w", err) diff --git a/internal/collector/smtp/smtp.go b/internal/collector/smtp/smtp.go index e33e664c..7c832769 100644 --- a/internal/collector/smtp/smtp.go +++ b/internal/collector/smtp/smtp.go @@ -21,6 +21,7 @@ import ( "fmt" "log/slog" "regexp" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -428,7 +429,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { err := c.perfDataCollector.Collect(&c.perfDataObject) if err != nil { return fmt.Errorf("failed to collect SMTP Server metrics: %w", err) diff --git a/internal/collector/system/system.go b/internal/collector/system/system.go index a2068880..d0bf559e 100644 --- a/internal/collector/system/system.go +++ b/internal/collector/system/system.go @@ -147,7 +147,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { err := c.perfDataCollector.Collect(&c.perfDataObject) if err != nil { return fmt.Errorf("failed to collect System metrics: %w", err) diff --git a/internal/collector/tcp/tcp.go b/internal/collector/tcp/tcp.go index 9ece359f..b947925e 100644 --- a/internal/collector/tcp/tcp.go +++ b/internal/collector/tcp/tcp.go @@ -23,6 +23,7 @@ import ( "log/slog" "slices" "strings" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/headers/iphlpapi" @@ -212,7 +213,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { errs := make([]error, 0) if slices.Contains(c.config.CollectorsEnabled, subCollectorMetrics) { diff --git a/internal/collector/terminal_services/terminal_services.go b/internal/collector/terminal_services/terminal_services.go index 43e965d1..13b3158c 100644 --- a/internal/collector/terminal_services/terminal_services.go +++ b/internal/collector/terminal_services/terminal_services.go @@ -23,6 +23,7 @@ import ( "log/slog" "strconv" "strings" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/headers/wtsapi32" @@ -50,7 +51,7 @@ type Win32_ServerFeature struct { func isConnectionBrokerServer(miSession *mi.Session) bool { var dst []Win32_ServerFeature - if err := miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * FROM Win32_ServerFeature"))); err != nil { + if err := miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * FROM Win32_ServerFeature")), 0); err != nil { return false } @@ -260,7 +261,7 @@ func (c *Collector) Build(logger *slog.Logger, miSession *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { errs := make([]error, 0) if err := c.collectWTSSessions(ch); err != nil { diff --git a/internal/collector/textfile/textfile.go b/internal/collector/textfile/textfile.go index fe777e22..0a97d015 100644 --- a/internal/collector/textfile/textfile.go +++ b/internal/collector/textfile/textfile.go @@ -303,7 +303,7 @@ func (cr carriageReturnFilteringReader) Read(p []byte) (int, error) { } // Collect implements the Collector interface. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { mTimes := map[string]time.Time{} // Create empty metricFamily slice here and append parsedFamilies to it inside the loop. diff --git a/internal/collector/textfile/textfile_test_test.go b/internal/collector/textfile/textfile_test_test.go index 99920b54..2cb33063 100644 --- a/internal/collector/textfile/textfile_test_test.go +++ b/internal/collector/textfile/textfile_test_test.go @@ -53,7 +53,7 @@ func TestMultipleDirectories(t *testing.T) { errCh := make(chan error, 1) go func() { - errCh <- textFileCollector.Collect(metrics) + errCh <- textFileCollector.Collect(metrics, 0) close(metrics) }() @@ -91,7 +91,7 @@ func TestDuplicateFileName(t *testing.T) { errCh := make(chan error, 1) go func() { - errCh <- textFileCollector.Collect(metrics) + errCh <- textFileCollector.Collect(metrics, 0) close(metrics) }() diff --git a/internal/collector/thermalzone/thermalzone.go b/internal/collector/thermalzone/thermalzone.go index 89b6133c..aca704f8 100644 --- a/internal/collector/thermalzone/thermalzone.go +++ b/internal/collector/thermalzone/thermalzone.go @@ -20,6 +20,7 @@ package thermalzone import ( "fmt" "log/slog" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -113,7 +114,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { err := c.perfDataCollector.Collect(&c.perfDataObject) if err != nil { return fmt.Errorf("failed to collect Thermal Zone Information metrics: %w", err) diff --git a/internal/collector/time/time.go b/internal/collector/time/time.go index e058794a..a475f96f 100644 --- a/internal/collector/time/time.go +++ b/internal/collector/time/time.go @@ -217,7 +217,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { errs := make([]error, 0) if slices.Contains(c.config.CollectorsEnabled, collectorSystemTime) { @@ -274,6 +274,8 @@ func (c *Collector) collectClockSource(ch chan<- prometheus.Metric) error { return fmt.Errorf("failed to open registry key: %w", err) } + defer key.Close() + val, _, err := key.GetStringValue("Type") if err != nil { return fmt.Errorf("failed to read 'Type' value: %w", err) @@ -293,12 +295,6 @@ func (c *Collector) collectClockSource(ch chan<- prometheus.Metric) error { ) } - if err := key.Close(); err != nil { - c.logger.Debug("failed to close registry key", - slog.Any("err", err), - ) - } - return nil } diff --git a/internal/collector/udp/udp.go b/internal/collector/udp/udp.go index b01af81b..6cd56d56 100644 --- a/internal/collector/udp/udp.go +++ b/internal/collector/udp/udp.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "log/slog" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -127,7 +128,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { return c.collect(ch) } diff --git a/internal/collector/update/update.go b/internal/collector/update/update.go index e54cc5cf..95f45833 100644 --- a/internal/collector/update/update.go +++ b/internal/collector/update/update.go @@ -155,7 +155,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { func (c *Collector) GetName() string { return Name } -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { c.mu.RLock() defer c.mu.RUnlock() diff --git a/internal/collector/vmware/vmware.go b/internal/collector/vmware/vmware.go index 71b34ca5..3ebb1f45 100644 --- a/internal/collector/vmware/vmware.go +++ b/internal/collector/vmware/vmware.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "log/slog" + "time" "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/mi" @@ -231,7 +232,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { // Collect sends the metric values for each metric // to the provided prometheus Metric channel. -func (c *Collector) Collect(ch chan<- prometheus.Metric) error { +func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { errs := make([]error, 0) if err := c.collectCpu(ch); err != nil { diff --git a/internal/mi/application.go b/internal/mi/application.go index 8e962f6f..bddcca19 100644 --- a/internal/mi/application.go +++ b/internal/mi/application.go @@ -205,6 +205,16 @@ func (application *Application) NewOperationOptions() (*OperationOptions, error) return operationOptions, nil } +// MustNewOperationOptions is the panicking version of NewOperationOptions. +func (application *Application) MustNewOperationOptions() *OperationOptions { + operationOptions, err := application.NewOperationOptions() + if err != nil { + panic(fmt.Sprintf("failed to create operation options: %v", err)) + } + + return operationOptions +} + // NewDestinationOptions creates an DestinationOptions object that can be used with the Application.NewSession function. // // https://learn.microsoft.com/en-us/windows/win32/api/mi/nf-mi-mi_application_newdestinationoptions diff --git a/internal/mi/mi_test.go b/internal/mi/mi_test.go index 1d6427b5..0facd390 100644 --- a/internal/mi/mi_test.go +++ b/internal/mi/mi_test.go @@ -257,7 +257,7 @@ func Test_MI_FD_Leak(t *testing.T) { for range 300 { var processes []win32Process - err := session.Query(&processes, mi.NamespaceRootCIMv2, queryPrinter) + err := session.Query(&processes, mi.NamespaceRootCIMv2, queryPrinter, -1) require.NoError(t, err) currentFileHandle, err = testutils.GetProcessHandleCount(windows.CurrentProcess()) @@ -287,3 +287,48 @@ func Test_MI_FD_Leak(t *testing.T) { t.Log("Current File Handle Count: ", currentFileHandle) } + +func Test_MI_QueryTimeout(t *testing.T) { + application, err := mi.ApplicationInitialize() + require.NoError(t, err) + require.NotEmpty(t, application) + + destinationOptions, err := application.NewDestinationOptions() + require.NoError(t, err) + require.NotEmpty(t, destinationOptions) + + err = destinationOptions.SetTimeout(1 * time.Second) + require.NoError(t, err) + + err = destinationOptions.SetLocale(mi.LocaleEnglish) + require.NoError(t, err) + + session, err := application.NewSession(destinationOptions) + require.NoError(t, err) + require.NotEmpty(t, session) + + operationOptions, err := application.NewOperationOptions() + require.NoError(t, err) + require.NotEmpty(t, operationOptions) + + err = operationOptions.SetTimeout(1 * time.Millisecond) + require.NoError(t, err) + + operation, err := session.QueryInstances(mi.OperationFlagsStandardRTTI, operationOptions, mi.NamespaceRootCIMv2, mi.QueryDialectWQL, "select Name from win32_process where handle = 0") + require.NoError(t, err) + require.NotEmpty(t, operation) + + instance, moreResults, err := operation.GetInstance() + require.ErrorIs(t, err, mi.MI_RESULT_INVALID_OPERATION_TIMEOUT) + require.False(t, moreResults) + require.Empty(t, instance) + + err = operation.Close() + require.NoError(t, err) + + err = session.Close() + require.NoError(t, err) + + err = application.Close() + require.NoError(t, err) +} diff --git a/internal/mi/operation.go b/internal/mi/operation.go index c187625b..051a2cdf 100644 --- a/internal/mi/operation.go +++ b/internal/mi/operation.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "reflect" + "strings" "syscall" "time" "unsafe" @@ -150,8 +151,35 @@ func (o *Operation) GetInstance() (*Instance, bool, error) { uintptr(unsafe.Pointer(&errorMessageUTF16)), uintptr(unsafe.Pointer(&errorDetails)), ) + + //nolint:nestif if !errors.Is(instanceResult, MI_RESULT_OK) { - return nil, false, fmt.Errorf("instance result: %w (%s)", instanceResult, windows.UTF16PtrToString(errorMessageUTF16)) + errorMessage := strings.TrimSpace(windows.UTF16PtrToString(errorMessageUTF16)) + + // We need a language neutral way to detect an operation timeout, because MI_RESULT_OPERATION_TIMED_OUT + // is not returned by the API, but instead we get MI_RESULT_INVALID_OPERATION_TIMEOUT with a specific error code + // in the error details. + if errorDetails != nil { + count, _ := errorDetails.GetElementCount() + if count != 0 { + errorCodeRaw, err := errorDetails.GetElement("error_Code") + if err == nil { + errorCodeValue, _ := errorCodeRaw.GetValue() + + errorCode, ok := errorCodeValue.(uint32) + if ok && errorCode == 262148 { + instanceResult = MI_RESULT_INVALID_OPERATION_TIMEOUT + errorMessage = "" + } + } + } + } + + if errorMessage != "" { + errorMessage = fmt.Sprintf(" (%s)", errorMessage) + } + + return nil, false, fmt.Errorf("instance result: %w%s", instanceResult, errorMessage) } if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) { @@ -273,6 +301,20 @@ func (o *OperationOptions) SetTimeout(timeout time.Duration) error { return nil } +func (o *OperationOptions) Close() error { + if o == nil || o.ft == nil { + return ErrNotInitialized + } + + r0, _, _ := syscall.SyscallN(o.ft.Clone, uintptr(unsafe.Pointer(o))) + + if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) { + return result + } + + return nil +} + func (o *OperationOptions) Delete() error { if o == nil || o.ft == nil { return ErrNotInitialized diff --git a/internal/mi/session.go b/internal/mi/session.go index f77f87d3..eedd480b 100644 --- a/internal/mi/session.go +++ b/internal/mi/session.go @@ -22,6 +22,7 @@ import ( "fmt" "reflect" "syscall" + "time" "unsafe" "golang.org/x/sys/windows" @@ -229,7 +230,7 @@ func (s *Session) QueryUnmarshal(dst any, ) if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) { - return result + return fmt.Errorf("failed to query instances: %w", result) } defer func() { @@ -308,11 +309,28 @@ func (s *Session) QueryUnmarshal(dst any, } // Query queries for a set of instances based on a query expression. -func (s *Session) Query(dst any, namespaceName Namespace, queryExpression Query) error { - err := s.QueryUnmarshal(dst, OperationFlagsStandardRTTI, nil, namespaceName, QueryDialectWQL, queryExpression) - if err != nil { - return fmt.Errorf("WMI query failed: %w", err) +// +//nolint:nestif +func (s *Session) Query(dst any, namespaceName Namespace, queryExpression Query, queryTimeout time.Duration) error { + var operationOptions *OperationOptions + + if queryTimeout >= 0 { + app, err := s.GetApplication() + if err != nil { + return fmt.Errorf("failed to get application: %w", err) + } + + operationOptions, err = app.NewOperationOptions() + if err != nil { + return fmt.Errorf("failed to create operation options: %w", err) + } + + if queryTimeout > 0 { + if err = operationOptions.SetTimeout(queryTimeout); err != nil { + return fmt.Errorf("failed to set timeout: %w", err) + } + } } - return nil + return s.QueryUnmarshal(dst, OperationFlagsStandardRTTI, operationOptions, namespaceName, QueryDialectWQL, queryExpression) } diff --git a/internal/pdh/collector.go b/internal/pdh/collector.go index 29f3b5a9..9321b6a9 100644 --- a/internal/pdh/collector.go +++ b/internal/pdh/collector.go @@ -221,7 +221,7 @@ func NewCollectorWithReflection(logger *slog.Logger, resultType CounterType, obj } if counter.Type == PERF_ELAPSED_TIME { - if ret := GetCounterTimeBase(counterHandle, &counter.Frequency); ret != ErrorSuccess { + if ret := GetCounterTimeBase(counterHandle, &counter.Frequency); ret != ErrorSuccess && ret != NoData { errs = append(errs, fmt.Errorf("GetCounterTimeBase: %w", NewPdhError(ret))) continue diff --git a/internal/utils/testutils/testutils.go b/internal/utils/testutils/testutils.go index c2779546..0643595e 100644 --- a/internal/utils/testutils/testutils.go +++ b/internal/utils/testutils/testutils.go @@ -60,8 +60,10 @@ func FuncBenchmarkCollector[C collector.Collector](b *testing.B, name string, co }() for b.Loop() { - require.NoError(b, c.Collect(metrics)) + require.NoError(b, c.Collect(metrics, 0)) } + + require.NoError(b, collectors.Close()) } func TestCollector[C collector.Collector, V any](t *testing.T, fn func(*V) C, conf *V) { @@ -110,7 +112,7 @@ func TestCollector[C collector.Collector, V any](t *testing.T, fn func(*V) C, co time.Sleep(1 * time.Second) - err = c.Collect(ch) + err = c.Collect(ch, 0) switch { // container collector diff --git a/pkg/collector/collect.go b/pkg/collector/collect.go index 0784611f..17272047 100644 --- a/pkg/collector/collect.go +++ b/pkg/collector/collect.go @@ -136,7 +136,7 @@ func (c *Collection) collectCollector(ch chan<- prometheus.Metric, logger *slog. close(bufCh) }() - errCh <- collector.Collect(bufCh) + errCh <- collector.Collect(bufCh, maxScrapeDuration) }() wg := sync.WaitGroup{} diff --git a/pkg/collector/collection.go b/pkg/collector/collection.go index fe77af79..277177b2 100644 --- a/pkg/collector/collection.go +++ b/pkg/collector/collection.go @@ -244,6 +244,7 @@ func (c *Collection) Build(ctx context.Context, logger *slog.Logger) error { errors.Is(err, registry.ErrNotExist) || errors.Is(err, pdh.NewPdhError(pdh.CstatusNoObject)) || errors.Is(err, pdh.NewPdhError(pdh.CstatusNoCounter)) || + errors.Is(err, mi.MI_RESULT_INVALID_OPERATION_TIMEOUT) || errors.Is(err, mi.MI_RESULT_INVALID_NAMESPACE) { logger.LogAttrs(ctx, slog.LevelWarn, "couldn't initialize collector", slog.Any("err", err)) diff --git a/pkg/collector/types.go b/pkg/collector/types.go index 2830139d..e191ea7c 100644 --- a/pkg/collector/types.go +++ b/pkg/collector/types.go @@ -52,7 +52,7 @@ type Collector interface { // Build build the collector Build(logger *slog.Logger, miSession *mi.Session) error // Collect Get new metrics and expose them via prometheus registry. - Collect(ch chan<- prometheus.Metric) (err error) + Collect(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) (err error) // Close closes the collector Close() error }