From 3555e9c4bcf689e16d77b028c472c75172bf3360 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Fri, 16 Oct 2026 20:41:42 +0200 Subject: [PATCH] logical_disk: remove the *_latency_seconds_total counters (#2763) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan-Otto Kröpke --- docs/collector.logical_disk.md | 15 +++- docs/upgrade/0.32.md | 5 +- docs/upgrade/0.32.prom | 6 ++ internal/collector/logical_disk/AGENTS.md | 10 +-- .../collector/logical_disk/logical_disk.go | 71 ++++--------------- .../logical_disk/logical_disk_test.go | 16 +++-- internal/collector/logical_disk/types.go | 3 - internal/metriccontract/metrics_test.go | 9 ++- tools/e2e-output.txt | 6 -- 9 files changed, 57 insertions(+), 84 deletions(-) diff --git a/docs/collector.logical_disk.md b/docs/collector.logical_disk.md index 6b699eca..ca109ca2 100644 --- a/docs/collector.logical_disk.md +++ b/docs/collector.logical_disk.md @@ -39,9 +39,6 @@ Comma-separated list of collectors to use. Available collectors: metrics, bitloc | `windows_logical_disk_size_bytes` | Total size of the disk in bytes | gauge | `volume` | | `windows_logical_disk_idle_seconds_total` | Seconds the disk was idle (not servicing read/write requests) | counter | `volume` | | `windows_logical_disk_split_ios_total` | Number of I/Os to the disk split into multiple I/Os | counter | `volume` | -| `windows_logical_disk_read_latency_seconds_total` | Shows the average time, in seconds, of a read operation from the disk | counter | `volume` | -| `windows_logical_disk_write_latency_seconds_total` | Shows the average time, in seconds, of a write operation to the disk | counter | `volume` | -| `windows_logical_disk_read_write_latency_seconds_total` | Shows the time, in seconds, of the average disk transfer | counter | `volume` | | `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` | @@ -59,6 +56,18 @@ rate(windows_logical_disk_read_seconds_total[5m]) rate(windows_logical_disk_write_seconds_total[5m]) ``` +### Average latency +`Avg. Disk sec/Read`, `Avg. Disk sec/Write` and `Avg. Disk sec/Transfer` divide the busy time by the number of operations. +Their raw time values are the same as the ones of `% Disk Read Time` and `% Disk Write Time`, so the exporter only exposes +`windows_logical_disk_read_seconds_total` and `windows_logical_disk_write_seconds_total`. +The former `windows_logical_disk_read_latency_seconds_total`, `windows_logical_disk_write_latency_seconds_total` and +`windows_logical_disk_read_write_latency_seconds_total` counters held the same busy time, not a latency, and were removed in 0.32. +Divide the busy time by the number of operations for the average latency: +``` +rate(windows_logical_disk_read_seconds_total[5m]) / rate(windows_logical_disk_reads_total[5m]) +rate(windows_logical_disk_write_seconds_total[5m]) / rate(windows_logical_disk_writes_total[5m]) +``` + ### Size metrics The `free_bytes` and `size_bytes` metrics are read from the volume on every scrape. Both are the free and total bytes of the whole volume, regardless of NTFS disk quotas of the account running windows_exporter. diff --git a/docs/upgrade/0.32.md b/docs/upgrade/0.32.md index efd0d27e..ffa6e76e 100644 --- a/docs/upgrade/0.32.md +++ b/docs/upgrade/0.32.md @@ -530,7 +530,7 @@ Multiply the new ratios by 100 to get the old values; alert on `windows_dfsr_vol These metrics keep their values. The name changed to add the unit, to describe the value or, for counters, to put the unit before the `_total` suffix. If Prometheus scrapes with OpenMetrics, the stored names of these counters change as well.
-Show the table (95 metrics) +Show the table (97 metrics) | 0.31 | 0.32 | Note | |-------------------------------------------------------------------------|---------------------------------------------------------------------------------|------| @@ -601,6 +601,8 @@ These metrics keep their values. The name changed to add the unit, to describe t | `windows_iis_total_worker_process_shutdown_failures` | `windows_iis_worker_process_shutdown_failures_total` | Same value | | `windows_iis_total_worker_process_startup_failures` | `windows_iis_worker_process_startup_failures_total` | Same value | | `windows_iis_total_worker_processes_created` | `windows_iis_worker_processes_created_total` | Same value | +| `windows_logical_disk_read_latency_seconds_total` | `windows_logical_disk_read_seconds_total` | Same value | +| `windows_logical_disk_write_latency_seconds_total` | `windows_logical_disk_write_seconds_total` | Same value | | `windows_mscluster_cluster_add_evict_delay` | `windows_mscluster_cluster_add_evict_delay_seconds` | Same value | | `windows_mscluster_cluster_clus_svc_hang_timeout` | `windows_mscluster_cluster_clus_svc_hang_timeout_seconds` | Same value | | `windows_mscluster_cluster_clus_svc_regroup_opening_timeout` | `windows_mscluster_cluster_clus_svc_regroup_opening_timeout_seconds` | Same value | @@ -813,6 +815,7 @@ If Prometheus scrapes with OpenMetrics, it already stored exactly these names, b | `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])` | +| `windows_logical_disk_read_write_latency_seconds_total` | Sum of the read and write busy time, never a latency. Use `rate(windows_logical_disk_read_seconds_total[5m]) + rate(windows_logical_disk_write_seconds_total[5m])` | | `windows_cache_data_map_hits_percent` | Deprecated in earlier 0.32 builds. It was the raw hit count, not a percentage. Use `rate(windows_cache_data_map_hits_total[5m]) / rate(windows_cache_data_maps_total[5m])` | | `windows_mscluster_cluster_quorum_log_file_size`, `windows_mscluster_cluster_resource_dll_deadlock_period` | Obsolete cluster properties without a meaning on supported Windows versions | | `windows_hyperv_hypervisor_virtual_processor_time_total` | Duplicate. Use `windows_hyperv_hypervisor_virtual_processor_mode_time_seconds_total` | diff --git a/docs/upgrade/0.32.prom b/docs/upgrade/0.32.prom index 3db93dc1..b1957093 100644 --- a/docs/upgrade/0.32.prom +++ b/docs/upgrade/0.32.prom @@ -386,6 +386,12 @@ groups: expr: windows_iis_server_file_cache_max_memory_bytes - record: windows_iis_worker_file_cache_max_memory_bytes_total expr: windows_iis_worker_file_cache_max_memory_bytes + - name: windows_exporter-0.32-logical_disk + rules: + - record: windows_logical_disk_read_latency_seconds_total + expr: windows_logical_disk_read_seconds_total + - record: windows_logical_disk_write_latency_seconds_total + expr: windows_logical_disk_write_seconds_total - name: windows_exporter-0.32-memory rules: - record: windows_memory_commit_limit diff --git a/internal/collector/logical_disk/AGENTS.md b/internal/collector/logical_disk/AGENTS.md index fa7857bf..bde1002c 100644 --- a/internal/collector/logical_disk/AGENTS.md +++ b/internal/collector/logical_disk/AGENTS.md @@ -26,7 +26,11 @@ multi-instance. These notes were recorded on a Windows Server 2025 `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). + `Disk Writes/sec` (1698) and their sum (4771). Their raw values duplicate the + busy time, so the collector no longer reads them; the former + `*_latency_seconds_total` counters were the busy time, not a latency. The + average latency is `rate(windows_logical_disk_read_seconds_total[5m]) / + rate(windows_logical_disk_reads_total[5m])`. - `% Idle Time` is a cumulative 100 ns timer as well, not a percentage. On `C:` it was 115960642 ticks, about 11.6 seconds. - `Disk Read Bytes/sec` and `Disk Write Bytes/sec` (`PERF_COUNTER_BULK_COUNT`) @@ -52,9 +56,6 @@ 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 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 | | `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,6 +67,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_AVERAGE_TIMER`: `Avg. Disk sec/Read` (raw 9858832, base 3073), `Avg. Disk sec/Transfer` (raw 21178037, base 4771), `Avg. Disk sec/Write` (raw 11319205, base 1698) - `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` diff --git a/internal/collector/logical_disk/logical_disk.go b/internal/collector/logical_disk/logical_disk.go index 755d96d1..9fd3509b 100644 --- a/internal/collector/logical_disk/logical_disk.go +++ b/internal/collector/logical_disk/logical_disk.go @@ -94,22 +94,19 @@ type Collector struct { // lastMountErr is the last logged error of getAllMountedVolumes. lastMountErr string - freeSpace *prometheus.Desc - idleTime *prometheus.Desc - information *prometheus.Desc - readBytesTotal *prometheus.Desc - readLatency *prometheus.Desc - readOnly *prometheus.Desc - readsTotal *prometheus.Desc - readTime *prometheus.Desc - readWriteLatency *prometheus.Desc - requestsQueued *prometheus.Desc - splitIOs *prometheus.Desc - totalSpace *prometheus.Desc - writeBytesTotal *prometheus.Desc - writeLatency *prometheus.Desc - writesTotal *prometheus.Desc - writeTime *prometheus.Desc + freeSpace *prometheus.Desc + idleTime *prometheus.Desc + information *prometheus.Desc + readBytesTotal *prometheus.Desc + readOnly *prometheus.Desc + readsTotal *prometheus.Desc + readTime *prometheus.Desc + requestsQueued *prometheus.Desc + splitIOs *prometheus.Desc + totalSpace *prometheus.Desc + writeBytesTotal *prometheus.Desc + writesTotal *prometheus.Desc + writeTime *prometheus.Desc bitlockerStatus *prometheus.Desc } @@ -289,27 +286,6 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { nil, ) - c.readLatency = prometheus.NewDesc( - prometheus.BuildFQName(types.Namespace, Name, "read_latency_seconds_total"), - "Shows the average time, in seconds, of a read operation from the disk (LogicalDisk.AvgDiskSecPerRead)", - []string{"volume"}, - nil, - ) - - c.writeLatency = prometheus.NewDesc( - prometheus.BuildFQName(types.Namespace, Name, "write_latency_seconds_total"), - "Shows the average time, in seconds, of a write operation to the disk (LogicalDisk.AvgDiskSecPerWrite)", - []string{"volume"}, - nil, - ) - - c.readWriteLatency = prometheus.NewDesc( - prometheus.BuildFQName(types.Namespace, Name, "read_write_latency_seconds_total"), - "Shows the time, in seconds, of the average disk transfer (LogicalDisk.AvgDiskSecPerTransfer)", - []string{"volume"}, - nil, - ) - c.bitlockerStatus = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "bitlocker_status"), "BitLocker status for the logical disk", @@ -463,27 +439,6 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error data.SplitIOPerSec, data.Name, ) - - ch <- prometheus.MustNewConstMetric( - c.readLatency, - prometheus.CounterValue, - data.AvgDiskSecPerRead*pdh.TicksToSecondScaleFactor, - data.Name, - ) - - ch <- prometheus.MustNewConstMetric( - c.writeLatency, - prometheus.CounterValue, - data.AvgDiskSecPerWrite*pdh.TicksToSecondScaleFactor, - data.Name, - ) - - ch <- prometheus.MustNewConstMetric( - c.readWriteLatency, - prometheus.CounterValue, - data.AvgDiskSecPerTransfer*pdh.TicksToSecondScaleFactor, - data.Name, - ) } if c.bitlockerEnabled { diff --git a/internal/collector/logical_disk/logical_disk_test.go b/internal/collector/logical_disk/logical_disk_test.go index ae160796..347357e5 100644 --- a/internal/collector/logical_disk/logical_disk_test.go +++ b/internal/collector/logical_disk/logical_disk_test.go @@ -40,18 +40,22 @@ func TestCollector(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) { +// TestCollectorDuplicatesRemoved checks that the removed avg_*_requests_queued gauges and +// *_latency_seconds_total counters are gone while their replacements are still emitted. +// The raw "Avg. Disk Read/Write Queue Length" and "Avg. Disk sec/Read/Write/Transfer" +// values were the same cumulative values as "% Disk Read/Write Time". +func TestCollectorDuplicatesRemoved(t *testing.T) { metrics := testutils.TestCollector(t, logical_disk.New, &logical_disk.Config{ CollectorsEnabled: logical_disk.ConfigDefaults.CollectorsEnabled, VolumeInclude: types.RegExpAny, }) 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", + "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", + "windows_logical_disk_read_latency_seconds_total": "windows_logical_disk_read_seconds_total", + "windows_logical_disk_write_latency_seconds_total": "windows_logical_disk_write_seconds_total", + "windows_logical_disk_read_write_latency_seconds_total": "windows_logical_disk_write_seconds_total", } { 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 79267ebf..09aef135 100644 --- a/internal/collector/logical_disk/types.go +++ b/internal/collector/logical_disk/types.go @@ -20,9 +20,6 @@ package logical_disk type perfDataCounterValues struct { Name string - 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"` diff --git a/internal/metriccontract/metrics_test.go b/internal/metriccontract/metrics_test.go index 84802187..1530706e 100644 --- a/internal/metriccontract/metrics_test.go +++ b/internal/metriccontract/metrics_test.go @@ -86,9 +86,12 @@ var dynamicPrefixes = []string{ // //nolint:gochecknoglobals var historicalReferences = map[string]string{ - "windows_logical_disk_avg_read_requests_queued": "docs/collector.logical_disk.md: removed in 0.32, use the read/write *_seconds_total rate", - "windows_logical_disk_avg_write_requests_queued": "docs/collector.logical_disk.md: removed in 0.32, use the read/write *_seconds_total rate", - "windows_net_route_info": "docs/collector.net.md: documented but never emitted, removed from the docs", + "windows_logical_disk_avg_read_requests_queued": "docs/collector.logical_disk.md: removed in 0.32, use the read/write *_seconds_total rate", + "windows_logical_disk_avg_write_requests_queued": "docs/collector.logical_disk.md: removed in 0.32, use the read/write *_seconds_total rate", + "windows_logical_disk_read_latency_seconds_total": "docs/collector.logical_disk.md: removed in 0.32, duplicated read_seconds_total", + "windows_logical_disk_read_write_latency_seconds_total": "docs/collector.logical_disk.md: removed in 0.32, the sum of the read and write busy time", + "windows_logical_disk_write_latency_seconds_total": "docs/collector.logical_disk.md: removed in 0.32, duplicated write_seconds_total", + "windows_net_route_info": "docs/collector.net.md: documented but never emitted, removed from the docs", } // ignoredReferences are windows_ names that are not metrics of the exporter. diff --git a/tools/e2e-output.txt b/tools/e2e-output.txt index 91c9afad..ade1903a 100644 --- a/tools/e2e-output.txt +++ b/tools/e2e-output.txt @@ -155,12 +155,8 @@ windows_exporter_collector_timeout{collector="udp"} 0 # TYPE windows_logical_disk_info gauge # HELP windows_logical_disk_read_bytes_total The number of bytes transferred from the disk during read operations (LogicalDisk.DiskReadBytesPerSec) # TYPE windows_logical_disk_read_bytes_total counter -# HELP windows_logical_disk_read_latency_seconds_total Shows the average time, in seconds, of a read operation from the disk (LogicalDisk.AvgDiskSecPerRead) -# TYPE windows_logical_disk_read_latency_seconds_total counter # HELP windows_logical_disk_read_seconds_total Seconds that the disk was busy servicing read requests (LogicalDisk.PercentDiskReadTime) # TYPE windows_logical_disk_read_seconds_total counter -# HELP windows_logical_disk_read_write_latency_seconds_total Shows the time, in seconds, of the average disk transfer (LogicalDisk.AvgDiskSecPerTransfer) -# TYPE windows_logical_disk_read_write_latency_seconds_total counter # HELP windows_logical_disk_reads_total The number of read operations on the disk (LogicalDisk.DiskReadsPerSec) # TYPE windows_logical_disk_reads_total counter # HELP windows_logical_disk_requests_queued The number of requests queued to the disk (LogicalDisk.CurrentDiskQueueLength) @@ -171,8 +167,6 @@ windows_exporter_collector_timeout{collector="udp"} 0 # TYPE windows_logical_disk_split_ios_total counter # HELP windows_logical_disk_write_bytes_total The number of bytes transferred to the disk during write operations (LogicalDisk.DiskWriteBytesPerSec) # TYPE windows_logical_disk_write_bytes_total counter -# HELP windows_logical_disk_write_latency_seconds_total Shows the average time, in seconds, of a write operation to the disk (LogicalDisk.AvgDiskSecPerWrite) -# TYPE windows_logical_disk_write_latency_seconds_total counter # HELP windows_logical_disk_write_seconds_total Seconds that the disk was busy servicing write requests (LogicalDisk.PercentDiskWriteTime) # TYPE windows_logical_disk_write_seconds_total counter # HELP windows_logical_disk_writes_total The number of write operations on the disk (LogicalDisk.DiskWritesPerSec)