From 897855ac16fe36da1920b0a6135ad619cb6d76c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Sun, 11 Oct 2026 18:47:21 +0200 Subject: [PATCH] process, gpu, hyperv, netframework: reuse label pairs of unchanged series (#2685) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan-Otto Kröpke --- internal/collector/gpu/gpu.go | 67 +++--- internal/collector/gpu/utils.go | 74 ++++++ internal/collector/gpu/utils_internal_test.go | 35 +++ internal/collector/hyperv/hyperv.go | 18 +- internal/collector/hyperv/hyperv_datastore.go | 95 ++++---- .../hyperv/hyperv_dynamic_memory_balancer.go | 11 +- .../hyperv/hyperv_dynamic_memory_vm.go | 23 +- internal/collector/hyperv/hyperv_host.go | 9 +- .../hyperv_hypervisor_logical_processor.go | 13 +- .../hyperv_hypervisor_root_partition.go | 45 ++-- ...yperv_hypervisor_root_virtual_processor.go | 13 +- .../hyperv_hypervisor_virtual_processor.go | 21 +- .../hyperv/hyperv_legacy_network_adapter.go | 15 +- .../collector/hyperv/hyperv_replica_vm.go | 33 +-- .../hyperv_virtual_machine_health_summary.go | 7 +- .../hyperv_virtual_machine_vid_partition.go | 9 +- .../hyperv/hyperv_virtual_network_adapter.go | 15 +- ...rv_virtual_network_adapter_drop_reasons.go | 103 ++++----- .../collector/hyperv/hyperv_virtual_smb.go | 37 +-- .../hyperv/hyperv_virtual_storage_device.go | 31 +-- .../collector/hyperv/hyperv_virtual_switch.go | 45 ++-- .../collector/hyperv/hyperv_wmi_health.go | 5 +- .../hyperv/interrupt_mappings_test.go | 2 +- .../collector/netframework/netframework.go | 17 +- .../netframework_clrexceptions.go | 11 +- .../netframework/netframework_clrinterop.go | 9 +- .../netframework/netframework_clrjit.go | 11 +- .../netframework/netframework_clrloading.go | 21 +- .../netframework_clrlocksandthreads.go | 17 +- .../netframework/netframework_clrmemory.go | 39 ++-- .../netframework/netframework_clrremoting.go | 15 +- .../netframework/netframework_clrsecurity.go | 11 +- .../netframework/netframework_pdh_test.go | 26 ++- internal/collector/process/process.go | 57 +++-- internal/labelcache/labelcache.go | 212 +++++++++++++++++ internal/labelcache/labelcache_test.go | 214 ++++++++++++++++++ 36 files changed, 1002 insertions(+), 384 deletions(-) create mode 100644 internal/labelcache/labelcache.go create mode 100644 internal/labelcache/labelcache_test.go diff --git a/internal/collector/gpu/gpu.go b/internal/collector/gpu/gpu.go index 4ca71a81..0d19bce5 100644 --- a/internal/collector/gpu/gpu.go +++ b/internal/collector/gpu/gpu.go @@ -26,6 +26,7 @@ import ( "github.com/alecthomas/kingpin/v2" "github.com/prometheus-community/windows_exporter/internal/headers/cfgmgr32" "github.com/prometheus-community/windows_exporter/internal/headers/gdi32" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/pdh" "github.com/prometheus-community/windows_exporter/internal/types" @@ -57,6 +58,12 @@ type Collector struct { // It is replaced in tests to make the discovery deterministic. discoverGPUDevices func() ([]gdi32.GPUDevice, error) + // labels keeps the label pairs of the series of the last scrape, and + // instances the parsed counter instance names, so neither is built again + // while the GPU process or engine stays. + labels labelcache.Cache + instances instanceCache + // GPU Engine gpuEnginePerfDataCollector *pdh.Collector[gpuEnginePerfDataCounterValues] gpuEnginePerfDataObject []gpuEnginePerfDataCounterValues @@ -140,6 +147,8 @@ func (c *Collector) Close() error { c.gpuLocalAdapterMemoryPerfDataCollector.Close() c.gpuNonLocalAdapterMemoryPerfDataCollector.Close() c.gpuProcessMemoryPerfDataCollector.Close() + c.labels.Reset() + c.instances.reset() return nil } @@ -400,23 +409,29 @@ func (c *Collector) getGPUDevice(luid string) (gpuDevice, bool) { func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { errs := make([]error, 0) - if err := c.collectGpuEngineMetrics(ch); err != nil { + scrape := c.labels.Begin() + defer scrape.Commit() + + instances := c.instances.begin() + defer instances.commit() + + if err := c.collectGpuEngineMetrics(ch, scrape, instances); err != nil { errs = append(errs, err) } - if err := c.collectGpuAdapterMemoryMetrics(ch); err != nil { + if err := c.collectGpuAdapterMemoryMetrics(ch, scrape, instances); err != nil { errs = append(errs, err) } - if err := c.collectGpuLocalAdapterMemoryMetrics(ch); err != nil { + if err := c.collectGpuLocalAdapterMemoryMetrics(ch, scrape, instances); err != nil { errs = append(errs, err) } - if err := c.collectGpuNonLocalAdapterMemoryMetrics(ch); err != nil { + if err := c.collectGpuNonLocalAdapterMemoryMetrics(ch, scrape, instances); err != nil { errs = append(errs, err) } - if err := c.collectGpuProcessMemoryMetrics(ch); err != nil { + if err := c.collectGpuProcessMemoryMetrics(ch, scrape, instances); err != nil { errs = append(errs, err) } @@ -471,7 +486,7 @@ func (c *Collector) collectGpuInfo(ch chan<- prometheus.Metric) { } } -func (c *Collector) collectGpuEngineMetrics(ch chan<- prometheus.Metric) error { +func (c *Collector) collectGpuEngineMetrics(ch chan<- prometheus.Metric, scrape *labelcache.Scrape, instances *instanceScrape) error { // Collect the GPU Engine perf data. if err := c.gpuEnginePerfDataCollector.Collect(&c.gpuEnginePerfDataObject); err != nil { return fmt.Errorf("failed to collect GPU Engine perf data: %w", err) @@ -479,14 +494,14 @@ func (c *Collector) collectGpuEngineMetrics(ch chan<- prometheus.Metric) error { // Iterate over the GPU Engine perf data and aggregate the values. for _, data := range c.gpuEnginePerfDataObject { - instance := parseGPUCounterInstanceString(data.Name) + instance := instances.parse(data.Name) device, ok := c.getGPUDevice(instance.Luid) if !ok { continue } - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.gpuEngineRunningTime, prometheus.CounterValue, data.RunningTime/10_000_000, @@ -497,35 +512,35 @@ func (c *Collector) collectGpuEngineMetrics(ch chan<- prometheus.Metric) error { return nil } -func (c *Collector) collectGpuAdapterMemoryMetrics(ch chan<- prometheus.Metric) error { +func (c *Collector) collectGpuAdapterMemoryMetrics(ch chan<- prometheus.Metric, scrape *labelcache.Scrape, instances *instanceScrape) error { // Collect the GPU Adapter Memory perf data. if err := c.gpuAdapterMemoryPerfDataCollector.Collect(&c.gpuAdapterMemoryPerfDataObject); err != nil { return fmt.Errorf("failed to collect GPU Adapter Memory perf data: %w", err) } for _, data := range c.gpuAdapterMemoryPerfDataObject { - instance := parseGPUCounterInstanceString(data.Name) + instance := instances.parse(data.Name) device, ok := c.getGPUDevice(instance.Luid) if !ok { continue } - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.gpuAdapterMemoryDedicatedUsage, prometheus.GaugeValue, data.DedicatedUsage, instance.Luid, device.ID, instance.Phys, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.gpuAdapterMemorySharedUsage, prometheus.GaugeValue, data.SharedUsage, instance.Luid, device.ID, instance.Phys, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.gpuAdapterMemoryTotalCommitted, prometheus.GaugeValue, data.TotalCommitted, @@ -536,21 +551,21 @@ func (c *Collector) collectGpuAdapterMemoryMetrics(ch chan<- prometheus.Metric) return nil } -func (c *Collector) collectGpuLocalAdapterMemoryMetrics(ch chan<- prometheus.Metric) error { +func (c *Collector) collectGpuLocalAdapterMemoryMetrics(ch chan<- prometheus.Metric, scrape *labelcache.Scrape, instances *instanceScrape) error { // Collect the GPU Local Adapter Memory perf data. if err := c.gpuLocalAdapterMemoryPerfDataCollector.Collect(&c.gpuLocalAdapterMemoryPerfDataObject); err != nil { return fmt.Errorf("failed to collect GPU Local Adapter Memory perf data: %w", err) } for _, data := range c.gpuLocalAdapterMemoryPerfDataObject { - instance := parseGPUCounterInstanceString(data.Name) + instance := instances.parse(data.Name) device, ok := c.getGPUDevice(instance.Luid) if !ok { continue } - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.gpuLocalAdapterMemoryUsage, prometheus.GaugeValue, data.LocalUsage, @@ -561,21 +576,21 @@ func (c *Collector) collectGpuLocalAdapterMemoryMetrics(ch chan<- prometheus.Met return nil } -func (c *Collector) collectGpuNonLocalAdapterMemoryMetrics(ch chan<- prometheus.Metric) error { +func (c *Collector) collectGpuNonLocalAdapterMemoryMetrics(ch chan<- prometheus.Metric, scrape *labelcache.Scrape, instances *instanceScrape) error { // Collect the GPU Non Local Adapter Memory perf data. if err := c.gpuNonLocalAdapterMemoryPerfDataCollector.Collect(&c.gpuNonLocalAdapterMemoryPerfDataObject); err != nil { return fmt.Errorf("failed to collect GPU Non Local Adapter Memory perf data: %w", err) } for _, data := range c.gpuNonLocalAdapterMemoryPerfDataObject { - instance := parseGPUCounterInstanceString(data.Name) + instance := instances.parse(data.Name) device, ok := c.getGPUDevice(instance.Luid) if !ok { continue } - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.gpuNonLocalAdapterMemoryUsage, prometheus.GaugeValue, data.NonLocalUsage, @@ -586,49 +601,49 @@ func (c *Collector) collectGpuNonLocalAdapterMemoryMetrics(ch chan<- prometheus. return nil } -func (c *Collector) collectGpuProcessMemoryMetrics(ch chan<- prometheus.Metric) error { +func (c *Collector) collectGpuProcessMemoryMetrics(ch chan<- prometheus.Metric, scrape *labelcache.Scrape, instances *instanceScrape) error { // Collect the GPU Process Memory perf data. if err := c.gpuProcessMemoryPerfDataCollector.Collect(&c.gpuProcessMemoryPerfDataObject); err != nil { return fmt.Errorf("failed to collect GPU Process Memory perf data: %w", err) } for _, data := range c.gpuProcessMemoryPerfDataObject { - instance := parseGPUCounterInstanceString(data.Name) + instance := instances.parse(data.Name) device, ok := c.getGPUDevice(instance.Luid) if !ok { continue } - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.gpuProcessMemoryDedicatedUsage, prometheus.GaugeValue, data.DedicatedUsage, instance.Pid, instance.Luid, device.ID, instance.Phys, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.gpuProcessMemoryLocalUsage, prometheus.GaugeValue, data.LocalUsage, instance.Pid, instance.Luid, device.ID, instance.Phys, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.gpuProcessMemoryNonLocalUsage, prometheus.GaugeValue, data.NonLocalUsage, instance.Pid, instance.Luid, device.ID, instance.Phys, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.gpuProcessMemorySharedUsage, prometheus.GaugeValue, data.SharedUsage, instance.Pid, instance.Luid, device.ID, instance.Phys, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.gpuProcessMemoryTotalCommitted, prometheus.GaugeValue, data.TotalCommitted, diff --git a/internal/collector/gpu/utils.go b/internal/collector/gpu/utils.go index 7c0ede7c..dc540eaa 100644 --- a/internal/collector/gpu/utils.go +++ b/internal/collector/gpu/utils.go @@ -20,6 +20,7 @@ package gpu import ( "fmt" "strings" + "sync" "github.com/prometheus-community/windows_exporter/internal/headers/gdi32" ) @@ -84,3 +85,76 @@ func parseGPUCounterInstanceString(s string) Instance { return instance } + +// instanceCache keeps the parsed counter instance names of the last scrape. +// The same instances appear in every scrape while a GPU process or engine +// exists, so they are only parsed once. +type instanceCache struct { + mu sync.Mutex + entries map[string]Instance +} + +// instanceScrape parses the instance names of one scrape. +type instanceScrape struct { + cache *instanceCache + // prev is the last committed generation. It is never modified, so it is + // read without holding mu. + prev map[string]Instance + + mu sync.Mutex + next map[string]Instance +} + +func (c *instanceCache) begin() *instanceScrape { + c.mu.Lock() + prev := c.entries + c.mu.Unlock() + + return &instanceScrape{cache: c, prev: prev, next: make(map[string]Instance, len(prev))} +} + +func (c *instanceCache) reset() { + c.mu.Lock() + c.entries = nil + c.mu.Unlock() +} + +// parse returns parseGPUCounterInstanceString(name), reusing the result of +// the previous scrape. +func (s *instanceScrape) parse(name string) Instance { + instance, ok := s.prev[name] + + s.mu.Lock() + if !ok { + instance, ok = s.next[name] + } + s.mu.Unlock() + + if !ok { + instance = parseGPUCounterInstanceString(name) + } + + s.mu.Lock() + if s.next != nil { + s.next[name] = instance + } + s.mu.Unlock() + + return instance +} + +// commit makes the instances of this scrape the base of the next one. +func (s *instanceScrape) commit() { + s.mu.Lock() + next := s.next + s.next = nil + s.mu.Unlock() + + if next == nil { + return + } + + s.cache.mu.Lock() + s.cache.entries = next + s.cache.mu.Unlock() +} diff --git a/internal/collector/gpu/utils_internal_test.go b/internal/collector/gpu/utils_internal_test.go index 59e85e7d..1ea883f1 100644 --- a/internal/collector/gpu/utils_internal_test.go +++ b/internal/collector/gpu/utils_internal_test.go @@ -74,3 +74,38 @@ func TestParseGPUCounterInstanceString(t *testing.T) { }) } } + +func TestInstanceCache(t *testing.T) { + t.Parallel() + + var cache instanceCache + + names := []string{ + "pid_1234_luid_0x00000000_0x00005678_phys_0_eng_0_engtype_3D", + "pid_1234_luid_0x00000000_0x00005678_phys_0_eng_1_engtype_Compute_0", + "luid_0x00000000_0x00005678_phys_0", + } + + for range 3 { + scrape := cache.begin() + + for _, name := range names { + require.Equal(t, parseGPUCounterInstanceString(name), scrape.parse(name)) + } + + scrape.commit() + scrape.commit() + } + + require.Len(t, cache.entries, len(names)) + + // Instances that a scrape doesn't see are dropped. + scrape := cache.begin() + scrape.parse(names[0]) + scrape.commit() + + require.Len(t, cache.entries, 1) + + cache.reset() + require.Empty(t, cache.entries) +} diff --git a/internal/collector/hyperv/hyperv.go b/internal/collector/hyperv/hyperv.go index 4e7b7428..ea71261a 100644 --- a/internal/collector/hyperv/hyperv.go +++ b/internal/collector/hyperv/hyperv.go @@ -27,6 +27,7 @@ import ( "time" "github.com/alecthomas/kingpin/v2" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/osversion" "github.com/prometheus-community/windows_exporter/internal/utils/recovery" @@ -110,8 +111,13 @@ type Collector struct { miSession *mi.Session - collectorFns []func(ch chan<- prometheus.Metric) error + collectorFns []func(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error closeFns []func() + + // labels keeps the label pairs of the series of the last scrape. The + // counters change on every scrape, but their VM, switch and adapter + // labels stay the same. + labels labelcache.Cache } func New(config *Config) *Collector { @@ -162,6 +168,7 @@ func (c *Collector) Close() error { } c.closeFns = nil + c.labels.Reset() return nil } @@ -169,7 +176,7 @@ func (c *Collector) Close() error { func (c *Collector) Build(logger *slog.Logger, miSession *mi.Session) error { c.miSession = miSession c.logger = logger.With(slog.String("collector", Name)) - c.collectorFns = make([]func(ch chan<- prometheus.Metric) error, 0, len(c.config.CollectorsEnabled)) + c.collectorFns = make([]func(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error, 0, len(c.config.CollectorsEnabled)) c.closeFns = make([]func(), 0, len(c.config.CollectorsEnabled)) if len(c.config.CollectorsEnabled) == 0 { @@ -178,7 +185,7 @@ func (c *Collector) Build(logger *slog.Logger, miSession *mi.Session) error { subCollectors := map[string]struct { build func() error - collect func(ch chan<- prometheus.Metric) error + collect func(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error close func() minBuildNumber uint16 }{ @@ -325,11 +332,14 @@ 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, _ time.Duration) error { + scrape := c.labels.Begin() + defer scrape.Commit() + var g recovery.Group for _, fn := range c.collectorFns { g.Go(func() error { - return fn(ch) + return fn(ch, scrape) }) } diff --git a/internal/collector/hyperv/hyperv_datastore.go b/internal/collector/hyperv/hyperv_datastore.go index b99e97ed..795373cb 100644 --- a/internal/collector/hyperv/hyperv_datastore.go +++ b/internal/collector/hyperv/hyperv_datastore.go @@ -20,6 +20,7 @@ package hyperv import ( "fmt" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/pdh" "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" @@ -417,329 +418,329 @@ func (c *Collector) buildDataStore() error { return nil } -func (c *Collector) collectDataStore(ch chan<- prometheus.Metric) error { +func (c *Collector) collectDataStore(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error { err := c.perfDataCollectorDataStore.Collect(&c.perfDataObjectDataStore) if err != nil { return fmt.Errorf("failed to collect Hyper-V DataStore metrics: %w", err) } for _, data := range c.perfDataObjectDataStore { - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreFragmentationRatio, prometheus.GaugeValue, data.DataStoreFragmentationRatio, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreSectorSize, prometheus.GaugeValue, data.DataStoreSectorSize, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreDataAlignment, prometheus.GaugeValue, data.DataStoreDataAlignment, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreCurrentReplayLogSize, prometheus.GaugeValue, data.DataStoreCurrentReplayLogSize, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreAvailableEntries, prometheus.GaugeValue, data.DataStoreAvailableEntries, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreEmptyEntries, prometheus.GaugeValue, data.DataStoreEmptyEntries, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreFreeBytes, prometheus.GaugeValue, data.DataStoreFreeBytes, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreDataEnd, prometheus.GaugeValue, data.DataStoreDataEnd, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreFileObjects, prometheus.GaugeValue, data.DataStoreFileObjects, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreObjectTables, prometheus.GaugeValue, data.DataStoreObjectTables, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreKeyTables, prometheus.GaugeValue, data.DataStoreKeyTables, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreFileDataSize, prometheus.GaugeValue, data.DataStoreFileDataSize, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreTableDataSize, prometheus.GaugeValue, data.DataStoreTableDataSize, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreNamesSize, prometheus.GaugeValue, data.DataStoreNamesSize, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreNumberOfKeys, prometheus.GaugeValue, data.DataStoreNumberOfKeys, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreReconnectLatencyMicro, prometheus.GaugeValue, data.DataStoreReconnectLatencyMicro, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreDisconnectCount, prometheus.CounterValue, data.DataStoreDisconnectCount, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreWriteToFileByteLatency, prometheus.GaugeValue, data.DataStoreWriteToFileByteLatency, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreWriteToFileByteCount, prometheus.CounterValue, data.DataStoreWriteToFileByteCount, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreWriteToFileCount, prometheus.CounterValue, data.DataStoreWriteToFileCount, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreReadFromFileByteLatency, prometheus.GaugeValue, data.DataStoreReadFromFileByteLatency, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreReadFromFileByteCount, prometheus.CounterValue, data.DataStoreReadFromFileByteCount, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreReadFromFileCount, prometheus.CounterValue, data.DataStoreReadFromFileCount, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreWriteToStorageByteLatency, prometheus.GaugeValue, data.DataStoreWriteToStorageByteLatency, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreWriteToStorageByteCount, prometheus.CounterValue, data.DataStoreWriteToStorageByteCount, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreWriteToStorageCount, prometheus.CounterValue, data.DataStoreWriteToStorageCount, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreReadFromStorageByteLatency, prometheus.GaugeValue, data.DataStoreReadFromStorageByteLatency, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreReadFromStorageByteCount, prometheus.CounterValue, data.DataStoreReadFromStorageByteCount, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreReadFromStorageCount, prometheus.CounterValue, data.DataStoreReadFromStorageCount, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreCommitByteLatency, prometheus.GaugeValue, data.DataStoreCommitByteLatency, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreCommitByteCount, prometheus.CounterValue, data.DataStoreCommitByteCount, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreCommitCount, prometheus.CounterValue, data.DataStoreCommitCount, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreCacheUpdateOperationLatency, prometheus.GaugeValue, data.DataStoreCacheUpdateOperationLatency, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreCacheUpdateOperationCount, prometheus.CounterValue, data.DataStoreCacheUpdateOperationCount, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreCommitOperationLatency, prometheus.GaugeValue, data.DataStoreCommitOperationLatency, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreCommitOperationCount, prometheus.CounterValue, data.DataStoreCommitOperationCount, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreCompactOperationLatency, prometheus.GaugeValue, data.DataStoreCompactOperationLatency, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreCompactOperationCount, prometheus.CounterValue, data.DataStoreCompactOperationCount, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreLoadFileOperationLatency, prometheus.GaugeValue, data.DataStoreLoadFileOperationLatency, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreLoadFileOperationCount, prometheus.CounterValue, data.DataStoreLoadFileOperationCount, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreRemoveOperationLatency, prometheus.GaugeValue, data.DataStoreRemoveOperationLatency, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreRemoveOperationCount, prometheus.CounterValue, data.DataStoreRemoveOperationCount, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreQuerySizeOperationLatency, prometheus.GaugeValue, data.DataStoreQuerySizeOperationLatency, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreQuerySizeOperationCount, prometheus.CounterValue, data.DataStoreQuerySizeOperationCount, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreSetOperationLatencyMicro, prometheus.GaugeValue, data.DataStoreSetOperationLatencyMicro, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.dataStoreSetOperationCount, prometheus.CounterValue, data.DataStoreSetOperationCount, diff --git a/internal/collector/hyperv/hyperv_dynamic_memory_balancer.go b/internal/collector/hyperv/hyperv_dynamic_memory_balancer.go index 63c4a309..b2283f5d 100644 --- a/internal/collector/hyperv/hyperv_dynamic_memory_balancer.go +++ b/internal/collector/hyperv/hyperv_dynamic_memory_balancer.go @@ -20,6 +20,7 @@ package hyperv import ( "fmt" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/osversion" "github.com/prometheus-community/windows_exporter/internal/pdh" "github.com/prometheus-community/windows_exporter/internal/types" @@ -85,14 +86,14 @@ func (c *Collector) buildDynamicMemoryBalancer() error { return nil } -func (c *Collector) collectDynamicMemoryBalancer(ch chan<- prometheus.Metric) error { +func (c *Collector) collectDynamicMemoryBalancer(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error { err := c.perfDataCollectorDynamicMemoryBalancer.Collect(&c.perfDataObjectDynamicMemoryBalancer) if err != nil { return fmt.Errorf("failed to collect Hyper-V Dynamic Memory Balancer metrics: %w", err) } for _, data := range c.perfDataObjectDynamicMemoryBalancer { - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.vmDynamicMemoryBalancerAvailableMemory, prometheus.GaugeValue, utils.MBToBytes(data.VmDynamicMemoryBalancerAvailableMemory), @@ -100,7 +101,7 @@ func (c *Collector) collectDynamicMemoryBalancer(ch chan<- prometheus.Metric) er ) if osversion.Build() >= osversion.LTSC2019 { - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.vmDynamicMemoryBalancerAvailableMemoryForBalancing, prometheus.GaugeValue, utils.MBToBytes(data.VmDynamicMemoryBalancerAvailableMemoryForBalancing), @@ -108,14 +109,14 @@ func (c *Collector) collectDynamicMemoryBalancer(ch chan<- prometheus.Metric) er ) } - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.vmDynamicMemoryBalancerAveragePressure, prometheus.GaugeValue, utils.PercentageToRatio(data.VmDynamicMemoryBalancerAveragePressure), data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.vmDynamicMemoryBalancerSystemCurrentPressure, prometheus.GaugeValue, utils.PercentageToRatio(data.VmDynamicMemoryBalancerSystemCurrentPressure), diff --git a/internal/collector/hyperv/hyperv_dynamic_memory_vm.go b/internal/collector/hyperv/hyperv_dynamic_memory_vm.go index be793fa7..0a425d37 100644 --- a/internal/collector/hyperv/hyperv_dynamic_memory_vm.go +++ b/internal/collector/hyperv/hyperv_dynamic_memory_vm.go @@ -21,6 +21,7 @@ import ( "fmt" "strings" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/osversion" "github.com/prometheus-community/windows_exporter/internal/pdh" "github.com/prometheus-community/windows_exporter/internal/types" @@ -133,7 +134,7 @@ func (c *Collector) buildDynamicMemoryVM() error { return nil } -func (c *Collector) collectDynamicMemoryVM(ch chan<- prometheus.Metric) error { +func (c *Collector) collectDynamicMemoryVM(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error { err := c.perfDataCollectorDynamicMemoryVM.Collect(&c.perfDataObjectDynamicMemoryVM) if err != nil { return fmt.Errorf("failed to collect Hyper-V Dynamic Memory VM metrics: %w", err) @@ -142,14 +143,14 @@ func (c *Collector) collectDynamicMemoryVM(ch chan<- prometheus.Metric) error { for _, data := range c.perfDataObjectDynamicMemoryVM { vmName := dynamicMemoryVMName(data.Name) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.vmMemoryAddedMemory, prometheus.CounterValue, utils.MBToBytes(data.VmMemoryAddedMemory), vmName, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.vmMemoryCurrentPressure, prometheus.GaugeValue, utils.PercentageToRatio(data.VmMemoryCurrentPressure), @@ -157,7 +158,7 @@ func (c *Collector) collectDynamicMemoryVM(ch chan<- prometheus.Metric) error { ) if osversion.Build() >= osversion.LTSC2022 { - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.vmMemoryGuestAvailableMemory, prometheus.GaugeValue, utils.MBToBytes(data.VmMemoryGuestAvailableMemory), @@ -165,49 +166,49 @@ func (c *Collector) collectDynamicMemoryVM(ch chan<- prometheus.Metric) error { ) } - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.vmMemoryGuestVisiblePhysicalMemory, prometheus.GaugeValue, utils.MBToBytes(data.VmMemoryGuestVisiblePhysicalMemory), vmName, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.vmMemoryMaximumPressure, prometheus.GaugeValue, utils.PercentageToRatio(data.VmMemoryMaximumPressure), vmName, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.vmMemoryMemoryAddOperations, prometheus.CounterValue, data.VmMemoryMemoryAddOperations, vmName, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.vmMemoryMemoryRemoveOperations, prometheus.CounterValue, data.VmMemoryMemoryRemoveOperations, vmName, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.vmMemoryMinimumPressure, prometheus.GaugeValue, utils.PercentageToRatio(data.VmMemoryMinimumPressure), vmName, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.vmMemoryPhysicalMemory, prometheus.GaugeValue, utils.MBToBytes(data.VmMemoryPhysicalMemory), vmName, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.vmMemoryRemovedMemory, prometheus.CounterValue, utils.MBToBytes(data.VmMemoryRemovedMemory), diff --git a/internal/collector/hyperv/hyperv_host.go b/internal/collector/hyperv/hyperv_host.go index ac227cb2..594998ec 100644 --- a/internal/collector/hyperv/hyperv_host.go +++ b/internal/collector/hyperv/hyperv_host.go @@ -24,6 +24,7 @@ import ( "log/slog" "github.com/prometheus-community/windows_exporter/internal/headers/hcs" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/pdh" "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" @@ -105,7 +106,7 @@ func (c *Collector) buildHost() error { return nil } -func (c *Collector) collectHost(ch chan<- prometheus.Metric) error { +func (c *Collector) collectHost(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error { err := c.perfDataCollectorLogicalProcessor.Collect(&c.perfDataObjectLogicalProcessor) if err != nil { return fmt.Errorf("failed to collect Hyper-V Hypervisor Logical Processor metrics: %w", err) @@ -125,7 +126,7 @@ func (c *Collector) collectHost(ch chan<- prometheus.Metric) error { processorCount := float64(vm.ProcessorCount) totalVirtualCoreCount += processorCount - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.vmProcessorCount, prometheus.GaugeValue, processorCount, @@ -134,13 +135,13 @@ func (c *Collector) collectHost(ch chan<- prometheus.Metric) error { } } - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hostLogicalProcessorCount, prometheus.GaugeValue, logicalCoreCount, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.totalVMProcessorCount, prometheus.GaugeValue, totalVirtualCoreCount, diff --git a/internal/collector/hyperv/hyperv_hypervisor_logical_processor.go b/internal/collector/hyperv/hyperv_hypervisor_logical_processor.go index 817c1bdf..2aaf3b70 100644 --- a/internal/collector/hyperv/hyperv_hypervisor_logical_processor.go +++ b/internal/collector/hyperv/hyperv_hypervisor_logical_processor.go @@ -21,6 +21,7 @@ import ( "fmt" "strings" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/pdh" "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" @@ -80,7 +81,7 @@ func (c *Collector) buildHypervisorLogicalProcessor() error { return nil } -func (c *Collector) collectHypervisorLogicalProcessor(ch chan<- prometheus.Metric) error { +func (c *Collector) collectHypervisorLogicalProcessor(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error { err := c.perfDataCollectorHypervisorLogicalProcessor.Collect(&c.perfDataObjectHypervisorLogicalProcessor) if err != nil { return fmt.Errorf("failed to collect Hyper-V Hypervisor Logical Processor metrics: %w", err) @@ -95,35 +96,35 @@ func (c *Collector) collectHypervisorLogicalProcessor(ch chan<- prometheus.Metri coreID := parts[2] - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorLogicalProcessorTimeTotal, prometheus.CounterValue, data.HypervisorLogicalProcessorGuestRunTimePercent, coreID, "guest", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorLogicalProcessorTimeTotal, prometheus.CounterValue, data.HypervisorLogicalProcessorHypervisorRunTimePercent, coreID, "hypervisor", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorLogicalProcessorTimeTotal, prometheus.CounterValue, data.HypervisorLogicalProcessorIdleRunTimePercent, coreID, "idle", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorLogicalProcessorTotalRunTimeTotal, prometheus.CounterValue, data.HypervisorLogicalProcessorTotalRunTimePercent, coreID, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorLogicalProcessorContextSwitches, prometheus.CounterValue, data.HypervisorLogicalProcessorContextSwitches, diff --git a/internal/collector/hyperv/hyperv_hypervisor_root_partition.go b/internal/collector/hyperv/hyperv_hypervisor_root_partition.go index fc6087bb..615cfc14 100644 --- a/internal/collector/hyperv/hyperv_hypervisor_root_partition.go +++ b/internal/collector/hyperv/hyperv_hypervisor_root_partition.go @@ -20,6 +20,7 @@ package hyperv import ( "fmt" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/pdh" pdhtypes "github.com/prometheus-community/windows_exporter/internal/pdh/types" "github.com/prometheus-community/windows_exporter/internal/types" @@ -220,133 +221,133 @@ func (c *Collector) buildHypervisorRootPartitionDescriptors() { ) } -func (c *Collector) collectHypervisorRootPartition(ch chan<- prometheus.Metric) error { +func (c *Collector) collectHypervisorRootPartition(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error { err := c.perfDataCollectorHypervisorRootPartition.Collect(&c.perfDataObjectHypervisorRootPartition) if err != nil { return fmt.Errorf("failed to collect Hyper-V Hypervisor Root Partition metrics: %w", err) } - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootPartitionAddressSpaces, prometheus.GaugeValue, c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartitionAddressSpaces, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootPartitionAttachedDevices, prometheus.GaugeValue, c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartitionAttachedDevices, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootPartitionDepositedPages, prometheus.GaugeValue, c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartitionDepositedPages, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootPartitionDeviceDMAErrors, prometheus.GaugeValue, c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartitionDeviceDMAErrors, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootPartitionDeviceInterruptErrors, prometheus.GaugeValue, c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartitionDeviceInterruptErrors, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootPartitionDeviceInterruptMappings, prometheus.GaugeValue, c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartitionDeviceInterruptMappings, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootPartitionDeviceInterruptThrottleEvents, prometheus.GaugeValue, c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartitionDeviceInterruptThrottleEvents, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootPartitionGPAPages, prometheus.GaugeValue, c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartitionGPAPages, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootPartitionGPASpaceModifications, prometheus.CounterValue, c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartitionGPASpaceModifications, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootPartitionIOTLBFlushCost, prometheus.GaugeValue, c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartitionIOTLBFlushCost, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootPartitionIOTLBFlushes, prometheus.CounterValue, c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartitionIOTLBFlushes, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootPartitionRecommendedVirtualTLBSize, prometheus.GaugeValue, c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartitionRecommendedVirtualTLBSize, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootPartitionSkippedTimerTicks, prometheus.GaugeValue, c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartitionSkippedTimerTicks, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootPartition1GDevicePages, prometheus.GaugeValue, c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartition1GDevicePages, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootPartition1GGPAPages, prometheus.GaugeValue, c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartition1GGPAPages, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootPartition2MDevicePages, prometheus.GaugeValue, c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartition2MDevicePages, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootPartition2MGPAPages, prometheus.GaugeValue, c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartition2MGPAPages, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootPartition4KDevicePages, prometheus.GaugeValue, c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartition4KDevicePages, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootPartition4KGPAPages, prometheus.GaugeValue, c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartition4KGPAPages, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootPartitionVirtualTLBFlushEntries, prometheus.CounterValue, c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartitionVirtualTLBFlushEntries, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootPartitionVirtualTLBPages, prometheus.GaugeValue, c.perfDataObjectHypervisorRootPartition[0].HypervisorRootPartitionVirtualTLBPages, diff --git a/internal/collector/hyperv/hyperv_hypervisor_root_virtual_processor.go b/internal/collector/hyperv/hyperv_hypervisor_root_virtual_processor.go index e0c36717..c4d83a5d 100644 --- a/internal/collector/hyperv/hyperv_hypervisor_root_virtual_processor.go +++ b/internal/collector/hyperv/hyperv_hypervisor_root_virtual_processor.go @@ -21,6 +21,7 @@ import ( "fmt" "strings" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/pdh" "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" @@ -82,7 +83,7 @@ func (c *Collector) buildHypervisorRootVirtualProcessor() error { return nil } -func (c *Collector) collectHypervisorRootVirtualProcessor(ch chan<- prometheus.Metric) error { +func (c *Collector) collectHypervisorRootVirtualProcessor(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error { err := c.perfDataCollectorHypervisorRootVirtualProcessor.Collect(&c.perfDataObjectHypervisorRootVirtualProcessor) if err != nil { return fmt.Errorf("failed to collect Hyper-V Hypervisor Root Virtual Processor metrics: %w", err) @@ -97,35 +98,35 @@ func (c *Collector) collectHypervisorRootVirtualProcessor(ch chan<- prometheus.M coreID := parts[2] - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootVirtualProcessorTimeTotal, prometheus.CounterValue, data.HypervisorRootVirtualProcessorGuestRunTimePercent, coreID, "guest_run", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootVirtualProcessorTimeTotal, prometheus.CounterValue, data.HypervisorRootVirtualProcessorHypervisorRunTimePercent, coreID, "hypervisor", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootVirtualProcessorTimeTotal, prometheus.CounterValue, data.HypervisorRootVirtualProcessorRemoteRunTimePercent, coreID, "remote", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootVirtualProcessorTotalRunTimeTotal, prometheus.CounterValue, data.HypervisorRootVirtualProcessorTotalRunTimePercent, coreID, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorRootVirtualProcessorCPUWaitTimePerDispatch, prometheus.CounterValue, data.HypervisorRootVirtualProcessorCPUWaitTimePerDispatch, diff --git a/internal/collector/hyperv/hyperv_hypervisor_virtual_processor.go b/internal/collector/hyperv/hyperv_hypervisor_virtual_processor.go index 579751ab..04d32be7 100644 --- a/internal/collector/hyperv/hyperv_hypervisor_virtual_processor.go +++ b/internal/collector/hyperv/hyperv_hypervisor_virtual_processor.go @@ -21,6 +21,7 @@ import ( "fmt" "strings" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/pdh" "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" @@ -97,7 +98,7 @@ func (c *Collector) buildHypervisorVirtualProcessor() error { return nil } -func (c *Collector) collectHypervisorVirtualProcessor(ch chan<- prometheus.Metric) error { +func (c *Collector) collectHypervisorVirtualProcessor(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error { err := c.perfDataCollectorHypervisorVirtualProcessor.Collect(&c.perfDataObjectHypervisorVirtualProcessor) if err != nil { return fmt.Errorf("failed to collect Hyper-V Hypervisor Virtual Processor metrics: %w", err) @@ -118,63 +119,63 @@ func (c *Collector) collectHypervisorVirtualProcessor(ch chan<- prometheus.Metri vmName := parts[0] coreID := coreParts[2] - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorVirtualProcessorTimeTotal, prometheus.CounterValue, data.HypervisorVirtualProcessorHypervisorRunTimePercent, vmName, coreID, "hypervisor", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorVirtualProcessorTimeTotal, prometheus.CounterValue, data.HypervisorVirtualProcessorGuestRunTimePercent, vmName, coreID, "guest", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorVirtualProcessorTimeTotal, prometheus.CounterValue, data.HypervisorVirtualProcessorRemoteRunTimePercent, vmName, coreID, "remote", ) // Same metric with new name for better clarity, old one is kept for backward compatibility - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorVirtualProcessorModeTimeTotal, prometheus.CounterValue, data.HypervisorVirtualProcessorHypervisorRunTimePercent, vmName, coreID, "hypervisor", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorVirtualProcessorModeTimeTotal, prometheus.CounterValue, data.HypervisorVirtualProcessorGuestRunTimePercent, vmName, coreID, "guest", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorVirtualProcessorModeTimeTotal, prometheus.CounterValue, data.HypervisorVirtualProcessorRemoteRunTimePercent, vmName, coreID, "remote", ) // end same metric - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorVirtualProcessorTotalRunTimeTotal, prometheus.CounterValue, data.HypervisorVirtualProcessorTotalRunTimePercent, vmName, coreID, ) // Same metric with new name for better clarity, old one is kept for backward compatibility - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorVirtualProcessorRunTimeTotal, prometheus.CounterValue, data.HypervisorVirtualProcessorTotalRunTimePercent, vmName, coreID, ) // end same metric - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.hypervisorVirtualProcessorContextSwitches, prometheus.CounterValue, data.HypervisorVirtualProcessorCPUWaitTimePerDispatch, diff --git a/internal/collector/hyperv/hyperv_legacy_network_adapter.go b/internal/collector/hyperv/hyperv_legacy_network_adapter.go index f5860e12..5cca6754 100644 --- a/internal/collector/hyperv/hyperv_legacy_network_adapter.go +++ b/internal/collector/hyperv/hyperv_legacy_network_adapter.go @@ -20,6 +20,7 @@ package hyperv import ( "fmt" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/pdh" "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" @@ -97,49 +98,49 @@ func (c *Collector) buildLegacyNetworkAdapter() error { return nil } -func (c *Collector) collectLegacyNetworkAdapter(ch chan<- prometheus.Metric) error { +func (c *Collector) collectLegacyNetworkAdapter(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error { err := c.perfDataCollectorLegacyNetworkAdapter.Collect(&c.perfDataObjectLegacyNetworkAdapter) if err != nil { return fmt.Errorf("failed to collect Hyper-V Legacy Network Adapter metrics: %w", err) } for _, data := range c.perfDataObjectLegacyNetworkAdapter { - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.legacyNetworkAdapterBytesDropped, prometheus.CounterValue, data.LegacyNetworkAdapterBytesDropped, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.legacyNetworkAdapterBytesReceived, prometheus.CounterValue, data.LegacyNetworkAdapterBytesReceived, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.legacyNetworkAdapterBytesSent, prometheus.CounterValue, data.LegacyNetworkAdapterBytesSent, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.legacyNetworkAdapterFramesReceived, prometheus.CounterValue, data.LegacyNetworkAdapterFramesReceived, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.legacyNetworkAdapterFramesDropped, prometheus.CounterValue, data.LegacyNetworkAdapterFramesDropped, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.legacyNetworkAdapterFramesSent, prometheus.CounterValue, data.LegacyNetworkAdapterFramesSent, diff --git a/internal/collector/hyperv/hyperv_replica_vm.go b/internal/collector/hyperv/hyperv_replica_vm.go index a8096895..c7be1060 100644 --- a/internal/collector/hyperv/hyperv_replica_vm.go +++ b/internal/collector/hyperv/hyperv_replica_vm.go @@ -24,6 +24,7 @@ import ( "strings" "time" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/pdh" "github.com/prometheus-community/windows_exporter/internal/types" @@ -177,14 +178,14 @@ func (c *Collector) buildReplicaVM() error { return nil } -func (c *Collector) collectReplicaVM(ch chan<- prometheus.Metric) error { +func (c *Collector) collectReplicaVM(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error { return errors.Join( - c.collectReplicaVMPerfData(ch), - c.collectReplicaVMRelationships(ch), + c.collectReplicaVMPerfData(ch, scrape), + c.collectReplicaVMRelationships(ch, scrape), ) } -func (c *Collector) collectReplicaVMPerfData(ch chan<- prometheus.Metric) error { +func (c *Collector) collectReplicaVMPerfData(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error { if c.perfDataCollectorReplicaVM == nil { return nil } @@ -198,63 +199,63 @@ func (c *Collector) collectReplicaVMPerfData(ch chan<- prometheus.Metric) error } for _, data := range c.perfDataObjectReplicaVM { - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.replicaVMAverageReplicationLatency, prometheus.GaugeValue, data.AverageReplicationLatency, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.replicaVMAverageReplicationSize, prometheus.GaugeValue, data.AverageReplicationSize, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.replicaVMCompressionEfficiency, prometheus.GaugeValue, data.CompressionEfficiency, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.replicaVMLastReplicationSize, prometheus.GaugeValue, data.LastReplicationSize, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.replicaVMNetworkReceivedBytes, prometheus.CounterValue, data.NetworkBytesRecv, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.replicaVMNetworkSentBytes, prometheus.CounterValue, data.NetworkBytesSent, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.replicaVMReplicationCount, prometheus.CounterValue, data.ReplicationCount, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.replicaVMReplicationLatency, prometheus.GaugeValue, data.ReplicationLatency, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.replicaVMResynchronizedBytes, prometheus.CounterValue, data.ResynchronizedBytes, @@ -265,7 +266,7 @@ func (c *Collector) collectReplicaVMPerfData(ch chan<- prometheus.Metric) error return nil } -func (c *Collector) collectReplicaVMRelationships(ch chan<- prometheus.Metric) error { +func (c *Collector) collectReplicaVMRelationships(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error { var dst []msvmReplicationRelationship if err := c.miSession.Query(&dst, mi.NamespaceRootVirtualizationV2, c.miQueryReplicaVM, replicaVMQueryTimeout); err != nil { @@ -275,7 +276,7 @@ func (c *Collector) collectReplicaVMRelationships(ch chan<- prometheus.Metric) e for _, relationship := range dst { relationshipType := replicationRelationshipType(relationship.InstanceID) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.replicaVMHealth, prometheus.GaugeValue, float64(relationship.ReplicationHealth), @@ -283,7 +284,7 @@ func (c *Collector) collectReplicaVMRelationships(ch chan<- prometheus.Metric) e relationshipType, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.replicaVMState, prometheus.GaugeValue, float64(relationship.ReplicationState), diff --git a/internal/collector/hyperv/hyperv_virtual_machine_health_summary.go b/internal/collector/hyperv/hyperv_virtual_machine_health_summary.go index 229635b7..67ab1cb8 100644 --- a/internal/collector/hyperv/hyperv_virtual_machine_health_summary.go +++ b/internal/collector/hyperv/hyperv_virtual_machine_health_summary.go @@ -20,6 +20,7 @@ package hyperv import ( "fmt" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/pdh" "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" @@ -59,20 +60,20 @@ func (c *Collector) buildVirtualMachineHealthSummary() error { return nil } -func (c *Collector) collectVirtualMachineHealthSummary(ch chan<- prometheus.Metric) error { +func (c *Collector) collectVirtualMachineHealthSummary(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error { err := c.perfDataCollectorVirtualMachineHealthSummary.Collect(&c.perfDataObjectVirtualMachineHealthSummary) if err != nil { return fmt.Errorf("failed to collect Hyper-V Virtual Machine Health Summary metrics: %w", err) } - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.health, prometheus.GaugeValue, c.perfDataObjectVirtualMachineHealthSummary[0].HealthCritical, "critical", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.health, prometheus.GaugeValue, c.perfDataObjectVirtualMachineHealthSummary[0].HealthOk, diff --git a/internal/collector/hyperv/hyperv_virtual_machine_vid_partition.go b/internal/collector/hyperv/hyperv_virtual_machine_vid_partition.go index f0364ae2..28411d9a 100644 --- a/internal/collector/hyperv/hyperv_virtual_machine_vid_partition.go +++ b/internal/collector/hyperv/hyperv_virtual_machine_vid_partition.go @@ -20,6 +20,7 @@ package hyperv import ( "fmt" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/pdh" "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" @@ -73,28 +74,28 @@ func (c *Collector) buildVirtualMachineVidPartition() error { return nil } -func (c *Collector) collectVirtualMachineVidPartition(ch chan<- prometheus.Metric) error { +func (c *Collector) collectVirtualMachineVidPartition(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error { err := c.perfDataCollectorVirtualMachineVidPartition.Collect(&c.perfDataObjectVirtualMachineVidPartition) if err != nil { return fmt.Errorf("failed to collect Hyper-V VM Vid Partition metrics: %w", err) } for _, data := range c.perfDataObjectVirtualMachineVidPartition { - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.physicalPagesAllocated, prometheus.GaugeValue, data.PhysicalPagesAllocated, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.preferredNUMANodeIndex, prometheus.GaugeValue, data.PreferredNUMANodeIndex, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.remotePhysicalPages, prometheus.GaugeValue, data.RemotePhysicalPages, diff --git a/internal/collector/hyperv/hyperv_virtual_network_adapter.go b/internal/collector/hyperv/hyperv_virtual_network_adapter.go index 20e5db9f..0691c82b 100644 --- a/internal/collector/hyperv/hyperv_virtual_network_adapter.go +++ b/internal/collector/hyperv/hyperv_virtual_network_adapter.go @@ -20,6 +20,7 @@ package hyperv import ( "fmt" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/pdh" "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" @@ -97,49 +98,49 @@ func (c *Collector) buildVirtualNetworkAdapter() error { return nil } -func (c *Collector) collectVirtualNetworkAdapter(ch chan<- prometheus.Metric) error { +func (c *Collector) collectVirtualNetworkAdapter(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error { err := c.perfDataCollectorVirtualNetworkAdapter.Collect(&c.perfDataObjectVirtualNetworkAdapter) if err != nil { return fmt.Errorf("failed to collect Hyper-V Virtual Network Adapter metrics: %w", err) } for _, data := range c.perfDataObjectVirtualNetworkAdapter { - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterBytesReceived, prometheus.CounterValue, data.VirtualNetworkAdapterBytesReceived, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterBytesSent, prometheus.CounterValue, data.VirtualNetworkAdapterBytesSent, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDroppedPacketsIncoming, prometheus.CounterValue, data.VirtualNetworkAdapterDroppedPacketsIncoming, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDroppedPacketsOutgoing, prometheus.CounterValue, data.VirtualNetworkAdapterDroppedPacketsOutgoing, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterPacketsReceived, prometheus.CounterValue, data.VirtualNetworkAdapterPacketsReceived, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterPacketsSent, prometheus.CounterValue, data.VirtualNetworkAdapterPacketsSent, diff --git a/internal/collector/hyperv/hyperv_virtual_network_adapter_drop_reasons.go b/internal/collector/hyperv/hyperv_virtual_network_adapter_drop_reasons.go index ba524a18..d4ac129e 100644 --- a/internal/collector/hyperv/hyperv_virtual_network_adapter_drop_reasons.go +++ b/internal/collector/hyperv/hyperv_virtual_network_adapter_drop_reasons.go @@ -20,6 +20,7 @@ package hyperv import ( "fmt" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/pdh" "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" @@ -182,357 +183,357 @@ func (c *Collector) buildVirtualNetworkAdapterDropReasons() error { return nil } -func (c *Collector) collectVirtualNetworkAdapterDropReasons(ch chan<- prometheus.Metric) error { +func (c *Collector) collectVirtualNetworkAdapterDropReasons(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error { err := c.perfDataCollectorVirtualNetworkAdapterDropReasons.Collect(&c.perfDataObjectVirtualNetworkAdapterDropReasons) if err != nil { return fmt.Errorf("failed to collect Hyper-V Virtual Network Adapter Drop Reasons metrics: %w", err) } for _, data := range c.perfDataObjectVirtualNetworkAdapterDropReasons { - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingNativeFwdingReq, data.Name, "NativeFwdingReq", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingNativeFwdingReq, data.Name, "NativeFwdingReq", "incoming", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingMTUMismatch, data.Name, "MTUMismatch", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingMTUMismatch, data.Name, "MTUMismatch", "incoming", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingInvalidConfig, data.Name, "InvalidConfig", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingInvalidConfig, data.Name, "InvalidConfig", "incoming", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingRequiredExtensionMissing, data.Name, "RequiredExtensionMissing", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingRequiredExtensionMissing, data.Name, "RequiredExtensionMissing", "incoming", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingVirtualSubnetId, data.Name, "VirtualSubnetId", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingVirtualSubnetId, data.Name, "VirtualSubnetId", "incoming", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingBridgeReserved, data.Name, "BridgeReserved", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingBridgeReserved, data.Name, "BridgeReserved", "incoming", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingRouterGuard, data.Name, "RouterGuard", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingRouterGuard, data.Name, "RouterGuard", "incoming", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingDhcpGuard, data.Name, "DhcpGuard", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingDhcpGuard, data.Name, "DhcpGuard", "incoming", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingMacSpoofing, data.Name, "MacSpoofing", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingMacSpoofing, data.Name, "MacSpoofing", "incoming", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingIpsec, data.Name, "Ipsec", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingIpsec, data.Name, "Ipsec", "incoming", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingQos, data.Name, "Qos", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingQos, data.Name, "Qos", "incoming", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingFailedPvlanSetting, data.Name, "FailedPvlanSetting", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingFailedPvlanSetting, data.Name, "FailedPvlanSetting", "incoming", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingFailedSecurityPolicy, data.Name, "FailedSecurityPolicy", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingFailedSecurityPolicy, data.Name, "FailedSecurityPolicy", "incoming", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingUnauthorizedMAC, data.Name, "UnauthorizedMAC", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingUnauthorizedMAC, data.Name, "UnauthorizedMAC", "incoming", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingUnauthorizedVLAN, data.Name, "UnauthorizedVLAN", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingUnauthorizedVLAN, data.Name, "UnauthorizedVLAN", "incoming", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingFilteredVLAN, data.Name, "FilteredVLAN", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingFilteredVLAN, data.Name, "FilteredVLAN", "incoming", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingFiltered, data.Name, "Filtered", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingFiltered, data.Name, "Filtered", "incoming", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingBusy, data.Name, "Busy", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingBusy, data.Name, "Busy", "incoming", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingNotAccepted, data.Name, "NotAccepted", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingNotAccepted, data.Name, "NotAccepted", "incoming", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingDisconnected, data.Name, "Disconnected", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingDisconnected, data.Name, "Disconnected", "incoming", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingNotReady, data.Name, "NotReady", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingNotReady, data.Name, "NotReady", "incoming", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingResources, data.Name, "Resources", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingResources, data.Name, "Resources", "incoming", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingInvalidPacket, data.Name, "InvalidPacket", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingInvalidPacket, data.Name, "InvalidPacket", "incoming", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingInvalidData, data.Name, "InvalidData", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingInvalidData, data.Name, "InvalidData", "incoming", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsOutgoingUnknown, data.Name, "Unknown", "outgoing", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualNetworkAdapterDropReasons, prometheus.CounterValue, data.VirtualNetworkAdapterDropReasonsIncomingUnknown, diff --git a/internal/collector/hyperv/hyperv_virtual_smb.go b/internal/collector/hyperv/hyperv_virtual_smb.go index 24bb2fae..3148ed4e 100644 --- a/internal/collector/hyperv/hyperv_virtual_smb.go +++ b/internal/collector/hyperv/hyperv_virtual_smb.go @@ -20,6 +20,7 @@ package hyperv import ( "fmt" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/pdh" "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" @@ -185,126 +186,126 @@ func (c *Collector) buildVirtualSMB() error { return nil } -func (c *Collector) collectVirtualSMB(ch chan<- prometheus.Metric) error { +func (c *Collector) collectVirtualSMB(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error { err := c.perfDataCollectorVirtualSMB.Collect(&c.perfDataObjectVirtualSMB) if err != nil { return fmt.Errorf("failed to collect Hyper-V Virtual SMB metrics: %w", err) } for _, data := range c.perfDataObjectVirtualSMB { - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSMBDirectMappedSections, prometheus.GaugeValue, data.VirtualSMBDirectMappedSections, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSMBDirectMappedPages, prometheus.GaugeValue, data.VirtualSMBDirectMappedPages, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSMBWriteBytesRDMA, prometheus.CounterValue, data.VirtualSMBWriteBytesRDMA, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSMBWriteBytes, prometheus.CounterValue, data.VirtualSMBWriteBytes, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSMBReadBytesRDMA, prometheus.CounterValue, data.VirtualSMBReadBytesRDMA, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSMBReadBytes, prometheus.CounterValue, data.VirtualSMBReadBytes, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSMBFlushRequests, prometheus.CounterValue, data.VirtualSMBFlushRequests, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSMBWriteRequestsRDMA, prometheus.CounterValue, data.VirtualSMBWriteRequestsRDMA, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSMBWriteRequests, prometheus.CounterValue, data.VirtualSMBWriteRequests, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSMBReadRequestsRDMA, prometheus.CounterValue, data.VirtualSMBReadRequestsRDMA, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSMBReadRequests, prometheus.CounterValue, data.VirtualSMBReadRequests, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSMBCurrentPendingRequests, prometheus.GaugeValue, data.VirtualSMBCurrentPendingRequests, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSMBCurrentOpenFileCount, prometheus.GaugeValue, data.VirtualSMBCurrentOpenFileCount, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSMBTreeConnectCount, prometheus.GaugeValue, data.VirtualSMBTreeConnectCount, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSMBRequests, prometheus.CounterValue, data.VirtualSMBRequests, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSMBSentBytes, prometheus.CounterValue, data.VirtualSMBSentBytes, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSMBReceivedBytes, prometheus.CounterValue, data.VirtualSMBReceivedBytes, diff --git a/internal/collector/hyperv/hyperv_virtual_storage_device.go b/internal/collector/hyperv/hyperv_virtual_storage_device.go index ede6725c..3e1fdd01 100644 --- a/internal/collector/hyperv/hyperv_virtual_storage_device.go +++ b/internal/collector/hyperv/hyperv_virtual_storage_device.go @@ -20,6 +20,7 @@ package hyperv import ( "fmt" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/pdh" "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" @@ -165,91 +166,91 @@ func (c *Collector) buildVirtualStorageDevice() error { return nil } -func (c *Collector) collectVirtualStorageDevice(ch chan<- prometheus.Metric) error { +func (c *Collector) collectVirtualStorageDevice(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error { err := c.perfDataCollectorVirtualStorageDevice.Collect(&c.perfDataObjectVirtualStorageDevice) if err != nil { return fmt.Errorf("failed to collect Hyper-V Virtual Storage Device metrics: %w", err) } for _, data := range c.perfDataObjectVirtualStorageDevice { - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualStorageDeviceErrorCount, prometheus.CounterValue, data.VirtualStorageDeviceErrorCount, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualStorageDeviceQueueLength, prometheus.GaugeValue, data.VirtualStorageDeviceQueueLength, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualStorageDeviceReadBytes, prometheus.CounterValue, data.VirtualStorageDeviceReadBytes, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualStorageDeviceReadOperations, prometheus.CounterValue, data.VirtualStorageDeviceReadOperations, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualStorageDeviceWriteBytes, prometheus.CounterValue, data.VirtualStorageDeviceWriteBytes, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualStorageDeviceWriteOperations, prometheus.CounterValue, data.VirtualStorageDeviceWriteOperations, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualStorageDeviceLatency, prometheus.GaugeValue, data.VirtualStorageDeviceLatency, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualStorageDeviceThroughput, prometheus.CounterValue, data.VirtualStorageDeviceThroughput, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualStorageDeviceNormalizedThroughput, prometheus.GaugeValue, data.VirtualStorageDeviceNormalizedThroughput, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualStorageDeviceLowerQueueLength, prometheus.GaugeValue, data.VirtualStorageDeviceLowerQueueLength, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualStorageDeviceLowerLatency, prometheus.GaugeValue, data.VirtualStorageDeviceLowerLatency, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualStorageDeviceIOQuotaReplenishmentRate, prometheus.GaugeValue, data.VirtualStorageDeviceIOQuotaReplenishmentRate, @@ -258,14 +259,14 @@ func (c *Collector) collectVirtualStorageDevice(ch chan<- prometheus.Metric) err // The raw value of a PERF_AVERAGE_TIMER counter is the sum of all IO latencies in // 100ns ticks; the operation count it is averaged over is Throughput. - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualStorageDeviceIOLatency, prometheus.CounterValue, data.VirtualStorageDeviceLatency*pdh.TicksToSecondScaleFactor, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualStorageDeviceLowerIOLatency, prometheus.CounterValue, data.VirtualStorageDeviceLowerLatency*pdh.TicksToSecondScaleFactor, diff --git a/internal/collector/hyperv/hyperv_virtual_switch.go b/internal/collector/hyperv/hyperv_virtual_switch.go index 9828eedd..3ee80a09 100644 --- a/internal/collector/hyperv/hyperv_virtual_switch.go +++ b/internal/collector/hyperv/hyperv_virtual_switch.go @@ -20,6 +20,7 @@ package hyperv import ( "fmt" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/pdh" "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" @@ -217,154 +218,154 @@ func (c *Collector) buildVirtualSwitch() error { return nil } -func (c *Collector) collectVirtualSwitch(ch chan<- prometheus.Metric) error { +func (c *Collector) collectVirtualSwitch(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error { err := c.perfDataCollectorVirtualSwitch.Collect(&c.perfDataObjectVirtualSwitch) if err != nil { return fmt.Errorf("failed to collect Hyper-V Virtual Switch metrics: %w", err) } for _, data := range c.perfDataObjectVirtualSwitch { - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSwitchBroadcastPacketsReceived, prometheus.CounterValue, data.VirtualSwitchBroadcastPacketsReceived, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSwitchBroadcastPacketsSent, prometheus.CounterValue, data.VirtualSwitchBroadcastPacketsSent, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSwitchBytes, prometheus.CounterValue, data.VirtualSwitchBytes, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSwitchBytesReceived, prometheus.CounterValue, data.VirtualSwitchBytesReceived, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSwitchBytesSent, prometheus.CounterValue, data.VirtualSwitchBytesSent, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSwitchDirectedPacketsReceived, prometheus.CounterValue, data.VirtualSwitchDirectedPacketsReceived, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSwitchDirectedPacketsSent, prometheus.CounterValue, data.VirtualSwitchDirectedPacketsSent, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSwitchDroppedPacketsIncoming, prometheus.CounterValue, data.VirtualSwitchDroppedPacketsIncoming, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSwitchDroppedPacketsOutgoing, prometheus.CounterValue, data.VirtualSwitchDroppedPacketsOutgoing, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSwitchExtensionsDroppedPacketsIncoming, prometheus.CounterValue, data.VirtualSwitchExtensionsDroppedPacketsIncoming, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSwitchExtensionsDroppedPacketsOutgoing, prometheus.CounterValue, data.VirtualSwitchExtensionsDroppedPacketsOutgoing, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSwitchLearnedMacAddresses, prometheus.CounterValue, data.VirtualSwitchLearnedMacAddresses, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSwitchMulticastPacketsReceived, prometheus.CounterValue, data.VirtualSwitchMulticastPacketsReceived, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSwitchMulticastPacketsSent, prometheus.CounterValue, data.VirtualSwitchMulticastPacketsSent, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSwitchNumberOfSendChannelMoves, prometheus.CounterValue, data.VirtualSwitchNumberOfSendChannelMoves, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSwitchNumberOfVMQMoves, prometheus.CounterValue, data.VirtualSwitchNumberOfVMQMoves, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSwitchPacketsFlooded, prometheus.CounterValue, data.VirtualSwitchPacketsFlooded, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSwitchPackets, prometheus.CounterValue, data.VirtualSwitchPackets, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSwitchPacketsReceived, prometheus.CounterValue, data.VirtualSwitchPacketsReceived, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSwitchPacketsSent, prometheus.CounterValue, data.VirtualSwitchPacketsSent, data.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualSwitchPurgedMacAddresses, prometheus.CounterValue, data.VirtualSwitchPurgedMacAddresses, diff --git a/internal/collector/hyperv/hyperv_wmi_health.go b/internal/collector/hyperv/hyperv_wmi_health.go index cf62fdbc..ff477507 100644 --- a/internal/collector/hyperv/hyperv_wmi_health.go +++ b/internal/collector/hyperv/hyperv_wmi_health.go @@ -24,6 +24,7 @@ import ( "time" "github.com/prometheus-community/windows_exporter/internal/headers/sysinfoapi" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" @@ -79,7 +80,7 @@ func (c *Collector) buildWMIHealth() error { // collectWMIHealth reports 1 if a minimal query against the Hyper-V WMI // namespace succeeds and 0 otherwise. -func (c *Collector) collectWMIHealth(ch chan<- prometheus.Metric) error { +func (c *Collector) collectWMIHealth(ch chan<- prometheus.Metric, scrape *labelcache.Scrape) error { var dst []msvmComputerSystem healthValue := 1.0 @@ -90,7 +91,7 @@ func (c *Collector) collectWMIHealth(ch chan<- prometheus.Metric) error { healthValue = 0.0 } - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.wmiHealth, prometheus.GaugeValue, healthValue, diff --git a/internal/collector/hyperv/interrupt_mappings_test.go b/internal/collector/hyperv/interrupt_mappings_test.go index ba368f7f..acc31de2 100644 --- a/internal/collector/hyperv/interrupt_mappings_test.go +++ b/internal/collector/hyperv/interrupt_mappings_test.go @@ -32,7 +32,7 @@ func TestRootPartitionInterruptMappings(t *testing.T) { c.buildHypervisorRootPartitionDescriptors() c.perfDataCollectorHypervisorRootPartition = interruptMappingFixture{} metrics := make(chan prometheus.Metric, 100) - require.NoError(t, c.collectHypervisorRootPartition(metrics)) + require.NoError(t, c.collectHypervisorRootPartition(metrics, nil)) close(metrics) found := false diff --git a/internal/collector/netframework/netframework.go b/internal/collector/netframework/netframework.go index fdc547cb..116e15b4 100644 --- a/internal/collector/netframework/netframework.go +++ b/internal/collector/netframework/netframework.go @@ -28,6 +28,7 @@ import ( "unsafe" "github.com/alecthomas/kingpin/v2" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/pdh" "github.com/prometheus-community/windows_exporter/internal/utils/recovery" @@ -73,6 +74,10 @@ const ( // A Collector collects .NET Framework performance counters. type Collector struct { + // labels keeps the label pairs of the series of the last scrape. The + // counters change on every scrape, but their process labels stay the + // same while the process runs. + labels labelcache.Cache config Config logger *slog.Logger perfFrequency float64 @@ -86,7 +91,7 @@ type Collector struct { perfClrRemoting perfCollector[perfDataClrRemoting] perfClrSecurity perfCollector[perfDataClrSecurity] - collectorFns []func(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error + collectorFns []func(ch chan<- prometheus.Metric, scrape *labelcache.Scrape, maxScrapeDuration time.Duration) error // clrexceptions numberOfExceptionsThrown *prometheus.Desc @@ -203,6 +208,7 @@ func (c *Collector) Close() error { c.closeFns = nil c.collectorFns = nil + c.labels.Reset() return nil } @@ -224,11 +230,11 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { c.perfFrequency = float64(frequency) } - c.collectorFns = make([]func(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error, 0, len(c.config.CollectorsEnabled)) + c.collectorFns = make([]func(ch chan<- prometheus.Metric, scrape *labelcache.Scrape, maxScrapeDuration time.Duration) error, 0, len(c.config.CollectorsEnabled)) subCollectors := map[string]struct { build func() error - collect func(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error + collect func(ch chan<- prometheus.Metric, scrape *labelcache.Scrape, maxScrapeDuration time.Duration) error close func() }{ collectorClrExceptions: { @@ -334,11 +340,14 @@ 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, maxScrapeDuration time.Duration) error { + scrape := c.labels.Begin() + defer scrape.Commit() + var g recovery.Group for _, fn := range c.collectorFns { g.Go(func() error { - return fn(ch, maxScrapeDuration) + return fn(ch, scrape, maxScrapeDuration) }) } diff --git a/internal/collector/netframework/netframework_clrexceptions.go b/internal/collector/netframework/netframework_clrexceptions.go index 24483aa1..37ea00b9 100644 --- a/internal/collector/netframework/netframework_clrexceptions.go +++ b/internal/collector/netframework/netframework_clrexceptions.go @@ -21,6 +21,7 @@ import ( "fmt" "time" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" ) @@ -70,7 +71,7 @@ type perfDataClrExceptions struct { ThrowToCatchDepthPersec float64 `perfdata:"Throw To Catch Depth / sec"` } -func (c *Collector) collectClrExceptions(ch chan<- prometheus.Metric, _ time.Duration) error { +func (c *Collector) collectClrExceptions(ch chan<- prometheus.Metric, scrape *labelcache.Scrape, _ time.Duration) error { var dst []perfDataClrExceptions if err := c.perfClrExceptions.Collect(&dst); err != nil { return fmt.Errorf("failed to collect .NET CLR Exceptions: %w", err) @@ -81,28 +82,28 @@ func (c *Collector) collectClrExceptions(ch chan<- prometheus.Metric, _ time.Dur continue } - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.numberOfExceptionsThrown, prometheus.CounterValue, float64(process.NumberofExcepsThrown), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.numberOfFilters, prometheus.CounterValue, float64(process.NumberofFiltersPersec), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.numberOfFinally, prometheus.CounterValue, float64(process.NumberofFinallysPersec), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.throwToCatchDepth, prometheus.CounterValue, float64(process.ThrowToCatchDepthPersec), diff --git a/internal/collector/netframework/netframework_clrinterop.go b/internal/collector/netframework/netframework_clrinterop.go index 364522e2..a3adbea7 100644 --- a/internal/collector/netframework/netframework_clrinterop.go +++ b/internal/collector/netframework/netframework_clrinterop.go @@ -21,6 +21,7 @@ import ( "fmt" "time" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" ) @@ -63,7 +64,7 @@ type perfDataClrInterop struct { Numberofmarshalling float64 `perfdata:"# of marshalling"` } -func (c *Collector) collectClrInterop(ch chan<- prometheus.Metric, _ time.Duration) error { +func (c *Collector) collectClrInterop(ch chan<- prometheus.Metric, scrape *labelcache.Scrape, _ time.Duration) error { var dst []perfDataClrInterop if err := c.perfClrInterop.Collect(&dst); err != nil { return fmt.Errorf("failed to collect .NET CLR Interop: %w", err) @@ -74,21 +75,21 @@ func (c *Collector) collectClrInterop(ch chan<- prometheus.Metric, _ time.Durati continue } - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.numberOfCCWs, prometheus.CounterValue, float64(process.NumberofCCWs), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.numberOfMarshalling, prometheus.CounterValue, float64(process.Numberofmarshalling), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.numberOfStubs, prometheus.CounterValue, float64(process.NumberofStubs), diff --git a/internal/collector/netframework/netframework_clrjit.go b/internal/collector/netframework/netframework_clrjit.go index 25ae4d01..3b5d1156 100644 --- a/internal/collector/netframework/netframework_clrjit.go +++ b/internal/collector/netframework/netframework_clrjit.go @@ -21,6 +21,7 @@ import ( "fmt" "time" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" ) @@ -70,7 +71,7 @@ type perfDataClrJIT struct { TotalNumberofILBytesJitted float64 `perfdata:"Total # of IL Bytes Jitted"` } -func (c *Collector) collectClrJIT(ch chan<- prometheus.Metric, _ time.Duration) error { +func (c *Collector) collectClrJIT(ch chan<- prometheus.Metric, scrape *labelcache.Scrape, _ time.Duration) error { var dst []perfDataClrJIT if err := c.perfClrJIT.Collect(&dst); err != nil { return fmt.Errorf("failed to collect .NET CLR Jit: %w", err) @@ -81,28 +82,28 @@ func (c *Collector) collectClrJIT(ch chan<- prometheus.Metric, _ time.Duration) continue } - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.numberOfMethodsJitted, prometheus.CounterValue, float64(process.NumberofMethodsJitted), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.timeInJit, prometheus.GaugeValue, float64(process.PercentTimeinJit)/c.perfFrequency, process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.standardJitFailures, prometheus.GaugeValue, float64(process.StandardJitFailures), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.totalNumberOfILBytesJitted, prometheus.CounterValue, float64(process.TotalNumberofILBytesJitted), diff --git a/internal/collector/netframework/netframework_clrloading.go b/internal/collector/netframework/netframework_clrloading.go index cdd8a0f7..c06a9d41 100644 --- a/internal/collector/netframework/netframework_clrloading.go +++ b/internal/collector/netframework/netframework_clrloading.go @@ -21,6 +21,7 @@ import ( "fmt" "time" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" ) @@ -105,7 +106,7 @@ type perfDataClrLoading struct { Totalappdomainsunloaded float64 `perfdata:"Total appdomains unloaded"` } -func (c *Collector) collectClrLoading(ch chan<- prometheus.Metric, _ time.Duration) error { +func (c *Collector) collectClrLoading(ch chan<- prometheus.Metric, scrape *labelcache.Scrape, _ time.Duration) error { var dst []perfDataClrLoading if err := c.perfClrLoading.Collect(&dst); err != nil { return fmt.Errorf("failed to collect .NET CLR Loading: %w", err) @@ -116,63 +117,63 @@ func (c *Collector) collectClrLoading(ch chan<- prometheus.Metric, _ time.Durati continue } - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.bytesInLoaderHeap, prometheus.GaugeValue, float64(process.BytesinLoaderHeap), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.currentAppDomains, prometheus.GaugeValue, float64(process.Currentappdomains), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.currentAssemblies, prometheus.GaugeValue, float64(process.CurrentAssemblies), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.currentClassesLoaded, prometheus.GaugeValue, float64(process.CurrentClassesLoaded), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.totalAppDomains, prometheus.CounterValue, float64(process.TotalAppdomains), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.totalAppDomainsUnloaded, prometheus.CounterValue, float64(process.Totalappdomainsunloaded), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.totalAssemblies, prometheus.CounterValue, float64(process.TotalAssemblies), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.totalClassesLoaded, prometheus.CounterValue, float64(process.TotalClassesLoaded), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.totalNumberOfLoadFailures, prometheus.CounterValue, float64(process.TotalNumberofLoadFailures), diff --git a/internal/collector/netframework/netframework_clrlocksandthreads.go b/internal/collector/netframework/netframework_clrlocksandthreads.go index a0b241b6..2ad3b9d8 100644 --- a/internal/collector/netframework/netframework_clrlocksandthreads.go +++ b/internal/collector/netframework/netframework_clrlocksandthreads.go @@ -21,6 +21,7 @@ import ( "fmt" "time" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" ) @@ -91,7 +92,7 @@ type perfDataClrLocksAndThreads struct { TotalNumberofContentions float64 `perfdata:"Total # of Contentions"` } -func (c *Collector) collectClrLocksAndThreads(ch chan<- prometheus.Metric, _ time.Duration) error { +func (c *Collector) collectClrLocksAndThreads(ch chan<- prometheus.Metric, scrape *labelcache.Scrape, _ time.Duration) error { var dst []perfDataClrLocksAndThreads if err := c.perfClrLocksAndThreads.Collect(&dst); err != nil { return fmt.Errorf("failed to collect .NET CLR LocksAndThreads: %w", err) @@ -102,49 +103,49 @@ func (c *Collector) collectClrLocksAndThreads(ch chan<- prometheus.Metric, _ tim continue } - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.currentQueueLength, prometheus.GaugeValue, float64(process.CurrentQueueLength), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.numberOfCurrentLogicalThreads, prometheus.GaugeValue, float64(process.NumberofcurrentlogicalThreads), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.numberOfCurrentPhysicalThreads, prometheus.GaugeValue, float64(process.NumberofcurrentphysicalThreads), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.numberOfCurrentRecognizedThreads, prometheus.GaugeValue, float64(process.Numberofcurrentrecognizedthreads), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.numberOfTotalRecognizedThreads, prometheus.CounterValue, float64(process.Numberoftotalrecognizedthreads), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.queueLengthPeak, prometheus.CounterValue, float64(process.QueueLengthPeak), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.totalNumberOfContentions, prometheus.CounterValue, float64(process.TotalNumberofContentions), diff --git a/internal/collector/netframework/netframework_clrmemory.go b/internal/collector/netframework/netframework_clrmemory.go index c5b43164..6848fe5a 100644 --- a/internal/collector/netframework/netframework_clrmemory.go +++ b/internal/collector/netframework/netframework_clrmemory.go @@ -22,6 +22,7 @@ import ( "strconv" "time" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" ) @@ -135,7 +136,7 @@ type perfDataClrMemory struct { ProcessID float64 `perfdata:"Process ID"` } -func (c *Collector) collectClrMemory(ch chan<- prometheus.Metric, _ time.Duration) error { +func (c *Collector) collectClrMemory(ch chan<- prometheus.Metric, scrape *labelcache.Scrape, _ time.Duration) error { var dst []perfDataClrMemory if err := c.perfClrMemory.Collect(&dst); err != nil { return fmt.Errorf("failed to collect .NET CLR Memory: %w", err) @@ -146,7 +147,7 @@ func (c *Collector) collectClrMemory(ch chan<- prometheus.Metric, _ time.Duratio continue } - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.allocatedBytes, prometheus.CounterValue, float64(process.AllocatedBytesPersec), @@ -154,7 +155,7 @@ func (c *Collector) collectClrMemory(ch chan<- prometheus.Metric, _ time.Duratio strconv.FormatUint(uint64(process.ProcessID), 10), ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.finalizationSurvivors, prometheus.GaugeValue, float64(process.FinalizationSurvivors), @@ -162,7 +163,7 @@ func (c *Collector) collectClrMemory(ch chan<- prometheus.Metric, _ time.Duratio strconv.FormatUint(uint64(process.ProcessID), 10), ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.heapSize, prometheus.GaugeValue, float64(process.Gen0heapsize), @@ -171,7 +172,7 @@ func (c *Collector) collectClrMemory(ch chan<- prometheus.Metric, _ time.Duratio "Gen0", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.promotedBytes, prometheus.GaugeValue, float64(process.Gen0PromotedBytesPerSec), @@ -180,7 +181,7 @@ func (c *Collector) collectClrMemory(ch chan<- prometheus.Metric, _ time.Duratio "Gen0", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.heapSize, prometheus.GaugeValue, float64(process.Gen1heapsize), @@ -189,7 +190,7 @@ func (c *Collector) collectClrMemory(ch chan<- prometheus.Metric, _ time.Duratio "Gen1", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.promotedBytes, prometheus.GaugeValue, float64(process.Gen1PromotedBytesPerSec), @@ -198,7 +199,7 @@ func (c *Collector) collectClrMemory(ch chan<- prometheus.Metric, _ time.Duratio "Gen1", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.heapSize, prometheus.GaugeValue, float64(process.Gen2heapsize), @@ -207,7 +208,7 @@ func (c *Collector) collectClrMemory(ch chan<- prometheus.Metric, _ time.Duratio "Gen2", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.heapSize, prometheus.GaugeValue, float64(process.LargeObjectHeapsize), @@ -216,7 +217,7 @@ func (c *Collector) collectClrMemory(ch chan<- prometheus.Metric, _ time.Duratio "LOH", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.numberGCHandles, prometheus.GaugeValue, float64(process.NumberGCHandles), @@ -224,7 +225,7 @@ func (c *Collector) collectClrMemory(ch chan<- prometheus.Metric, _ time.Duratio strconv.FormatUint(uint64(process.ProcessID), 10), ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.numberCollections, prometheus.CounterValue, float64(process.NumberGen0Collections), @@ -233,7 +234,7 @@ func (c *Collector) collectClrMemory(ch chan<- prometheus.Metric, _ time.Duratio "Gen0", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.numberCollections, prometheus.CounterValue, float64(process.NumberGen1Collections), @@ -242,7 +243,7 @@ func (c *Collector) collectClrMemory(ch chan<- prometheus.Metric, _ time.Duratio "Gen1", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.numberCollections, prometheus.CounterValue, float64(process.NumberGen2Collections), @@ -251,7 +252,7 @@ func (c *Collector) collectClrMemory(ch chan<- prometheus.Metric, _ time.Duratio "Gen2", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.numberInducedGC, prometheus.CounterValue, float64(process.NumberInducedGC), @@ -259,7 +260,7 @@ func (c *Collector) collectClrMemory(ch chan<- prometheus.Metric, _ time.Duratio strconv.FormatUint(uint64(process.ProcessID), 10), ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.numberOfPinnedObjects, prometheus.GaugeValue, float64(process.NumberofPinnedObjects), @@ -267,7 +268,7 @@ func (c *Collector) collectClrMemory(ch chan<- prometheus.Metric, _ time.Duratio strconv.FormatUint(uint64(process.ProcessID), 10), ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.numberOfSinkBlocksInUse, prometheus.GaugeValue, float64(process.NumberofSinkBlocksinuse), @@ -275,7 +276,7 @@ func (c *Collector) collectClrMemory(ch chan<- prometheus.Metric, _ time.Duratio strconv.FormatUint(uint64(process.ProcessID), 10), ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.numberTotalCommittedBytes, prometheus.GaugeValue, float64(process.NumberTotalcommittedBytes), @@ -283,7 +284,7 @@ func (c *Collector) collectClrMemory(ch chan<- prometheus.Metric, _ time.Duratio strconv.FormatUint(uint64(process.ProcessID), 10), ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.numberTotalReservedBytes, prometheus.GaugeValue, float64(process.NumberTotalreservedBytes), @@ -295,7 +296,7 @@ func (c *Collector) collectClrMemory(ch chan<- prometheus.Metric, _ time.Duratio continue } - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.timeInGC, prometheus.GaugeValue, 100*process.PercentTimeinGC/process.PercentTimeinGC_base, diff --git a/internal/collector/netframework/netframework_clrremoting.go b/internal/collector/netframework/netframework_clrremoting.go index 0143d78c..8eee12dc 100644 --- a/internal/collector/netframework/netframework_clrremoting.go +++ b/internal/collector/netframework/netframework_clrremoting.go @@ -21,6 +21,7 @@ import ( "fmt" "time" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" ) @@ -84,7 +85,7 @@ type perfDataClrRemoting struct { TotalRemoteCalls float64 `perfdata:"Total Remote Calls"` } -func (c *Collector) collectClrRemoting(ch chan<- prometheus.Metric, _ time.Duration) error { +func (c *Collector) collectClrRemoting(ch chan<- prometheus.Metric, scrape *labelcache.Scrape, _ time.Duration) error { var dst []perfDataClrRemoting if err := c.perfClrRemoting.Collect(&dst); err != nil { return fmt.Errorf("failed to collect .NET CLR Remoting: %w", err) @@ -95,42 +96,42 @@ func (c *Collector) collectClrRemoting(ch chan<- prometheus.Metric, _ time.Durat continue } - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.channels, prometheus.CounterValue, float64(process.Channels), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.contextBoundClassesLoaded, prometheus.GaugeValue, float64(process.ContextBoundClassesLoaded), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.contextBoundObjects, prometheus.CounterValue, float64(process.ContextBoundObjectsAllocPersec), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.contextProxies, prometheus.CounterValue, float64(process.ContextProxies), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.contexts, prometheus.GaugeValue, float64(process.Contexts), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.totalRemoteCalls, prometheus.CounterValue, float64(process.TotalRemoteCalls), diff --git a/internal/collector/netframework/netframework_clrsecurity.go b/internal/collector/netframework/netframework_clrsecurity.go index 24e385de..8ec5979f 100644 --- a/internal/collector/netframework/netframework_clrsecurity.go +++ b/internal/collector/netframework/netframework_clrsecurity.go @@ -21,6 +21,7 @@ import ( "fmt" "time" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" ) @@ -70,7 +71,7 @@ type perfDataClrSecurity struct { TotalRuntimeChecks float64 `perfdata:"Total Runtime Checks"` } -func (c *Collector) collectClrSecurity(ch chan<- prometheus.Metric, _ time.Duration) error { +func (c *Collector) collectClrSecurity(ch chan<- prometheus.Metric, scrape *labelcache.Scrape, _ time.Duration) error { var dst []perfDataClrSecurity if err := c.perfClrSecurity.Collect(&dst); err != nil { return fmt.Errorf("failed to collect .NET CLR Security: %w", err) @@ -81,28 +82,28 @@ func (c *Collector) collectClrSecurity(ch chan<- prometheus.Metric, _ time.Durat continue } - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.numberLinkTimeChecks, prometheus.CounterValue, float64(process.NumberLinkTimeChecks), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.timeInRTChecks, prometheus.GaugeValue, float64(process.PercentTimeinRTchecks)/c.perfFrequency, process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.stackWalkDepth, prometheus.GaugeValue, float64(process.StackWalkDepth), process.Name, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.totalRuntimeChecks, prometheus.CounterValue, float64(process.TotalRuntimeChecks), diff --git a/internal/collector/netframework/netframework_pdh_test.go b/internal/collector/netframework/netframework_pdh_test.go index 9eb55f50..cb461b8a 100644 --- a/internal/collector/netframework/netframework_pdh_test.go +++ b/internal/collector/netframework/netframework_pdh_test.go @@ -23,6 +23,7 @@ import ( "testing" "time" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/pdh" "github.com/prometheus/client_golang/prometheus" dto "github.com/prometheus/client_model/go" @@ -57,14 +58,27 @@ type expectedMetric struct { area string } -func assertFixtureMetrics(t *testing.T, collect func(chan<- prometheus.Metric, time.Duration) error, expected []expectedMetric, withPID bool) { +func assertFixtureMetrics(t *testing.T, collect func(chan<- prometheus.Metric, *labelcache.Scrape, time.Duration) error, expected []expectedMetric, withPID bool) { t.Helper() + // A first scrape fills the label cache, so the checked scrape publishes + // series with reused label pairs. + var cache labelcache.Cache + + prime := cache.Begin() + primeCh := make(chan prometheus.Metric, 1024) + require.NoError(t, collect(primeCh, prime, time.Second)) + prime.Commit() + registry := prometheus.NewRegistry() var collectErr error - registry.MustRegister(fixturePromCollector{collect: func(ch chan<- prometheus.Metric) { collectErr = collect(ch, time.Second) }}) + registry.MustRegister(fixturePromCollector{collect: func(ch chan<- prometheus.Metric) { + scrape := cache.Begin() + collectErr = collect(ch, scrape, time.Second) + scrape.Commit() + }}) families, err := registry.Gather() require.NoError(t, err) require.NoError(t, collectErr) @@ -382,7 +396,7 @@ func TestGCZeroBaseDoesNotPublishInvalidRatio(t *testing.T) { c.describeClrMemory() c.perfClrMemory = &fixturePerfCollector[perfDataClrMemory]{rows: []perfDataClrMemory{{Name: "worker", ProcessID: 123, AllocatedBytesPersec: 99}}} registry := prometheus.NewRegistry() - registry.MustRegister(fixturePromCollector{collect: func(ch chan<- prometheus.Metric) { require.NoError(t, c.collectClrMemory(ch, time.Second)) }}) + registry.MustRegister(fixturePromCollector{collect: func(ch chan<- prometheus.Metric) { require.NoError(t, c.collectClrMemory(ch, nil, time.Second)) }}) families, err := registry.Gather() require.NoError(t, err) @@ -416,7 +430,7 @@ func TestNoDataIsReturned(t *testing.T) { c.describeClrExceptions() c.perfClrExceptions = unavailablePerfCollector[perfDataClrExceptions]{} ch := make(chan prometheus.Metric, 16) - require.ErrorIs(t, c.collectClrExceptions(ch, time.Second), pdh.ErrNoData) + require.ErrorIs(t, c.collectClrExceptions(ch, nil, time.Second), pdh.ErrNoData) require.Empty(t, ch) } @@ -450,7 +464,7 @@ func BenchmarkClrMemoryMetricPublication(b *testing.B) { b.ResetTimer() for b.Loop() { - if err := c.collectClrMemory(ch, time.Second); err != nil { + if err := c.collectClrMemory(ch, nil, time.Second); err != nil { b.Fatal(err) } @@ -467,7 +481,7 @@ func TestCollectRetainsSuccessfulChildMetrics(t *testing.T) { c.perfClrExceptions = &fixturePerfCollector[perfDataClrExceptions]{rows: []perfDataClrExceptions{{Name: "worker", NumberofExcepsThrown: 37}}} failure := errors.New("provider failed") c.perfClrInterop = &fixturePerfCollector[perfDataClrInterop]{err: failure} - c.collectorFns = []func(chan<- prometheus.Metric, time.Duration) error{c.collectClrExceptions, c.collectClrInterop} + c.collectorFns = []func(chan<- prometheus.Metric, *labelcache.Scrape, time.Duration) error{c.collectClrExceptions, c.collectClrInterop} registry := prometheus.NewRegistry() var collectErr error diff --git a/internal/collector/process/process.go b/internal/collector/process/process.go index bbf53fe0..4a044e96 100644 --- a/internal/collector/process/process.go +++ b/internal/collector/process/process.go @@ -29,6 +29,7 @@ import ( "time" "github.com/alecthomas/kingpin/v2" + "github.com/prometheus-community/windows_exporter/internal/labelcache" "github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" @@ -74,6 +75,10 @@ type Collector struct { snapshot snapshotBuffer processes []processSnapshot + // labels keeps the label pairs of the series of the last scrape. Process + // values change on every scrape, but their labels stay the same while + // the process runs. + labels labelcache.Cache // infoCache holds the windows_process_info values of the processes of the last scrape, keyed by PID. infoCache map[uint32]processInfo @@ -176,6 +181,7 @@ func (c *Collector) Close() error { c.snapshot = snapshotBuffer{} c.processes = nil c.infoCache = nil + c.labels.Reset() // The session belongs to the caller of Build. c.miSession = nil @@ -374,13 +380,16 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric, maxScrapeDuration time. infos := c.resolveProcessInfo(processes) + scrape := c.labels.Begin() + defer scrape.Commit() + for i, process := range processes { name := process.name if appPoolName := appPools[process.pid]; appPoolName != "" { name = name + "_" + appPoolName } - c.collectProcess(ch, name, process, &infos[i]) + c.collectProcess(ch, scrape, name, process, &infos[i]) } return err @@ -463,10 +472,10 @@ func resolveAppPools( return appPools, nil } -func (c *Collector) collectProcess(ch chan<- prometheus.Metric, name string, process *processSnapshot, info *processInfo) { +func (c *Collector) collectProcess(ch chan<- prometheus.Metric, scrape *labelcache.Scrape, name string, process *processSnapshot, info *processInfo) { pid := strconv.FormatUint(uint64(process.pid), 10) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.info, prometheus.GaugeValue, 1.0, @@ -474,147 +483,147 @@ func (c *Collector) collectProcess(ch chan<- prometheus.Metric, name string, pro ) // Perflib reports whole seconds for the Elapsed Time counter of the Process counter set. - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.startTime, prometheus.GaugeValue, float64((process.createTime-windowsEpoch)/ticksPerSecond), name, pid, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.handleCount, prometheus.GaugeValue, float64(process.handleCount), name, pid, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.cpuTimeTotal, prometheus.CounterValue, float64(process.kernelTime)*secondsPerTick, name, pid, "privileged", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.cpuTimeTotal, prometheus.CounterValue, float64(process.userTime)*secondsPerTick, name, pid, "user", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.ioBytesTotal, prometheus.CounterValue, float64(process.otherTransferCount), name, pid, "other", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.ioOperationsTotal, prometheus.CounterValue, float64(process.otherOperationCount), name, pid, "other", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.ioBytesTotal, prometheus.CounterValue, float64(process.readTransferCount), name, pid, "read", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.ioOperationsTotal, prometheus.CounterValue, float64(process.readOperationCount), name, pid, "read", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.ioBytesTotal, prometheus.CounterValue, float64(process.writeTransferCount), name, pid, "write", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.ioOperationsTotal, prometheus.CounterValue, float64(process.writeOperationCount), name, pid, "write", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.pageFaultsTotal, prometheus.CounterValue, float64(process.pageFaultCount), name, pid, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.pageFileBytes, prometheus.GaugeValue, float64(process.pageFileUsage), name, pid, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.poolBytes, prometheus.GaugeValue, float64(process.nonPagedPoolUsage), name, pid, "nonpaged", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.poolBytes, prometheus.GaugeValue, float64(process.pagedPoolUsage), name, pid, "paged", ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.priorityBase, prometheus.GaugeValue, float64(process.basePriority), name, pid, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.privateBytes, prometheus.GaugeValue, float64(process.privatePageCount), name, pid, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.threadCount, prometheus.GaugeValue, float64(process.threadCount), name, pid, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.virtualBytes, prometheus.GaugeValue, float64(process.virtualSize), name, pid, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.workingSetPrivate, prometheus.GaugeValue, float64(process.workingSetPrivate), name, pid, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.workingSetPeak, prometheus.GaugeValue, float64(process.workingSetPeak), name, pid, ) - ch <- prometheus.MustNewConstMetric( + ch <- scrape.MustNewConstMetric( c.workingSet, prometheus.GaugeValue, float64(process.workingSetSize), diff --git a/internal/labelcache/labelcache.go b/internal/labelcache/labelcache.go new file mode 100644 index 00000000..fbb9de1b --- /dev/null +++ b/internal/labelcache/labelcache.go @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package labelcache reuses the label pairs of const metrics between scrapes. +// +// prometheus.NewConstMetric builds and sorts the label pairs of a series on +// every call. For series whose value changes on every scrape, such as process +// counters, internal/metriccache can't reuse the metric, but the labels stay +// the same as long as the series exists. A Scrape hands out metrics that share +// the label pairs built for the same series in the previous scrape. Series that +// aren't reported in a scrape are dropped when it commits. +package labelcache + +import ( + "fmt" + "sync" + + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" +) + +// maxLabels is the largest number of label values a cached series can have. +// Metrics with more labels are created without the cache. +const maxLabels = 6 + +// key identifies a series. It is a fixed-size array, so building and looking up +// a key doesn't allocate. +type key struct { + desc *prometheus.Desc + n int + values [maxLabels]string +} + +// Cache holds the label pairs of the last committed scrape. The zero value is +// ready to use. +type Cache struct { + mu sync.Mutex + entries map[key][]*dto.LabelPair + // resets counts Reset calls, so that a scrape begun before a Reset doesn't + // commit afterwards. + resets uint64 + // active counts the scrapes between Begin and Commit. spare is a replaced + // generation that no scrape reads anymore; the next scrape reuses it + // instead of allocating a new map. + active int + spare map[key][]*dto.LabelPair +} + +// Scrape creates the metrics of one scrape. +type Scrape struct { + cache *Cache + resets uint64 + // prev is the last committed generation. It is never modified, so it is + // read without holding mu. + prev map[key][]*dto.LabelPair + + mu sync.Mutex + // next collects the label pairs of this scrape. Commit hands it to the + // cache and sets it to nil. + next map[key][]*dto.LabelPair +} + +// Begin starts a scrape. Call Commit when it is done. +func (c *Cache) Begin() *Scrape { + c.mu.Lock() + prev, resets, next := c.entries, c.resets, c.spare + c.spare = nil + c.active++ + c.mu.Unlock() + + if next == nil { + next = make(map[key][]*dto.LabelPair, len(prev)) + } + + return &Scrape{ + cache: c, + resets: resets, + prev: prev, + next: next, + } +} + +// Reset drops all cached label pairs, for example when the collector closes. +func (c *Cache) Reset() { + c.mu.Lock() + c.entries = nil + c.spare = nil + c.resets++ + c.mu.Unlock() +} + +// Commit makes the series of this scrape the base of the next one. Series of +// the previous scrape that this scrape didn't report are dropped. +func (s *Scrape) Commit() { + if s == nil { + return + } + + s.mu.Lock() + next := s.next + s.next = nil + s.mu.Unlock() + + if next == nil { + return + } + + s.cache.mu.Lock() + defer s.cache.mu.Unlock() + + s.cache.active-- + + if s.cache.resets != s.resets { + return + } + + replaced := s.cache.entries + s.cache.entries = next + + // Other scrapes may still read the replaced generation. + if s.cache.active == 0 && replaced != nil { + clear(replaced) + s.cache.spare = replaced + } +} + +// MustNewConstMetric is prometheus.MustNewConstMetric, but it reuses the label +// pairs of the series from the previous scrape. A nil Scrape creates the metric +// without the cache. +// +//nolint:ireturn // Const metrics have no exported type. +func (s *Scrape) MustNewConstMetric(desc *prometheus.Desc, valueType prometheus.ValueType, value float64, labelValues ...string) prometheus.Metric { + if s == nil || len(labelValues) > maxLabels { + return prometheus.MustNewConstMetric(desc, valueType, value, append([]string(nil), labelValues...)...) + } + + k := key{desc: desc, n: len(labelValues)} + copy(k.values[:], labelValues) + + labels, ok := s.prev[k] + + s.mu.Lock() + if !ok { + labels, ok = s.next[k] + } + + if ok && s.next != nil { + s.next[k] = labels + } + s.mu.Unlock() + + if ok { + return &constMetric{desc: desc, valueType: valueType, value: value, labels: labels} + } + + // A new series: prometheus validates the label values and builds the + // pairs, which the following scrapes share. + metric := prometheus.MustNewConstMetric(desc, valueType, value, append([]string(nil), labelValues...)...) + + var out dto.Metric + if err := metric.Write(&out); err == nil { + s.mu.Lock() + if s.next != nil { + s.next[k] = out.GetLabel() + } + s.mu.Unlock() + } + + return metric +} + +// constMetric is a const metric with shared label pairs. Label pairs are +// immutable once written, like those of prometheus.NewConstMetric. +type constMetric struct { + desc *prometheus.Desc + labels []*dto.LabelPair + value float64 + valueType prometheus.ValueType +} + +func (m *constMetric) Desc() *prometheus.Desc { + return m.desc +} + +func (m *constMetric) Write(out *dto.Metric) error { + out.Label = m.labels + + switch m.valueType { + case prometheus.CounterValue: + out.Counter = &dto.Counter{Value: &m.value} + case prometheus.GaugeValue: + out.Gauge = &dto.Gauge{Value: &m.value} + case prometheus.UntypedValue: + out.Untyped = &dto.Untyped{Value: &m.value} + default: + return fmt.Errorf("encountered unknown type %v", m.valueType) + } + + return nil +} diff --git a/internal/labelcache/labelcache_test.go b/internal/labelcache/labelcache_test.go new file mode 100644 index 00000000..4c0ac56f --- /dev/null +++ b/internal/labelcache/labelcache_test.go @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package labelcache_test + +import ( + "strconv" + "sync" + "testing" + + "github.com/prometheus-community/windows_exporter/internal/labelcache" + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" +) + +//nolint:gochecknoglobals +var ( + counterDesc = prometheus.NewDesc("test_cpu_seconds_total", "test", []string{"process", "process_id", "mode"}, prometheus.Labels{"const": "x"}) + gaugeDesc = prometheus.NewDesc("test_handles", "test", []string{"process", "process_id"}, nil) + untypedDesc = prometheus.NewDesc("test_untyped", "test", nil, nil) + wideDesc = prometheus.NewDesc("test_info", "test", []string{"a", "b", "c", "d", "e", "f", "g"}, nil) +) + +func write(t *testing.T, metric prometheus.Metric) *dto.Metric { + t.Helper() + + var out dto.Metric + + require.NoError(t, metric.Write(&out)) + + return &out +} + +// Cached metrics must write exactly what prometheus.MustNewConstMetric writes, +// in the first scrape (new series) and the following ones (shared labels). +func TestMustNewConstMetric(t *testing.T) { + t.Parallel() + + var cache labelcache.Cache + + cases := []struct { + desc *prometheus.Desc + valueType prometheus.ValueType + values []string + }{ + {counterDesc, prometheus.CounterValue, []string{"svchost", "1234", "user"}}, + {counterDesc, prometheus.CounterValue, []string{"svchost", "1234", "privileged"}}, + {gaugeDesc, prometheus.GaugeValue, []string{"svchost", "1234"}}, + {untypedDesc, prometheus.UntypedValue, nil}, + {wideDesc, prometheus.GaugeValue, []string{"1", "2", "3", "4", "5", "6", "7"}}, + } + + for scrapeNumber := range 3 { + scrape := cache.Begin() + + for i, tc := range cases { + value := float64(scrapeNumber*10 + i) + got := scrape.MustNewConstMetric(tc.desc, tc.valueType, value, tc.values...) + want := prometheus.MustNewConstMetric(tc.desc, tc.valueType, value, tc.values...) + + require.Equal(t, want.Desc(), got.Desc()) + require.True(t, proto.Equal(write(t, want), write(t, got)), "scrape %d, case %d:\nwant %v\ngot %v", scrapeNumber, i, write(t, want), write(t, got)) + } + + scrape.Commit() + } +} + +// From the second scrape on, a series reuses the label pairs of the previous +// one; series that a scrape didn't report get new pairs. +func TestLabelReuse(t *testing.T) { + t.Parallel() + + var cache labelcache.Cache + + labelsOf := func(scrape *labelcache.Scrape, pid string) []*dto.LabelPair { + return write(t, scrape.MustNewConstMetric(gaugeDesc, prometheus.GaugeValue, 1, "p", pid)).GetLabel() + } + + scrape := cache.Begin() + first := labelsOf(scrape, "1") + labelsOf(scrape, "2") + scrape.Commit() + + scrape = cache.Begin() + require.Same(t, first[0], labelsOf(scrape, "1")[0], "label pairs reused") + scrape.Commit() + + // Process 2 wasn't reported in the second scrape, so its pairs were dropped. + scrape = cache.Begin() + second := labelsOf(scrape, "2") + require.Equal(t, "2", second[1].GetValue()) + scrape.Commit() + + scrape = cache.Begin() + require.Same(t, second[0], labelsOf(scrape, "2")[0]) + scrape.Commit() + + cache.Reset() + + scrape = cache.Begin() + require.NotSame(t, second[0], labelsOf(scrape, "2")[0], "reset drops the cache") + scrape.Commit() +} + +// A scrape begun before Reset must not restore its generation afterwards. +func TestResetDuringScrape(t *testing.T) { + t.Parallel() + + var cache labelcache.Cache + + scrape := cache.Begin() + pairs := write(t, scrape.MustNewConstMetric(gaugeDesc, prometheus.GaugeValue, 1, "p", "1")).GetLabel() + + cache.Reset() + scrape.Commit() + + scrape = cache.Begin() + require.NotSame(t, pairs[0], write(t, scrape.MustNewConstMetric(gaugeDesc, prometheus.GaugeValue, 1, "p", "1")).GetLabel()[0]) + scrape.Commit() + scrape.Commit() +} + +func TestInvalidLabelValues(t *testing.T) { + t.Parallel() + + var cache labelcache.Cache + + scrape := cache.Begin() + + require.Panics(t, func() { scrape.MustNewConstMetric(gaugeDesc, prometheus.GaugeValue, 1, "only one") }) + require.Panics(t, func() { scrape.MustNewConstMetric(gaugeDesc, prometheus.GaugeValue, 1, "p", "\xff") }) +} + +func TestConcurrentScrapes(t *testing.T) { + t.Parallel() + + var ( + cache labelcache.Cache + wg sync.WaitGroup + ) + + for range 8 { + wg.Go(func() { + for range 20 { + scrape := cache.Begin() + + var inner sync.WaitGroup + + for p := range 4 { + inner.Go(func() { + for pid := range 50 { + m := scrape.MustNewConstMetric(counterDesc, prometheus.CounterValue, 1, "p"+strconv.Itoa(p), strconv.Itoa(pid), "user") + if err := m.Write(&dto.Metric{}); err != nil { + t.Error(err) + } + } + }) + } + + inner.Wait() + scrape.Commit() + } + }) + } + + wg.Wait() +} + +func BenchmarkMustNewConstMetric(b *testing.B) { + pids := make([]string, 500) + for i := range pids { + pids[i] = strconv.Itoa(1000 + i) + } + + b.Run("prometheus", func(b *testing.B) { + b.ReportAllocs() + + for b.Loop() { + for _, pid := range pids { + _ = prometheus.MustNewConstMetric(counterDesc, prometheus.CounterValue, 1, "svchost", pid, "user") + } + } + }) + + b.Run("labelcache", func(b *testing.B) { + var cache labelcache.Cache + + b.ReportAllocs() + + for b.Loop() { + scrape := cache.Begin() + for _, pid := range pids { + _ = scrape.MustNewConstMetric(counterDesc, prometheus.CounterValue, 1, "svchost", pid, "user") + } + + scrape.Commit() + } + }) +}