@@ -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