diff --git a/collector/fixtures/e2e-64k-page-output.txt b/collector/fixtures/e2e-64k-page-output.txt index 18a34815ba..1b74382203 100644 --- a/collector/fixtures/e2e-64k-page-output.txt +++ b/collector/fixtures/e2e-64k-page-output.txt @@ -3514,9 +3514,9 @@ node_nfsd_server_threads 8 # HELP node_nvme_info Non-numeric data from /sys/class/nvme/, value is always 1. # TYPE node_nvme_info gauge node_nvme_info{cntlid="1997",device="nvme0",firmware_revision="1B2QEXP7",model="Samsung SSD 970 PRO 512GB",serial="S680HF8N190894I",state="live"} 1 -# HELP node_nvme_namespace_capacity_bytes Capacity of the NVMe namespace in bytes. Computed as namespace_size * namespace_logical_block_size +# HELP node_nvme_namespace_capacity_bytes Capacity of the NVMe namespace in bytes. # TYPE node_nvme_namespace_capacity_bytes gauge -node_nvme_namespace_capacity_bytes{device="nvme0",nsid="1"} 1.6e+13 +node_nvme_namespace_capacity_bytes{device="nvme0",nsid="1"} 2e+12 # HELP node_nvme_namespace_info Information about NVMe namespaces. Value is always 1 # TYPE node_nvme_namespace_info gauge node_nvme_namespace_info{ana_state="optimized",device="nvme0",nsid="1"} 1 @@ -3525,7 +3525,7 @@ node_nvme_namespace_info{ana_state="optimized",device="nvme0",nsid="1"} 1 node_nvme_namespace_logical_block_size_bytes{device="nvme0",nsid="1"} 4096 # HELP node_nvme_namespace_size_bytes Size of the NVMe namespace in bytes. Available in /sys/class/nvme///size # TYPE node_nvme_namespace_size_bytes gauge -node_nvme_namespace_size_bytes{device="nvme0",nsid="1"} 1.6e+13 +node_nvme_namespace_size_bytes{device="nvme0",nsid="1"} 2e+12 # HELP node_nvme_namespace_used_bytes Used space of the NVMe namespace in bytes. Available in /sys/class/nvme///nuse # TYPE node_nvme_namespace_used_bytes gauge node_nvme_namespace_used_bytes{device="nvme0",nsid="1"} 2e+12 diff --git a/collector/fixtures/e2e-output.txt b/collector/fixtures/e2e-output.txt index 0c91a90300..4dd448d5c6 100644 --- a/collector/fixtures/e2e-output.txt +++ b/collector/fixtures/e2e-output.txt @@ -3536,9 +3536,9 @@ node_nfsd_server_threads 8 # HELP node_nvme_info Non-numeric data from /sys/class/nvme/, value is always 1. # TYPE node_nvme_info gauge node_nvme_info{cntlid="1997",device="nvme0",firmware_revision="1B2QEXP7",model="Samsung SSD 970 PRO 512GB",serial="S680HF8N190894I",state="live"} 1 -# HELP node_nvme_namespace_capacity_bytes Capacity of the NVMe namespace in bytes. Computed as namespace_size * namespace_logical_block_size +# HELP node_nvme_namespace_capacity_bytes Capacity of the NVMe namespace in bytes. # TYPE node_nvme_namespace_capacity_bytes gauge -node_nvme_namespace_capacity_bytes{device="nvme0",nsid="1"} 1.6e+13 +node_nvme_namespace_capacity_bytes{device="nvme0",nsid="1"} 2e+12 # HELP node_nvme_namespace_info Information about NVMe namespaces. Value is always 1 # TYPE node_nvme_namespace_info gauge node_nvme_namespace_info{ana_state="optimized",device="nvme0",nsid="1"} 1 @@ -3547,7 +3547,7 @@ node_nvme_namespace_info{ana_state="optimized",device="nvme0",nsid="1"} 1 node_nvme_namespace_logical_block_size_bytes{device="nvme0",nsid="1"} 4096 # HELP node_nvme_namespace_size_bytes Size of the NVMe namespace in bytes. Available in /sys/class/nvme///size # TYPE node_nvme_namespace_size_bytes gauge -node_nvme_namespace_size_bytes{device="nvme0",nsid="1"} 1.6e+13 +node_nvme_namespace_size_bytes{device="nvme0",nsid="1"} 2e+12 # HELP node_nvme_namespace_used_bytes Used space of the NVMe namespace in bytes. Available in /sys/class/nvme///nuse # TYPE node_nvme_namespace_used_bytes gauge node_nvme_namespace_used_bytes{device="nvme0",nsid="1"} 2e+12 diff --git a/collector/nvme_linux.go b/collector/nvme_linux.go index dff757c7bd..ef95ee608b 100644 --- a/collector/nvme_linux.go +++ b/collector/nvme_linux.go @@ -21,10 +21,13 @@ import ( "log/slog" "os" + "github.com/alecthomas/kingpin/v2" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/procfs/sysfs" ) +var nvmeNamespaceUsage = kingpin.Flag("collector.nvme.namespace-usage", "Expose namespace used bytes (reads nuse, which makes the kernel query the controller).").Default("true").Bool() + type nvmeCollector struct { fs sysfs.FS logger *slog.Logger @@ -49,7 +52,7 @@ var ( nvmeNamespaceCapacityBytes = prometheus.NewDesc( prometheus.BuildFQName(namespace, "nvme", "namespace_capacity_bytes"), - "Capacity of the NVMe namespace in bytes. Computed as namespace_size * namespace_logical_block_size", + "Capacity of the NVMe namespace in bytes.", []string{"device", "nsid"}, nil, ) @@ -139,13 +142,26 @@ func (c *nvmeCollector) Update(ch chan<- prometheus.Metric) error { ) // Namespace used space in bytes - ch <- prometheus.MustNewConstMetric( - nvmeNamespaceUsedBytes, - prometheus.GaugeValue, - float64(namespace.UsedBytes), - device.Name, - namespace.ID, - ) + if *nvmeNamespaceUsage { + usedBlocks, err := namespace.UsedBlocks() + if err != nil { + // The kernel queries the controller on read, so this can + // fail, e.g. with EIO if the controller is not live. + // Keep collecting the other namespaces. + c.logger.Warn("Could not read NVMe namespace usage", "device", device.Name, "namespace", namespace.Name, "err", err) + } else if usedBlocks == nil { + c.logger.Debug("NVMe namespace nuse file not present, skipping", "device", device.Name, "namespace", namespace.Name) + } else { + usedBytes := *usedBlocks * namespace.LogicalBlockSize + ch <- prometheus.MustNewConstMetric( + nvmeNamespaceUsedBytes, + prometheus.GaugeValue, + float64(usedBytes), + device.Name, + namespace.ID, + ) + } + } // Namespace logical block size in bytes ch <- prometheus.MustNewConstMetric( diff --git a/go.mod b/go.mod index 943fb173c3..0ece4bb32c 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/prometheus/client_model v0.6.3 github.com/prometheus/common v0.72.1 github.com/prometheus/exporter-toolkit v0.20.0 - github.com/prometheus/procfs v0.22.0 + github.com/prometheus/procfs v0.23.0 github.com/safchain/ethtool v0.7.0 golang.org/x/sys v0.49.0 howett.net/plist v1.0.1 diff --git a/go.sum b/go.sum index 12ea361f53..dac01056a1 100644 --- a/go.sum +++ b/go.sum @@ -82,8 +82,8 @@ github.com/prometheus/common v0.72.1 h1:ZAiQed/nk8IIcsdzb2TlJu23NEUDyDLQ9TXTN2WR github.com/prometheus/common v0.72.1/go.mod h1:1IoBY4IRaJnhs2ESjNzjilP1cJ/P8pimGoomq7zRXrA= github.com/prometheus/exporter-toolkit v0.20.0 h1:hz3g2aPcq3mXlQSt1MGjj2rwVk1wtRalF+/FjYxFRkI= github.com/prometheus/exporter-toolkit v0.20.0/go.mod h1:gIIY0Mw0ci1wgYscdeMqVh6FUPYJca549eOkE39nU64= -github.com/prometheus/procfs v0.22.0 h1:6q9+/JL9IKAPbCmBrv9n5O5Ty3NKnciV5X7YGw0oics= -github.com/prometheus/procfs v0.22.0/go.mod h1:CvmFr/GVhIjIvWJZW3tgkODBQMRIf0EyWMQLHCHab58= +github.com/prometheus/procfs v0.23.0 h1:ad+S6FTkzwaMgacKLM5h6bNKExS+DMH0YiUwXItH/o4= +github.com/prometheus/procfs v0.23.0/go.mod h1:3AVXO0FqLafyYFU/V/IQRZlC8Rgqz8Dm/x6pKLK+RIk= github.com/safchain/ethtool v0.7.0 h1:rlJzfDetsVvT61uz8x1YIcFn12akMfuPulHtZjtb7Is= github.com/safchain/ethtool v0.7.0/go.mod h1:MenQKEjXdfkjD3mp2QdCk8B/hwvkrlOTm/FD4gTpFxQ= github.com/siebenmann/go-kstat v0.0.0-20210513183136-173c9b0a9973 h1:GfSdC6wKfTGcgCS7BtzF5694Amne1pGCSTY252WhlEY=