logical_disk: deprecate cumulative avg_*_requests_queued gauges (#2563)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
This commit is contained in:
Jan-Otto Kröpke
2026-10-09 08:56:47 +02:00
committed by GitHub
co-authored by Claude Opus 5.5
parent ee4c8ea0fe
commit c7fa244d0e
5 changed files with 89 additions and 22 deletions
@@ -232,14 +232,16 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
c.avgReadQueue = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "avg_read_requests_queued"),
"Average number of read requests that were queued for the selected disk during the sample interval (LogicalDisk.AvgDiskReadQueueLength)",
"DEPRECATED: use rate(windows_logical_disk_read_seconds_total). "+
"Cumulative read queue length in seconds, identical to windows_logical_disk_read_seconds_total (LogicalDisk.AvgDiskReadQueueLength)",
[]string{"volume"},
nil,
)
c.avgWriteQueue = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "avg_write_requests_queued"),
"Average number of write requests that were queued for the selected disk during the sample interval (LogicalDisk.AvgDiskWriteQueueLength)",
"DEPRECATED: use rate(windows_logical_disk_write_seconds_total). "+
"Cumulative write queue length in seconds, identical to windows_logical_disk_write_seconds_total (LogicalDisk.AvgDiskWriteQueueLength)",
[]string{"volume"},
nil,
)
@@ -399,6 +401,10 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error
data.Name,
)
// The raw value of a PERF_COUNTER_100NS_QUEUELEN_TYPE counter is the queue length
// integrated over time in 100ns ticks, not an average. It shares its source with
// "% Disk Read/Write Time". Kept as gauge for compatibility: as a counter,
// OpenMetrics exposition would rename the series to *_total.
ch <- prometheus.MustNewConstMetric(
c.avgReadQueue,
prometheus.GaugeValue,
@@ -46,6 +46,31 @@ func TestCollector(t *testing.T) {
})
}
// TestCollectorAvgQueueIsCumulative checks that the raw "Avg. Disk Read/Write Queue Length"
// values are not averages, but the same cumulative values as "% Disk Read/Write Time".
// This is why the avg_*_requests_queued metrics are kept only for compatibility.
func TestCollectorAvgQueueIsCumulative(t *testing.T) {
metrics := testutils.TestCollector(t, logical_disk.New, &logical_disk.Config{
CollectorsEnabled: logical_disk.ConfigDefaults.CollectorsEnabled,
VolumeInclude: types.RegExpAny,
})
for deprecated, replacement := range map[string]string{
"windows_logical_disk_avg_read_requests_queued": "windows_logical_disk_read_seconds_total",
"windows_logical_disk_avg_write_requests_queued": "windows_logical_disk_write_seconds_total",
} {
want := testutils.MetricValuesByLabel(metrics, replacement, "volume")
values := testutils.MetricValuesByLabel(metrics, deprecated, "volume")
require.NotEmpty(t, values, "%s was not emitted", deprecated)
for volume, got := range values {
require.Contains(t, want, volume)
require.InDelta(t, want[volume], got, 1e-6, "%s{volume=%q}", deprecated, volume)
}
}
}
func TestCollectorBitlocker(t *testing.T) {
metrics := testutils.TestCollector(t, logical_disk.New, &logical_disk.Config{
CollectorsEnabled: []string{"metrics", "bitlocker_status"},
+22
View File
@@ -256,6 +256,28 @@ func RequireFixtureMetric(t *testing.T, families map[string]*dto.MetricFamily, c
return nil
}
// MetricValuesByLabel returns the gauge or counter values of metricName,
// keyed by the value of the label labelName.
func MetricValuesByLabel(families map[string]*dto.MetricFamily, metricName, labelName string) map[string]float64 {
values := make(map[string]float64)
for _, metric := range families[metricName].GetMetric() {
for _, label := range metric.GetLabel() {
if label.GetName() != labelName {
continue
}
if metric.GetCounter() != nil {
values[label.GetValue()] = metric.GetCounter().GetValue()
} else {
values[label.GetValue()] = metric.GetGauge().GetValue()
}
}
}
return values
}
func noDataOnly(err error) bool {
if joined, ok := err.(interface{ Unwrap() []error }); ok {
for _, cause := range joined.Unwrap() {