diff --git a/internal/collector/iis/cache_metrics_test.go b/internal/collector/iis/cache_metrics_test.go new file mode 100644 index 00000000..336f51d8 --- /dev/null +++ b/internal/collector/iis/cache_metrics_test.go @@ -0,0 +1,135 @@ +// 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. + +//go:build windows + +package iis + +import ( + "reflect" + "testing" + + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/stretchr/testify/require" +) + +func TestCacheCounterSourcesDistinct(t *testing.T) { + t.Parallel() + + for _, counterType := range []reflect.Type{reflect.TypeFor[perfDataCounterServiceCache](), reflect.TypeFor[perfDataCounterValuesW3SVCW3WP]()} { + seen := make(map[string]string) + + for _, field := range reflect.VisibleFields(counterType) { + tag := field.Tag.Get("perfdata") + if tag == "" { + continue + } + + require.Empty(t, seen[tag], "%s maps both %s and %s", tag, seen[tag], field.Name) + seen[tag] = field.Name + } + } +} + +func TestCacheEmitsDifferentSourceValues(t *testing.T) { + t.Parallel() + + sources := map[string]float64{ + "URI Cache Flushes": 3, "Kernel: URI Cache Flushes": 5, + "Total Flushed URIs": 7, "Kernel: Total Flushed URIs": 11, + "Total URIs Cached": 20, "Kernel: Total URIs Cached": 40, + "Metadata Cache Hits": 80, "Metadata Cache Misses": 20, + "Output Cache Current Flushed Items": 13, + "Output Cache Current Items": 17, + "Output Cache Current Memory Usage": 19, + } + c := New(nil) + c.buildWebServiceCacheDescriptors() + c.buildW3SVCW3WPDescriptors() + c.serviceCachePerfDataCollector = cacheFixture[perfDataCounterServiceCache]{sources: sources} + c.w3SVCW3WPPerfDataCollector = cacheFixture[perfDataCounterValuesW3SVCW3WP]{sources: sources} + metrics := make(chan prometheus.Metric, 200) + require.NoError(t, c.collectWebServiceCache(metrics)) + require.NoError(t, c.collectW3SVCW3WPv7(metrics)) + close(metrics) + + values := make(map[*prometheus.Desc][]*dto.Metric) + + for metric := range metrics { + value := &dto.Metric{} + require.NoError(t, metric.Write(value)) + values[metric.Desc()] = append(values[metric.Desc()], value) + } + + for _, tc := range []struct { + desc *prometheus.Desc + want []float64 + }{ + {c.serviceCacheURICacheFlushesTotal, []float64{3, 5}}, + {c.serviceCacheURIsFlushedTotal, []float64{7, 11}}, + {c.serviceCacheURIsCachedTotal, []float64{20, 40}}, + {c.serviceCacheMetadataCacheHitsTotal, []float64{80}}, + {c.w3SVCW3WPURICacheFlushesTotal, []float64{3}}, + {c.w3SVCW3WPURIsFlushedTotal, []float64{7}}, + } { + require.Len(t, values[tc.desc], len(tc.want)) + + for i, expected := range tc.want { + require.InDelta(t, expected, values[tc.desc][i].GetCounter().GetValue(), 1e-9) + } + } + + for _, tc := range []struct { + desc *prometheus.Desc + want float64 + }{ + {c.serviceCacheOutputCacheActiveFlushedItems, 13}, + {c.serviceCacheOutputCacheItems, 17}, + {c.serviceCacheOutputCacheMemoryUsage, 19}, + {c.w3SVCW3WPOutputCacheActiveFlushedItems, 13}, + {c.w3SVCW3WPOutputCacheItems, 17}, + {c.w3SVCW3WPOutputCacheMemoryUsage, 19}, + } { + require.Len(t, values[tc.desc], 1) + require.NotNil(t, values[tc.desc][0].GetGauge()) + require.InDelta(t, tc.want, values[tc.desc][0].GetGauge().GetValue(), 1e-9) + } +} + +type cacheFixture[T any] struct{ sources map[string]float64 } + +func (f cacheFixture[T]) Collect(dst *[]T) error { + var row T + + value := reflect.ValueOf(&row).Elem() + for _, field := range reflect.VisibleFields(value.Type()) { + if field.Name == "Name" { + value.FieldByIndex(field.Index).SetString("123_Example") + + continue + } + + if tag := field.Tag.Get("perfdata"); tag != "" { + value.FieldByIndex(field.Index).SetFloat(f.sources[tag]) + } + } + + *dst = []T{row} + + return nil +} + +func (f cacheFixture[T]) Close() {} diff --git a/internal/collector/iis/iis_w3svc_w3wp.go b/internal/collector/iis/iis_w3svc_w3wp.go index 01a48a9a..0daea12e 100644 --- a/internal/collector/iis/iis_w3svc_w3wp.go +++ b/internal/collector/iis/iis_w3svc_w3wp.go @@ -22,12 +22,13 @@ import ( "regexp" "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" "github.com/prometheus/client_golang/prometheus" ) type collectorW3SVCW3WP struct { - w3SVCW3WPPerfDataCollector *pdh.Collector[perfDataCounterValuesW3SVCW3WP] + w3SVCW3WPPerfDataCollector pdhtypes.Collector[perfDataCounterValuesW3SVCW3WP] w3SVCW3WPPerfDataCollectorV8 *pdh.Collector[perfDataCounterValuesW3SVCW3WPV8] perfDataObjectW3SVCW3WP []perfDataCounterValuesW3SVCW3WP perfDataObjectW3SVCW3WPV8 []perfDataCounterValuesW3SVCW3WPV8 @@ -102,7 +103,7 @@ type perfDataCounterValuesW3SVCW3WP struct { W3SVCW3WPFilesCachedTotal float64 `perfdata:"Total Files Cached"` W3SVCW3WPFilesFlushedTotal float64 `perfdata:"Total Flushed Files"` - W3SVCW3WPURICacheFlushesTotal float64 `perfdata:"Total Flushed URIs"` + W3SVCW3WPURICacheFlushesTotal float64 `perfdata:"URI Cache Flushes"` W3SVCW3WPURICacheHitsTotal float64 `perfdata:"URI Cache Hits"` W3SVCW3WPURICacheMissesTotal float64 `perfdata:"URI Cache Misses"` W3SVCW3WPURIsCached float64 `perfdata:"Current URIs Cached"` @@ -163,6 +164,12 @@ func (c *Collector) buildW3SVCW3WP() error { } } + c.buildW3SVCW3WPDescriptors() + + return nil +} + +func (c *Collector) buildW3SVCW3WPDescriptors() { // W3SVC_W3WP c.w3SVCW3WPThreads = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "worker_threads"), @@ -387,8 +394,6 @@ func (c *Collector) buildW3SVCW3WP() error { []string{"app", "pid"}, nil, ) - - return nil } func (c *Collector) collectW3SVCW3WP(ch chan<- prometheus.Metric) error { @@ -720,7 +725,7 @@ func (c *Collector) collectW3SVCW3WPv7(ch chan<- prometheus.Metric) error { ch <- prometheus.MustNewConstMetric( c.w3SVCW3WPOutputCacheActiveFlushedItems, - prometheus.CounterValue, + prometheus.GaugeValue, data.W3SVCW3WPOutputCacheActiveFlushedItems, name, pid, @@ -728,7 +733,7 @@ func (c *Collector) collectW3SVCW3WPv7(ch chan<- prometheus.Metric) error { ch <- prometheus.MustNewConstMetric( c.w3SVCW3WPOutputCacheItems, - prometheus.CounterValue, + prometheus.GaugeValue, data.W3SVCW3WPOutputCacheItems, name, pid, @@ -736,7 +741,7 @@ func (c *Collector) collectW3SVCW3WPv7(ch chan<- prometheus.Metric) error { ch <- prometheus.MustNewConstMetric( c.w3SVCW3WPOutputCacheMemoryUsage, - prometheus.CounterValue, + prometheus.GaugeValue, data.W3SVCW3WPOutputCacheMemoryUsage, name, pid, diff --git a/internal/collector/iis/iis_web_service_cache.go b/internal/collector/iis/iis_web_service_cache.go index be09b475..c9f9a265 100644 --- a/internal/collector/iis/iis_web_service_cache.go +++ b/internal/collector/iis/iis_web_service_cache.go @@ -21,12 +21,13 @@ import ( "fmt" "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" "github.com/prometheus/client_golang/prometheus" ) type collectorWebServiceCache struct { - serviceCachePerfDataCollector *pdh.Collector[perfDataCounterServiceCache] + serviceCachePerfDataCollector pdhtypes.Collector[perfDataCounterServiceCache] perfDataObjectServiceCache []perfDataCounterServiceCache serviceCacheActiveFlushedEntries *prometheus.Desc @@ -73,8 +74,8 @@ type perfDataCounterServiceCache struct { ServiceCacheFilesCached float64 `perfdata:"Current Files Cached"` ServiceCacheFilesCachedTotal float64 `perfdata:"Total Files Cached"` ServiceCacheFilesFlushedTotal float64 `perfdata:"Total Flushed Files"` - ServiceCacheURICacheFlushesTotal float64 `perfdata:"Total Flushed URIs"` - ServiceCacheURICacheFlushesTotalKernel float64 `perfdata:"Total Flushed URIs"` + ServiceCacheURICacheFlushesTotal float64 `perfdata:"URI Cache Flushes"` + ServiceCacheURICacheFlushesTotalKernel float64 `perfdata:"Kernel: URI Cache Flushes"` ServiceCacheURIsFlushedTotalKernel float64 `perfdata:"Kernel: Total Flushed URIs"` ServiceCacheURICacheHitsTotal float64 `perfdata:"URI Cache Hits"` ServiceCacheURICacheHitsTotalKernel float64 `perfdata:"Kernel: URI Cache Hits"` @@ -83,7 +84,7 @@ type perfDataCounterServiceCache struct { ServiceCacheURIsCached float64 `perfdata:"Current URIs Cached"` ServiceCacheURIsCachedKernel float64 `perfdata:"Kernel: Current URIs Cached"` ServiceCacheURIsCachedTotal float64 `perfdata:"Total URIs Cached"` - ServiceCacheURIsCachedTotalKernel float64 `perfdata:"Total URIs Cached"` + ServiceCacheURIsCachedTotalKernel float64 `perfdata:"Kernel: Total URIs Cached"` ServiceCacheURIsFlushedTotal float64 `perfdata:"Total Flushed URIs"` ServiceCacheMetaDataCacheHits float64 `perfdata:"Metadata Cache Hits"` ServiceCacheMetaDataCacheMisses float64 `perfdata:"Metadata Cache Misses"` @@ -108,6 +109,12 @@ func (c *Collector) buildWebServiceCache() error { return fmt.Errorf("failed to create Web Service Cache collector: %w", err) } + c.buildWebServiceCacheDescriptors() + + return nil +} + +func (c *Collector) buildWebServiceCacheDescriptors() { // Web Service Cache c.serviceCacheActiveFlushedEntries = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "server_cache_active_flushed_entries"), @@ -277,8 +284,6 @@ func (c *Collector) buildWebServiceCache() error { nil, nil, ) - - return nil } func (c *Collector) collectWebServiceCache(ch chan<- prometheus.Metric) error { @@ -447,7 +452,7 @@ func (c *Collector) collectWebServiceCache(ch chan<- prometheus.Metric) error { ch <- prometheus.MustNewConstMetric( c.serviceCacheMetadataCacheHitsTotal, prometheus.CounterValue, - 0, // data.ServiceCacheMetadataCacheHitsTotal, + data.ServiceCacheMetaDataCacheHits, ) ch <- prometheus.MustNewConstMetric( @@ -464,19 +469,19 @@ func (c *Collector) collectWebServiceCache(ch chan<- prometheus.Metric) error { ch <- prometheus.MustNewConstMetric( c.serviceCacheOutputCacheActiveFlushedItems, - prometheus.CounterValue, + prometheus.GaugeValue, data.ServiceCacheOutputCacheActiveFlushedItems, ) ch <- prometheus.MustNewConstMetric( c.serviceCacheOutputCacheItems, - prometheus.CounterValue, + prometheus.GaugeValue, data.ServiceCacheOutputCacheItems, ) ch <- prometheus.MustNewConstMetric( c.serviceCacheOutputCacheMemoryUsage, - prometheus.CounterValue, + prometheus.GaugeValue, data.ServiceCacheOutputCacheMemoryUsage, )