@@ -21,6 +21,7 @@ import (
21
21
"fmt"
22
22
"log/slog"
23
23
"os"
24
+ "path/filepath"
24
25
"strconv"
25
26
"strings"
26
27
@@ -84,6 +85,8 @@ type diskstatsCollector struct {
84
85
filesystemInfoDesc typedFactorDesc
85
86
deviceMapperInfoDesc typedFactorDesc
86
87
ataDescs map [string ]typedFactorDesc
88
+ ioErrDesc typedFactorDesc
89
+ ioDoneDesc typedFactorDesc
87
90
logger * slog.Logger
88
91
getUdevDeviceProperties func (uint32 , uint32 ) (udevInfo , error )
89
92
}
@@ -256,6 +259,20 @@ func NewDiskstatsCollector(logger *slog.Logger) (Collector, error) {
256
259
), valueType : prometheus .GaugeValue ,
257
260
},
258
261
},
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
+ },
259
276
logger : logger ,
260
277
}
261
278
@@ -372,6 +389,37 @@ func (c *diskstatsCollector) Update(ch chan<- prometheus.Metric) error {
372
389
}
373
390
}
374
391
}
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
+ }
375
423
}
376
424
return nil
377
425
}
0 commit comments