@@ -21,6 +21,7 @@ import (
2121 "fmt"
2222 "log/slog"
2323 "os"
24+ "path/filepath"
2425 "strconv"
2526 "strings"
2627
@@ -84,6 +85,8 @@ type diskstatsCollector struct {
8485 filesystemInfoDesc typedFactorDesc
8586 deviceMapperInfoDesc typedFactorDesc
8687 ataDescs map [string ]typedFactorDesc
88+ ioErrDesc typedFactorDesc
89+ ioDoneDesc typedFactorDesc
8790 logger * slog.Logger
8891 getUdevDeviceProperties func (uint32 , uint32 ) (udevInfo , error )
8992}
@@ -256,6 +259,20 @@ func NewDiskstatsCollector(logger *slog.Logger) (Collector, error) {
256259 ), valueType : prometheus .GaugeValue ,
257260 },
258261 },
262+ ioErrDesc : typedFactorDesc {
263+ desc : prometheus .NewDesc (prometheus .BuildFQName (namespace , diskSubsystem , "ioerr_total" ),
264+ "Number of IO commands that completed with an error." ,
265+ []string {"device" },
266+ nil ,
267+ ), valueType : prometheus .CounterValue ,
268+ },
269+ ioDoneDesc : typedFactorDesc {
270+ desc : prometheus .NewDesc (prometheus .BuildFQName (namespace , diskSubsystem , "iodone_total" ),
271+ "Number of completed or rejected IO commands." ,
272+ []string {"device" },
273+ nil ,
274+ ), valueType : prometheus .CounterValue ,
275+ },
259276 logger : logger ,
260277 }
261278
@@ -372,6 +389,37 @@ func (c *diskstatsCollector) Update(ch chan<- prometheus.Metric) error {
372389 }
373390 }
374391 }
392+
393+ // Read IO error counts if available
394+ iodoneCnt , err := os .ReadFile (filepath .Join (* sysPath , "block" , dev , "device/iodone_cnt" ))
395+ if err != nil {
396+ // Skip if file doesn't exist
397+ if ! os .IsNotExist (err ) {
398+ c .logger .Debug ("Error reading IO errors count" , "collector" , "diskstats" , "err" , err )
399+ }
400+ } else {
401+ iodone , err := strconv .ParseUint (strings .TrimSpace (string (iodoneCnt )), 10 , 64 )
402+ if err != nil {
403+ c .logger .Debug ("Error parsing iodone count" , "collector" , "diskstats" , "err" , err )
404+ } else {
405+ ch <- c .ioDoneDesc .mustNewConstMetric (float64 (iodone ), dev )
406+ }
407+ }
408+
409+ ioerrCnt , err := os .ReadFile (filepath .Join (* sysPath , "block" , dev , "device/ioerr_cnt" ))
410+ if err != nil {
411+ // Skip if file doesn't exist
412+ if ! os .IsNotExist (err ) {
413+ c .logger .Debug ("Error reading IO errors count" , "collector" , "diskstats" , "err" , err )
414+ }
415+ } else {
416+ ioerr , err := strconv .ParseUint (strings .TrimSpace (string (ioerrCnt )), 10 , 64 )
417+ if err != nil {
418+ c .logger .Debug ("Error parsing ioerr count" , "collector" , "diskstats" , "err" , err )
419+ } else {
420+ ch <- c .ioErrDesc .mustNewConstMetric (float64 (ioerr ), dev )
421+ }
422+ }
375423 }
376424 return nil
377425}
0 commit comments