hyperv: deprecate cumulative virtual storage device latency gauges (#2565)

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 09:16:41 +02:00
committed by GitHub
co-authored by Claude Opus 5.5
parent fedca642a1
commit 54aeb2b391
3 changed files with 103 additions and 18 deletions
+37 -14
View File
@@ -321,20 +321,43 @@ Example alert:
### Hyper-V Virtual Storage Device
| Name | Description | Type | Labels |
|---------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------|---------|----------|
| `windows_hyperv_virtual_storage_device_error_count_total` | Represents the total number of errors that have occurred on this virtual device. | counter | `device` |
| `windows_hyperv_virtual_storage_device_queue_length` | Represents the average queue length on this virtual device. | gauge | `device` |
| `windows_hyperv_virtual_storage_device_bytes_read` | Represents the total number of bytes that have been read on this virtual device. | counter | `device` |
| `windows_hyperv_virtual_storage_device_operations_read_total` | Represents the total number of read operations that have occurred on this virtual device. | counter | `device` |
| `windows_hyperv_virtual_storage_device_bytes_written` | Represents the total number of bytes that have been written on this virtual device. | counter | `device` |
| `windows_hyperv_virtual_storage_device_operations_written_total` | Represents the total number of write operations that have occurred on this virtual device. | counter | `device` |
| `windows_hyperv_virtual_storage_device_latency_seconds` | Represents the average IO transfer latency for this virtual device. | gauge | `device` |
| `windows_hyperv_virtual_storage_device_throughput_total` | Represents the total number of 8KB IO transfers completed by this virtual device. | counter | `device` |
| `windows_hyperv_virtual_storage_device_normalized_throughput` | Represents the average number of IO transfers completed by this virtual device. | gauge | `device` |
| `windows_hyperv_virtual_storage_device_lower_queue_length` | Represents the average queue length on the underlying storage subsystem for this device. | gauge | `device` |
| `windows_hyperv_virtual_storage_device_lower_latency_seconds` | Represents the average IO transfer latency on the underlying storage subsystem for this virtual device. | gauge | `device` |
| `windows_hyperv_virtual_storage_device_io_quota_replenishment_rate` | Represents the IO quota replenishment rate for this virtual device. | gauge | `device` |
| Name | Description | Type | Labels |
|------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|---------|----------|
| `windows_hyperv_virtual_storage_device_error_count_total` | Represents the total number of errors that have occurred on this virtual device. | counter | `device` |
| `windows_hyperv_virtual_storage_device_queue_length` | **Deprecated:** use `rate(windows_hyperv_virtual_storage_device_io_latency_seconds_total)`. Cumulative queue length in 100ns ticks, see below. | gauge | `device` |
| `windows_hyperv_virtual_storage_device_bytes_read` | Represents the total number of bytes that have been read on this virtual device. | counter | `device` |
| `windows_hyperv_virtual_storage_device_operations_read_total` | Represents the total number of read operations that have occurred on this virtual device. | counter | `device` |
| `windows_hyperv_virtual_storage_device_bytes_written` | Represents the total number of bytes that have been written on this virtual device. | counter | `device` |
| `windows_hyperv_virtual_storage_device_operations_written_total` | Represents the total number of write operations that have occurred on this virtual device. | counter | `device` |
| `windows_hyperv_virtual_storage_device_io_latency_seconds_total` | Represents the total IO transfer latency for this virtual device. | counter | `device` |
| `windows_hyperv_virtual_storage_device_latency_seconds` | **Deprecated:** use `windows_hyperv_virtual_storage_device_io_latency_seconds_total`. Cumulative IO transfer latency in 100ns ticks, see below. | gauge | `device` |
| `windows_hyperv_virtual_storage_device_throughput_total` | Represents the total number of 8KB IO transfers completed by this virtual device. | counter | `device` |
| `windows_hyperv_virtual_storage_device_normalized_throughput` | Represents the average number of IO transfers completed by this virtual device. | gauge | `device` |
| `windows_hyperv_virtual_storage_device_lower_io_latency_seconds_total` | Represents the total IO transfer latency on the underlying storage subsystem for this virtual device. | counter | `device` |
| `windows_hyperv_virtual_storage_device_lower_queue_length` | **Deprecated:** use `rate(windows_hyperv_virtual_storage_device_lower_io_latency_seconds_total)`. Cumulative queue length in 100ns ticks, see below. | gauge | `device` |
| `windows_hyperv_virtual_storage_device_lower_latency_seconds` | **Deprecated:** use `windows_hyperv_virtual_storage_device_lower_io_latency_seconds_total`. Cumulative IO transfer latency in 100ns ticks, see below. | gauge | `device` |
| `windows_hyperv_virtual_storage_device_io_quota_replenishment_rate` | Represents the IO quota replenishment rate for this virtual device. | gauge | `device` |
#### Deprecated latency and queue length metrics
The `Latency`, `Lower Latency`, `Queue Length` and `Lower Queue Length` performance counters
are averages that Windows computes from two samples. windows_exporter reads their raw values,
which only grow: the sum of all IO latencies in 100ns ticks. The raw queue length values are
the same as the raw latency values.
`windows_hyperv_virtual_storage_device_latency_seconds`, `windows_hyperv_virtual_storage_device_lower_latency_seconds`,
`windows_hyperv_virtual_storage_device_queue_length` and `windows_hyperv_virtual_storage_device_lower_queue_length`
keep exposing these raw values as gauges for compatibility. They are deprecated and will be removed in a future release.
Use the `*_io_latency_seconds_total` counters instead:
```promql
# Average IO latency in seconds
rate(windows_hyperv_virtual_storage_device_io_latency_seconds_total[5m])
/ rate(windows_hyperv_virtual_storage_device_throughput_total[5m])
# Average queue length
rate(windows_hyperv_virtual_storage_device_io_latency_seconds_total[5m])
```
### Hyper-V VM Vid Partition
+26
View File
@@ -26,6 +26,7 @@ import (
"github.com/prometheus-community/windows_exporter/internal/pdh"
"github.com/prometheus-community/windows_exporter/internal/utils/testutils"
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
"github.com/stretchr/testify/require"
)
@@ -49,6 +50,31 @@ func TestCollector(t *testing.T) {
}
}
// TestCollectorVirtualStorageDeviceLatency checks that the deprecated latency gauges
// expose the raw cumulative value in 100ns ticks of the *_io_latency_seconds_total counters.
func TestCollectorVirtualStorageDeviceLatency(t *testing.T) {
metrics := testutils.TestCollector(t, hyperv.New, &hyperv.Config{CollectorsEnabled: []string{"virtual_storage_device"}})
for deprecated, replacement := range map[string]string{
"windows_hyperv_virtual_storage_device_latency_seconds": "windows_hyperv_virtual_storage_device_io_latency_seconds_total",
"windows_hyperv_virtual_storage_device_lower_latency_seconds": "windows_hyperv_virtual_storage_device_lower_io_latency_seconds_total",
} {
want := testutils.MetricValuesByLabel(metrics, deprecated, "device")
got := testutils.MetricValuesByLabel(metrics, replacement, "device")
require.Len(t, got, len(want))
if len(got) > 0 {
require.Equal(t, dto.MetricType_COUNTER, metrics[replacement].GetType())
}
for device, ticks := range want {
require.Contains(t, got, device)
require.InDelta(t, ticks*pdh.TicksToSecondScaleFactor, got[device], 1e-6, "%s{device=%q}", replacement, device)
}
}
}
// TestCloseReleasesQuery ensures Close releases the PDH queries of the sub-collectors.
func TestCloseReleasesQuery(t *testing.T) {
t.Parallel()
@@ -42,6 +42,8 @@ type collectorVirtualStorageDevice struct {
virtualStorageDeviceLowerQueueLength *prometheus.Desc // \Hyper-V Virtual Storage Device(*)\Lower Queue Length
virtualStorageDeviceLowerLatency *prometheus.Desc // \Hyper-V Virtual Storage Device(*)\Lower Latency
virtualStorageDeviceIOQuotaReplenishmentRate *prometheus.Desc // \Hyper-V Virtual Storage Device(*)\IO Quota Replenishment Rate
virtualStorageDeviceIOLatency *prometheus.Desc // \Hyper-V Virtual Storage Device(*)\Latency
virtualStorageDeviceLowerIOLatency *prometheus.Desc // \Hyper-V Virtual Storage Device(*)\Lower Latency
}
type perfDataCounterValuesVirtualStorageDevice struct {
@@ -77,7 +79,8 @@ func (c *Collector) buildVirtualStorageDevice() error {
)
c.virtualStorageDeviceQueueLength = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "virtual_storage_device_queue_length"),
"Represents the average queue length on this virtual device.",
"DEPRECATED: use rate(windows_hyperv_virtual_storage_device_io_latency_seconds_total). "+
"Cumulative queue length in 100ns ticks, identical to the raw latency.",
[]string{"device"},
nil,
)
@@ -107,7 +110,8 @@ func (c *Collector) buildVirtualStorageDevice() error {
)
c.virtualStorageDeviceLatency = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "virtual_storage_device_latency_seconds"),
"Represents the average IO transfer latency for this virtual device.",
"DEPRECATED: use windows_hyperv_virtual_storage_device_io_latency_seconds_total. "+
"Cumulative IO transfer latency in 100ns ticks for this virtual device.",
[]string{"device"},
nil,
)
@@ -125,13 +129,29 @@ func (c *Collector) buildVirtualStorageDevice() error {
)
c.virtualStorageDeviceLowerQueueLength = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "virtual_storage_device_lower_queue_length"),
"Represents the average queue length on the underlying storage subsystem for this device.",
"DEPRECATED: use rate(windows_hyperv_virtual_storage_device_lower_io_latency_seconds_total). "+
"Cumulative queue length in 100ns ticks on the underlying storage subsystem, identical to the raw lower latency.",
[]string{"device"},
nil,
)
c.virtualStorageDeviceLowerLatency = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "virtual_storage_device_lower_latency_seconds"),
"Represents the average IO transfer latency on the underlying storage subsystem for this virtual device.",
"DEPRECATED: use windows_hyperv_virtual_storage_device_lower_io_latency_seconds_total. "+
"Cumulative IO transfer latency in 100ns ticks on the underlying storage subsystem for this virtual device.",
[]string{"device"},
nil,
)
c.virtualStorageDeviceIOLatency = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "virtual_storage_device_io_latency_seconds_total"),
"Represents the total IO transfer latency for this virtual device. "+
"Divide its rate by the rate of windows_hyperv_virtual_storage_device_throughput_total for the average latency.",
[]string{"device"},
nil,
)
c.virtualStorageDeviceLowerIOLatency = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "virtual_storage_device_lower_io_latency_seconds_total"),
"Represents the total IO transfer latency on the underlying storage subsystem for this virtual device. "+
"Divide its rate by the rate of windows_hyperv_virtual_storage_device_throughput_total for the average latency.",
[]string{"device"},
nil,
)
@@ -235,6 +255,22 @@ func (c *Collector) collectVirtualStorageDevice(ch chan<- prometheus.Metric) err
data.VirtualStorageDeviceIOQuotaReplenishmentRate,
data.Name,
)
// The raw value of a PERF_AVERAGE_TIMER counter is the sum of all IO latencies in
// 100ns ticks; the operation count it is averaged over is Throughput.
ch <- prometheus.MustNewConstMetric(
c.virtualStorageDeviceIOLatency,
prometheus.CounterValue,
data.VirtualStorageDeviceLatency*pdh.TicksToSecondScaleFactor,
data.Name,
)
ch <- prometheus.MustNewConstMetric(
c.virtualStorageDeviceLowerIOLatency,
prometheus.CounterValue,
data.VirtualStorageDeviceLowerLatency*pdh.TicksToSecondScaleFactor,
data.Name,
)
}
return nil