iis: correct cache counter mappings and occupancy types (#2594)

Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
This commit is contained in:
Jan-Otto Kröpke
2026-10-09 10:47:50 +02:00
committed by GitHub
parent dda8962e1d
commit 7391ece210
3 changed files with 162 additions and 17 deletions
@@ -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() {}
+12 -7
View File
@@ -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,
+15 -10
View File
@@ -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,
)