diff --git a/UPGRADE.md b/UPGRADE.md index 4f693dbf..240c65a1 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -234,6 +234,8 @@ Removed: | Metric | Reason | |---------------------------------------------------|------------------------------------------------------------------------| | `windows_memory_free_system_page_table_entries` | Saturates near 2^32 on 64-bit Windows, where system PTEs are not a scarce resource | +| `windows_logical_disk_avg_read_requests_queued` | Running sum that only grew, never an average queue length. Use `rate(windows_logical_disk_read_seconds_total[5m])` | +| `windows_logical_disk_avg_write_requests_queued` | Running sum that only grew, never an average queue length. Use `rate(windows_logical_disk_write_seconds_total[5m])` | Deprecated. These are still exported in 0.32 and will be removed in a later release: @@ -245,12 +247,10 @@ Deprecated. These are still exported in 0.32 and will be removed in a later rele | `windows_hyperv_virtual_storage_device_lower_latency_seconds` | `windows_hyperv_virtual_storage_device_lower_io_latency_seconds_total`, used the same way | | `windows_hyperv_virtual_storage_device_queue_length` | `rate(windows_hyperv_virtual_storage_device_io_latency_seconds_total[5m])` | | `windows_hyperv_virtual_storage_device_lower_queue_length` | `rate(windows_hyperv_virtual_storage_device_lower_io_latency_seconds_total[5m])` | -| `windows_logical_disk_avg_read_requests_queued` | `rate(windows_logical_disk_read_seconds_total[5m])` | -| `windows_logical_disk_avg_write_requests_queued` | `rate(windows_logical_disk_write_seconds_total[5m])` | | `windows_cache_data_map_hits_percent` | `windows_cache_data_map_hits_total` | | `windows_scheduled_task_last_result` | `windows_scheduled_task_last_result_status` | -The deprecated Hyper-V storage latency and queue gauges and the logical disk `avg_*_requests_queued` gauges never held current values. +The deprecated Hyper-V storage latency and queue gauges and the removed logical disk `avg_*_requests_queued` gauges never held current values. They exported a running sum that only grows, so graphs of them rise steadily. The replacements give the actual average latency and queue length. Changed type, same name: diff --git a/docs/collector.logical_disk.md b/docs/collector.logical_disk.md index 82266c47..6b699eca 100644 --- a/docs/collector.logical_disk.md +++ b/docs/collector.logical_disk.md @@ -29,8 +29,6 @@ Comma-separated list of collectors to use. Available collectors: metrics, bitloc |--------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------|---------|-------------------------------------------------------------------| | `windows_logical_disk_info` | A metric with a constant '1' value labeled with logical disk information | gauge | `disk`,`type`,`volume`,`volume_name`,`filesystem`,`serial_number` | | `windows_logical_disk_requests_queued` | Number of requests outstanding on the disk at the time the performance data is collected | gauge | `volume` | -| `windows_logical_disk_avg_read_requests_queued` | **Deprecated:** use `rate(windows_logical_disk_read_seconds_total)`. Cumulative read queue length in seconds, see below | gauge | `volume` | -| `windows_logical_disk_avg_write_requests_queued` | **Deprecated:** use `rate(windows_logical_disk_write_seconds_total)`. Cumulative write queue length in seconds, see below | gauge | `volume` | | `windows_logical_disk_read_bytes_total` | Rate at which bytes are transferred from the disk during read operations | counter | `volume` | | `windows_logical_disk_reads_total` | Rate of read operations on the disk | counter | `volume` | | `windows_logical_disk_write_bytes_total` | Rate at which bytes are transferred to the disk during write operations | counter | `volume` | @@ -47,14 +45,14 @@ Comma-separated list of collectors to use. Available collectors: metrics, bitloc | `windows_logical_disk_readonly` | Whether the logical disk is read-only | gauge | `volume` | | `windows_logical_disk_bitlocker_status` | BitLocker status for the logical disk | gauge | `volume`,`status` | -### Deprecated average queue length metrics +### Average queue length `Avg. Disk Read Queue Length` and `Avg. Disk Write Queue Length` are averages that Windows computes from two samples. -windows_exporter reads their raw values, which only grow: the queue length summed over time, in seconds. +Their raw values only grow: the queue length summed over time, in seconds. These raw values are the same as the ones of `% Disk Read Time` and `% Disk Write Time`, which are exposed as `windows_logical_disk_read_seconds_total` and `windows_logical_disk_write_seconds_total`. -`windows_logical_disk_avg_read_requests_queued` and `windows_logical_disk_avg_write_requests_queued` keep exposing -the raw values as gauges for compatibility. They are deprecated and will be removed in a future release. +The former `windows_logical_disk_avg_read_requests_queued` and `windows_logical_disk_avg_write_requests_queued` +gauges exposed these raw values and were removed in 0.32. Use the rate of the `*_seconds_total` counters for the average queue length instead: ``` rate(windows_logical_disk_read_seconds_total[5m]) diff --git a/internal/collector/logical_disk/AGENTS.md b/internal/collector/logical_disk/AGENTS.md index 21f6c1c4..fa7857bf 100644 --- a/internal/collector/logical_disk/AGENTS.md +++ b/internal/collector/logical_disk/AGENTS.md @@ -21,7 +21,9 @@ multi-instance. These notes were recorded on a Windows Server 2025 cumulative busy time in 100 ns ticks. `internal/pdh` converts the `PERF_PRECISION_100NS_TIMER` counters to seconds. The queue length and `PERF_AVERAGE_TIMER` values arrive in ticks and need the 1e-7 factor; the - counter time base is 10 MHz here. + counter time base is 10 MHz here. The queue length counters duplicate the + busy time, so the collector no longer reads them; the average queue length is + `rate(windows_logical_disk_{read,write}_seconds_total[5m])`. - `Avg. Disk sec/Read`, `/Write` and `/Transfer` are `PERF_AVERAGE_TIMER`. Their base is the operation count and equals `Disk Reads/sec` (3073), `Disk Writes/sec` (1698) and their sum (4771). @@ -50,11 +52,9 @@ Counters the collector reads: | `% Disk Write Time` | `PERF_PRECISION_100NS_TIMER` | 11319205 | | | `% Free Space` | `PERF_RAW_FRACTION` | 49907 | 129254 | | `% Idle Time` | `PERF_PRECISION_100NS_TIMER` | 115960642 | | -| `Avg. Disk Read Queue Length` | `PERF_COUNTER_100NS_QUEUELEN_TYPE` | 9858832 | | | `Avg. Disk sec/Read` | `PERF_AVERAGE_TIMER` | 9858832 | 3073 | | `Avg. Disk sec/Transfer` | `PERF_AVERAGE_TIMER` | 21178037 | 4771 | | `Avg. Disk sec/Write` | `PERF_AVERAGE_TIMER` | 11319205 | 1698 | -| `Avg. Disk Write Queue Length` | `PERF_COUNTER_100NS_QUEUELEN_TYPE` | 11319205 | | | `Current Disk Queue Length` | `PERF_COUNTER_RAWCOUNT` | 0 | | | `Disk Read Bytes/sec` | `PERF_COUNTER_BULK_COUNT` | 131518976 | | | `Disk Reads/sec` | `PERF_COUNTER_COUNTER` | 3073 | | @@ -66,7 +66,7 @@ Counters the collector reads: Not read by the collector: - `PERF_AVERAGE_BULK`: `Avg. Disk Bytes/Read`, `Avg. Disk Bytes/Transfer`, `Avg. Disk Bytes/Write` -- `PERF_COUNTER_100NS_QUEUELEN_TYPE`: `Avg. Disk Queue Length` +- `PERF_COUNTER_100NS_QUEUELEN_TYPE`: `Avg. Disk Queue Length`, `Avg. Disk Read Queue Length` (raw 9858832), `Avg. Disk Write Queue Length` (raw 11319205) - `PERF_COUNTER_BULK_COUNT`: `Disk Bytes/sec` - `PERF_COUNTER_COUNTER`: `Disk Transfers/sec` - `PERF_PRECISION_100NS_TIMER`: `% Disk Time` diff --git a/internal/collector/logical_disk/logical_disk.go b/internal/collector/logical_disk/logical_disk.go index d58bc879..86c1cff8 100644 --- a/internal/collector/logical_disk/logical_disk.go +++ b/internal/collector/logical_disk/logical_disk.go @@ -93,8 +93,6 @@ type Collector struct { // lastMountErr is the last logged error of getAllMountedVolumes. lastMountErr string - avgReadQueue *prometheus.Desc - avgWriteQueue *prometheus.Desc freeSpace *prometheus.Desc idleTime *prometheus.Desc information *prometheus.Desc @@ -230,22 +228,6 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { nil, ) - c.avgReadQueue = prometheus.NewDesc( - prometheus.BuildFQName(types.Namespace, Name, "avg_read_requests_queued"), - "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"), - "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, - ) - c.readBytesTotal = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "read_bytes_total"), "The number of bytes transferred from the disk during read operations (LogicalDisk.DiskReadBytesPerSec)", @@ -421,24 +403,6 @@ 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, - data.AvgDiskReadQueueLength*pdh.TicksToSecondScaleFactor, - data.Name, - ) - - ch <- prometheus.MustNewConstMetric( - c.avgWriteQueue, - prometheus.GaugeValue, - data.AvgDiskWriteQueueLength*pdh.TicksToSecondScaleFactor, - data.Name, - ) - ch <- prometheus.MustNewConstMetric( c.readBytesTotal, prometheus.CounterValue, diff --git a/internal/collector/logical_disk/logical_disk_test.go b/internal/collector/logical_disk/logical_disk_test.go index 34b64c60..153626b5 100644 --- a/internal/collector/logical_disk/logical_disk_test.go +++ b/internal/collector/logical_disk/logical_disk_test.go @@ -46,28 +46,21 @@ 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) { +// TestCollectorAvgQueueRemoved checks that the removed avg_*_requests_queued gauges are +// gone while their replacements are still emitted. The raw "Avg. Disk Read/Write Queue +// Length" values were the same cumulative values as "% Disk Read/Write Time". +func TestCollectorAvgQueueRemoved(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{ + for removed, 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) - } + require.Empty(t, testutils.MetricValuesByLabel(metrics, removed, "volume"), "%s is still emitted", removed) + require.NotEmpty(t, testutils.MetricValuesByLabel(metrics, replacement, "volume"), "%s was not emitted", replacement) } } diff --git a/internal/collector/logical_disk/types.go b/internal/collector/logical_disk/types.go index ce065579..79267ebf 100644 --- a/internal/collector/logical_disk/types.go +++ b/internal/collector/logical_disk/types.go @@ -20,20 +20,18 @@ package logical_disk type perfDataCounterValues struct { Name string - AvgDiskReadQueueLength float64 `perfdata:"Avg. Disk Read Queue Length"` - AvgDiskSecPerRead float64 `perfdata:"Avg. Disk sec/Read"` - AvgDiskSecPerTransfer float64 `perfdata:"Avg. Disk sec/Transfer"` - AvgDiskSecPerWrite float64 `perfdata:"Avg. Disk sec/Write"` - AvgDiskWriteQueueLength float64 `perfdata:"Avg. Disk Write Queue Length"` - CurrentDiskQueueLength float64 `perfdata:"Current Disk Queue Length"` - FreeSpace float64 `perfdata:"Free Megabytes"` - DiskReadBytesPerSec float64 `perfdata:"Disk Read Bytes/sec"` - DiskReadsPerSec float64 `perfdata:"Disk Reads/sec"` - DiskWriteBytesPerSec float64 `perfdata:"Disk Write Bytes/sec"` - DiskWritesPerSec float64 `perfdata:"Disk Writes/sec"` - PercentDiskReadTime float64 `perfdata:"% Disk Read Time"` - PercentDiskWriteTime float64 `perfdata:"% Disk Write Time"` - PercentFreeSpace float64 `perfdata:"% Free Space,secondvalue"` - PercentIdleTime float64 `perfdata:"% Idle Time"` - SplitIOPerSec float64 `perfdata:"Split IO/Sec"` + AvgDiskSecPerRead float64 `perfdata:"Avg. Disk sec/Read"` + AvgDiskSecPerTransfer float64 `perfdata:"Avg. Disk sec/Transfer"` + AvgDiskSecPerWrite float64 `perfdata:"Avg. Disk sec/Write"` + CurrentDiskQueueLength float64 `perfdata:"Current Disk Queue Length"` + FreeSpace float64 `perfdata:"Free Megabytes"` + DiskReadBytesPerSec float64 `perfdata:"Disk Read Bytes/sec"` + DiskReadsPerSec float64 `perfdata:"Disk Reads/sec"` + DiskWriteBytesPerSec float64 `perfdata:"Disk Write Bytes/sec"` + DiskWritesPerSec float64 `perfdata:"Disk Writes/sec"` + PercentDiskReadTime float64 `perfdata:"% Disk Read Time"` + PercentDiskWriteTime float64 `perfdata:"% Disk Write Time"` + PercentFreeSpace float64 `perfdata:"% Free Space,secondvalue"` + PercentIdleTime float64 `perfdata:"% Idle Time"` + SplitIOPerSec float64 `perfdata:"Split IO/Sec"` } diff --git a/tools/e2e-output.txt b/tools/e2e-output.txt index 44836db2..89d025c8 100644 --- a/tools/e2e-output.txt +++ b/tools/e2e-output.txt @@ -147,10 +147,6 @@ windows_exporter_collector_timeout{collector="time"} 0 windows_exporter_collector_timeout{collector="udp"} 0 # HELP windows_exporter_scrape_duration_seconds windows_exporter: Total scrape duration. # TYPE windows_exporter_scrape_duration_seconds gauge -# HELP windows_logical_disk_avg_read_requests_queued 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) -# TYPE windows_logical_disk_avg_read_requests_queued gauge -# HELP windows_logical_disk_avg_write_requests_queued 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) -# TYPE windows_logical_disk_avg_write_requests_queued gauge # HELP windows_logical_disk_free_bytes Free space in bytes, updates every 10-15 min (LogicalDisk.PercentFreeSpace) # TYPE windows_logical_disk_free_bytes gauge # HELP windows_logical_disk_idle_seconds_total Seconds that the disk was idle (LogicalDisk.PercentIdleTime)