• Diskstat-1597068715819.png
    Diskstat-1597068715819.png

DiskStat Dashboard host or guest machine.

Show metrics:

  • Read/write device per second
  • IO bandwidth utilization
  • The number (after merges) of requests completed
  • The average time for requests
  • Average Queue size (sectors)
  • Queue utilization
  • I/Os currently in progress

grafana->graphite->collectd

Collector Configuration Details

<Plugin python>
    ModulePath "/opt/collectd/python"

    Import "diskstat"
    <Module diskstat>
#       Verbose true
        Interval 60
    </Module>
</Plugin>

/opt/collectd/python/diskstat.py


class diskstat(object):

    def __init__(self):
        self.plugin_name = 'diskstat'
        self.verbose_logging = False

    def log_verbose(self, msg):
        if not self.verbose_logging:
            return
        collectd.info('%s plugin [verbose]: %s' % (self.plugin_name, msg))

    def store(self, key, val):
        val = collectd.Values(type='gauge', plugin=self.plugin_name, type_instance=key, values=[val])
        val.dispatch()
        self.log_verbose('Sending value: %s:%s' % (key, val))

    def getdata(self):
        ret = {}
        mounted={}
        with open('/proc/self/mountinfo', 'r') as f:
            for line in f:
                arr = line.split()
                mounted[arr[2]] = arr[4]
        tpl = ['major', 'minor', 'dev_name', 'rd_ios', 'rd_merges', 'rd_sect', 'rd_ticks', 'wr_ios', 'wr_merges', 'wr_sect', 'wr_ticks', 'ios_in_progress', 'tot_ticks', 'rq_ticks', 'dc_ios', 'dc_merges', 'dc_sec', 'dc_ticks']
        with open('/proc/diskstats', 'r') as f:
            for line in f:
                arr = line.split()
                major = int(arr[0])
                # collect major=8 and len(dev_name)==3 (sda,sdb,sdc... for Hostsystem)
                if major == 8 and len(arr[2]) == 3:
                    dev_name = arr[2]
                    ret[dev_name] = {}
                    i = 0
                    for val in arr:
                        key = tpl[i]
                        ret[dev_name][key] = val
                        i += 1
                # collect major=254,253,252,8 and mounted devices (only mounted for guestVM)
                major_minor = "%s:%s" % (arr[0], arr[1])
                if major in [254, 253, 252, 8] and major_minor in mounted:
                    dev_name = mounted[major_minor][1:].replace('/', '-')
                    if not dev_name:
                        dev_name = 'root'
                    ret[dev_name] = {}
                    i = 0
                    for val in arr:
                        key = tpl[i]
                        ret[dev_name][key] = val
                        i += 1
        return ret

    def read(self):
        data = self.getdata()
        for name in data:
            qname = name.replace('.','_')
            # ios_in_progress
            self.store('%s__ios_in_progress' % qname, int(data[name]['ios_in_progress']))
            # sectors read and sectors written
            self.store('%s__wr_sect' % qname, int(data[name]['wr_sect']))
            self.store('%s__rd_sect' % qname, int(data[name]['rd_sect']))
            # reads merged and writes merged
            self.store('%s__wr_merges' % qname, int(data[name]['wr_merges']))
            self.store('%s__rd_merges' % qname, int(data[name]['rd_merges']))
            # writes completed and reads completed successfully
            self.store('%s__wr_ios' % qname, int(data[name]['wr_ios']))
            self.store('%s__rd_ios' % qname, int(data[name]['rd_ios']))
            # ticks in ms
            self.store('%s__rd_ticks' % qname, int(data[name]['rd_ticks']))
            self.store('%s__wr_ticks' % qname, int(data[name]['wr_ticks']))
            self.store('%s__tot_ticks' % qname, int(data[name]['tot_ticks']))
            self.store('%s__rq_ticks' % qname, int(data[name]['rq_ticks']))

    def configure_callback(self, conf):
        for node in conf.children:
            vals = [str(v) for v in node.values]
            if node.key == 'Verbose':
                self.verbose_logging = (vals[0].lower() == 'true')
            elif node.key == 'Interval':
                self.interval = float(vals[0])
            else:
                raise ValueError('%s plugin: Unknown config key: %s' % (self.plugin_name, node.key))
        collectd.register_read(self.read, self.interval)
        self.log_verbose('configured with interval=%s' % self.interval)


app_diskstat = diskstat()
collectd.register_config(app_diskstat.configure_callback)