From a31fae00d1f80384ac66df4bde662d845367bb9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Sat, 10 Oct 2026 16:09:43 +0200 Subject: [PATCH] fix(cpu_info,diskdrive): stop probing WMI during Build (#2648) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Claude Opus 5.5 Signed-off-by: Jan-Otto Kröpke --- internal/collector/cpu_info/cpu_info.go | 8 +++----- internal/collector/cpu_info/cpu_info_test.go | 16 ++++++++++++++++ internal/collector/diskdrive/diskdrive.go | 8 +++----- internal/collector/diskdrive/diskdrive_test.go | 16 ++++++++++++++++ 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/internal/collector/cpu_info/cpu_info.go b/internal/collector/cpu_info/cpu_info.go index 3190134b..ee47decb 100644 --- a/internal/collector/cpu_info/cpu_info.go +++ b/internal/collector/cpu_info/cpu_info.go @@ -151,11 +151,9 @@ func (c *Collector) Build(_ *slog.Logger, miSession *mi.Session) error { c.miQuery = miQuery c.miSession = miSession - var dst []miProcessor - if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, c.miQuery, 0); err != nil { - return fmt.Errorf("WMI query failed: %w", err) - } - + // Win32_Processor exists on every supported Windows version, so Build does not probe it. + // WMI can time out shortly after boot. A probe would disable the collector until restart, + // while a failing Collect only fails the affected scrapes. return nil } diff --git a/internal/collector/cpu_info/cpu_info_test.go b/internal/collector/cpu_info/cpu_info_test.go index e864d345..b2af4c30 100644 --- a/internal/collector/cpu_info/cpu_info_test.go +++ b/internal/collector/cpu_info/cpu_info_test.go @@ -18,10 +18,15 @@ package cpu_info_test import ( + "log/slog" "testing" + "time" "github.com/prometheus-community/windows_exporter/internal/collector/cpu_info" + "github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/utils/testutils" + "github.com/prometheus/client_golang/prometheus" + "github.com/stretchr/testify/require" ) func BenchmarkCollector(b *testing.B) { @@ -31,3 +36,14 @@ func BenchmarkCollector(b *testing.B) { func TestCollector(t *testing.T) { testutils.TestCollector(t, cpu_info.New, nil) } + +// A WMI failure during Build must not disable the collector until restart, so +// Build must not query WMI. The uninitialized session fails every query. +func TestBuildDoesNotQueryWMI(t *testing.T) { + c := cpu_info.New(nil) + + t.Cleanup(func() { require.NoError(t, c.Close()) }) + + require.NoError(t, c.Build(slog.New(slog.DiscardHandler), &mi.Session{})) + require.ErrorIs(t, c.Collect(make(chan prometheus.Metric, 64), time.Second), mi.ErrNotInitialized) +} diff --git a/internal/collector/diskdrive/diskdrive.go b/internal/collector/diskdrive/diskdrive.go index c9d7d47b..40f9e411 100644 --- a/internal/collector/diskdrive/diskdrive.go +++ b/internal/collector/diskdrive/diskdrive.go @@ -127,11 +127,9 @@ func (c *Collector) Build(logger *slog.Logger, miSession *mi.Session) error { c.miQuery = miQuery c.miSession = miSession - var dst []diskDrive - if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, c.miQuery, 0); err != nil { - return fmt.Errorf("WMI query failed: %w", err) - } - + // Win32_DiskDrive exists on every supported Windows version, so Build does not probe it. + // WMI can time out shortly after boot. A probe would disable the collector until restart, + // while a failing Collect only fails the affected scrapes. return nil } diff --git a/internal/collector/diskdrive/diskdrive_test.go b/internal/collector/diskdrive/diskdrive_test.go index 9cd79f0e..31b9fe28 100644 --- a/internal/collector/diskdrive/diskdrive_test.go +++ b/internal/collector/diskdrive/diskdrive_test.go @@ -18,10 +18,15 @@ package diskdrive_test import ( + "log/slog" "testing" + "time" "github.com/prometheus-community/windows_exporter/internal/collector/diskdrive" + "github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/utils/testutils" + "github.com/prometheus/client_golang/prometheus" + "github.com/stretchr/testify/require" ) func BenchmarkCollector(b *testing.B) { @@ -31,3 +36,14 @@ func BenchmarkCollector(b *testing.B) { func TestCollector(t *testing.T) { testutils.TestCollector(t, diskdrive.New, nil) } + +// A WMI failure during Build must not disable the collector until restart, so +// Build must not query WMI. The uninitialized session fails every query. +func TestBuildDoesNotQueryWMI(t *testing.T) { + c := diskdrive.New(nil) + + t.Cleanup(func() { require.NoError(t, c.Close()) }) + + require.NoError(t, c.Build(slog.New(slog.DiscardHandler), &mi.Session{})) + require.ErrorIs(t, c.Collect(make(chan prometheus.Metric, 64), time.Second), mi.ErrNotInitialized) +}