Skip to content

Commit

Permalink
Add drive I/O metrics for Prometheus
Browse files Browse the repository at this point in the history
Below metrics are exported:
* directpv_stats_drive_ready
* directpv_stats_drive_total_bytes_read
* directpv_stats_drive_total_bytes_written
* directpv_stats_drive_read_latency_seconds
* directpv_stats_drive_write_latency_seconds
* directpv_stats_drive_wait_time_seconds

Signed-off-by: Bala.FA <[email protected]>
  • Loading branch information
balamurugana committed Oct 9, 2024
1 parent 6f7b366 commit e8d0653
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 58 deletions.
29 changes: 0 additions & 29 deletions pkg/device/sysfs_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@ package device

import (
"bufio"
"errors"
"fmt"
"os"
"path"
"strconv"
"strings"
)
Expand Down Expand Up @@ -126,30 +124,3 @@ func GetStat(name string) (stats []uint64, err error) {

return stats, nil
}

// GetHardwareSectorSize returns hardware sector size of associated drive.
func GetHardwareSectorSize(name string) (uint64, error) {
if _, err := os.Lstat("/sys/block/" + name); err != nil {
if !errors.Is(err, os.ErrNotExist) {
return 0, err
}

partPath := "/sys/class/block/" + name
if _, err = os.Stat(partPath + "/partition"); err != nil {
return 0, err
}

linkPath, err := os.Readlink(partPath)
if err != nil {
return 0, err
}

name = path.Base(path.Dir(linkPath))
}

s, err := readFirstLine("/sys/block/" + name + "/queue/hw_sector_size")
if err != nil || s == "" {
return 0, err
}
return strconv.ParseUint(s, 10, 64)
}
38 changes: 9 additions & 29 deletions pkg/metrics/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import (
"k8s.io/klog/v2"
)

const defaultSectorSize = 512

type driveStats struct {
readSectorBytes float64
readTicks float64
Expand All @@ -51,19 +53,11 @@ func getDriveStats(driveName string) (*driveStats, error) {
return nil, fmt.Errorf("invalid stat format from drive %v", driveName)
}

hardwareSectorSize, err := device.GetHardwareSectorSize(driveName)
switch {
case err != nil:
return nil, err
case hardwareSectorSize == 0:
hardwareSectorSize = 512 // Use default value
}

// Refer https://www.kernel.org/doc/Documentation/block/stat.txt for meaning of each field.
return &driveStats{
readSectorBytes: float64(stat[2] * hardwareSectorSize),
readSectorBytes: float64(stat[2] * defaultSectorSize),
readTicks: float64(stat[3]),
writeSectorBytes: float64(stat[6] * hardwareSectorSize),
writeSectorBytes: float64(stat[6] * defaultSectorSize),
writeTicks: float64(stat[7]),
timeInQueue: float64(stat[9]),
}, nil
Expand Down Expand Up @@ -172,6 +166,11 @@ func (c *metricsCollector) publishDriveStats(drive *types.Drive, ch chan<- prome
prometheus.GaugeValue,
status, drive.Name,
)

if driveStat == nil {
return
}

ch <- prometheus.MustNewConstMetric(
prometheus.NewDesc(
prometheus.BuildFQName(consts.AppName, "stats", "drive_total_bytes_read"),
Expand Down Expand Up @@ -209,25 +208,6 @@ func (c *metricsCollector) publishDriveStats(drive *types.Drive, ch chan<- prome
driveStat.writeTicks/1000, drive.Name,
)

// Drive Read/Write Throughput
ch <- prometheus.MustNewConstMetric(
prometheus.NewDesc(
prometheus.BuildFQName(consts.AppName, "stats", "drive_read_throughput_bytes_per_second"),
"Drive Read Throughput",
[]string{"drive"}, nil),
prometheus.GaugeValue,
1000*driveStat.readSectorBytes/driveStat.readTicks, drive.Name,
)

ch <- prometheus.MustNewConstMetric(
prometheus.NewDesc(
prometheus.BuildFQName(consts.AppName, "stats", "drive_write_throughput_bytes_per_second"),
"Drive Write Throughput",
[]string{"drive"}, nil),
prometheus.GaugeValue,
1000*driveStat.writeSectorBytes/driveStat.writeTicks, drive.Name,
)

// Wait Time
ch <- prometheus.MustNewConstMetric(
prometheus.NewDesc(
Expand Down

0 comments on commit e8d0653

Please sign in to comment.