Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from collections import OrderedDict
- from time import sleep
- import glob
- import re
- import os
- import curses
- import argparse
- from subprocess import PIPE, run
- import json
- parser = argparse.ArgumentParser()
- parser.add_argument("-s", type=float, help="Sample size in seconds", default=1)
- parser.add_argument("-p", help="Show disk partition activity", action="store_true")
- args = parser.parse_args()
- sample_size = args.s
- def human_readable(b):
- r = b / 1024 / sample_size
- if r < 1024: # KB/sec
- return "{0:.3f} Kb".format(r)
- r = b / 1024 / 1024 / sample_size
- if r < 1024: # MiB/sec
- return "{0:.3f} Mb".format(r)
- r = b / 1024 / 1024 / 1024 / sample_size
- return "{0:.3f} Gb".format(r)
- def human_readable_fix(b):
- r = b / 1024 / sample_size
- if r < 1024: # KB/sec
- return [r, "Kb"]
- r = b / 1024 / 1024 / sample_size
- if r < 1024: # MiB/sec
- return [r, "Mb"]
- r = b / 1024 / 1024 / 1024 / sample_size
- return [r, "Gb"]
- class NetDev:
- name = ""
- tx = 0
- rx = 0
- class NetStat:
- stats = dict()
- infs_stat = dict()
- infs_stats1 = dict()
- infs_stats2 = dict()
- def get_inf_stats(self):
- inf_pattern = ['en.*', 'wl.*']
- stat = open('/proc/net/dev').read()
- for pattern in inf_pattern:
- regx = re.compile(pattern)
- res = regx.finditer(stat)
- for i in res:
- td = i.group(0).split()
- td[0] = td[0][:-1]
- self.stats[td[0]] = td[1:]
- def start_rx_tx_record(self):
- self.get_inf_stats() # update info
- for inf in self.stats:
- ndev = NetDev()
- ndev.name = inf
- ndev.rx = self.stats[inf][0]
- ndev.tx = self.stats[inf][8]
- self.infs_stats1[inf] = ndev
- def stop_rx_tx_record(self):
- self.get_inf_stats() # update info
- for inf in self.stats:
- ndev = NetDev()
- ndev.name = inf
- ndev.rx = self.stats[inf][0]
- ndev.tx = self.stats[inf][8]
- self.infs_stats2[inf] = ndev
- def compute_rx_tx_spd(self):
- infs_stat_sum = list()
- for inf1, inf2 in zip(self.infs_stats1, self.infs_stats2):
- if inf1 == inf2:
- ndev = NetDev()
- ndev.name = inf1
- ndev.rx = int(self.infs_stats2[inf1].rx) - int(self.infs_stats1[inf1].rx)
- ndev.tx = int(self.infs_stats2[inf1].tx) - int(self.infs_stats1[inf1].tx)
- infs_stat_sum.append(ndev)
- return infs_stat_sum
- class DiskFree:
- def __init__(self):
- self.cmd = ['df', '--block-size=1']
- res = run(self.cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True)
- out = str(res.stdout)
- self.dftab = dict()
- for line in out.splitlines()[1:]:
- sline = line.split()
- self.dftab[sline[0]] = sline[1:]
- def get_total(self, dev):
- dpath = '/dev/' + dev.name
- if dpath in self.dftab:
- return int(self.dftab[dpath][0])
- else:
- return None
- def get_used(self, dev):
- dpath = '/dev/' + dev.name
- if dpath in self.dftab:
- return int(self.dftab[dpath][1])
- else:
- return None
- def get_mount(self, dev):
- dpath = '/dev/' + dev.name
- if dpath in self.dftab:
- if self.dftab[dpath][4] == '/':
- return '/'
- else:
- return self.dftab[dpath][4]
- else:
- return ""
- class LsBlkB:
- def __init__(self):
- self.cmd = ['lsblk', '-b', '-J']
- res = run(self.cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True)
- out = str(res.stdout)
- js = json.loads(out)
- self.js = js['blockdevices']
- def get_size(self, dev):
- for i in range(0, len(self.js)):
- if self.js[i]['name'] == dev.name:
- return int(self.js[i]['size'])
- return 'unknown'
- def get_type(self, dev):
- for i in range(0, len(self.js)):
- if self.js[i]['name'] == dev.name:
- return self.js[i]['type']
- return 'null'
- class LsBlkFS:
- def __init__(self):
- self.cmd = ['lsblk', '-fs', '-J']
- res = run(self.cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True)
- out = str(res.stdout)
- js = json.loads(out)
- self.js = js['blockdevices']
- def get_fs(self, dev):
- for i in range(0, len(self.js)):
- if self.js[i]['name'] == dev.name:
- return self.js[i]['fstype']
- return ''
- def get_mount(self, dev):
- for i in range(0, len(self.js)):
- if self.js[i]['name'] == dev.name:
- return self.js[i]['mountpoint']
- return 'null'
- class SwapInfo:
- def __init__(self):
- self.cmd = ['swapon', '-l']
- res = run(self.cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True)
- out = str(res.stdout)
- self.dftab = dict()
- for line in out.splitlines()[1:]:
- sline = line.split()
- self.dftab[sline[0]] = sline[1:]
- def get_swap_info(self, dev):
- dpath = '/dev/' + dev.name
- if dpath in self.dftab:
- return [int(self.dftab[dpath][2]), int(self.dftab[dpath][3])]
- else:
- return None
- class Device:
- def __init__(self):
- self.name = ""
- self.stats = list()
- self.size = 0
- self.used = 0
- self.perc = 0
- self.fs = ''
- self.mount = ''
- self.sysfolder = ''
- self.model = ''
- self.child = 0
- self.childs = list()
- def __str__(self):
- return "name:{0}\nstats:{1}\nsize:{2}\nused:{3}\nperc:{4}\nfs:{5}\nmount:{6}\nsysfolder:{7}\n" \
- "model:{8}\nchild:{9}".format(self.name, self.stats, self.size, self.used,
- self.perc, self.fs, self.mount, self.sysfolder,
- self.model, self.child)
- class PermonmanceDevice(Device):
- perf = {}
- def __init__(self):
- Device.__init__(self)
- self.perf = {'read': 0, 'write': 0, 'size': ''}
- def compute(self, dev1):
- self.stats[2] = (self.stats[2] - dev1.stats[2])
- self.stats[6] = (self.stats[6] - dev1.stats[6])
- self.perf['read'] = human_readable(self.stats[2])
- self.perf['write'] = human_readable(self.stats[6])
- class HumanReadableDevice(PermonmanceDevice):
- def __init__(self):
- PermonmanceDevice.__init__(self)
- def compute(self, dev1):
- PermonmanceDevice.compute(self, dev1)
- size_p = human_readable_fix(self.size)
- used_p = human_readable_fix(self.used)
- perc_p = human_readable_fix(self.perc)
- used_s = "{0:.2f} {1}".format(round(used_p[0], 2), used_p[1])
- size_s = "{0:.2f} {1}".format(round(size_p[0], 2), size_p[1])
- perc_s = "{0:.2f}%".format(round(perc_p[0], 1))
- s = "{0}/{1} {2}".format(used_s, size_s, perc_s)
- PermonmanceDevice.perf['size'] = s
- def __str__(self):
- print(PermonmanceDevice.perf)
- class DeviceManager:
- def __init__(self):
- self.stack = list()
- self.devs = list()
- self.df = None
- self.lsblkfs = None
- self.lsblkb = None
- # self.swapinf = None
- def update(self):
- self.df = DiskFree()
- self.lsblkfs = LsBlkFS()
- self.lsblkb = LsBlkB()
- # self.swapinf = SwapInfo()
- if len(self.stack) >= 2:
- self.devs = list()
- self.stack = list()
- self.stack.append(self.devs)
- dev_pattern = ['sd.*']
- for device in glob.glob('/sys/block/*'):
- for pattern in dev_pattern:
- if re.compile(pattern).match(os.path.basename(device)):
- tdev = device.split('/')[-1]
- dev = HumanReadableDevice()
- dev.name = tdev
- dev.sysfolder = device
- self.devs.append(dev)
- for part in glob.glob('/sys/block/' + dev.name + '/*'):
- if re.compile(tdev + '[1-9]*').match(os.path.basename(part)):
- tpart = part.split('/')[-1]
- dev_part = HumanReadableDevice()
- dev_part.child = True
- dev_part.name = tpart
- dev_part.sysfolder = '/sys/block/' + dev.name + '/' + tpart
- dev.childs.append(dev_part)
- self.enrich_devices()
- def _enrich_model(self, dev):
- try:
- dev.model = open(dev.sysfolder + '/device/model').read().strip('\n').strip(' ')
- except:
- dev.model = 'inherit'
- def _enrich_mount(self, dev):
- dev.mount = self.lsblkfs.get_mount(dev)
- def _enrich_fs(self, dev):
- dev.fs = self.lsblkfs.get_fs(dev)
- def _enrich_size_(self, dev):
- res = self.df.get_total(dev)
- if res is not None:
- dev.size = res
- return True
- res = self.df.get_total(dev)
- if res is not None:
- dev.size = self.lsblkb.get_size(dev)
- return False
- return False
- def _enrich_used_(self, dev):
- res = self.df.get_used(dev)
- if res is not None:
- dev.used = res
- return True
- return False
- def _enrich_size(self, dev):
- if self._enrich_size_(dev) and self._enrich_used_(dev):
- dev.perc = dev.used / dev.size
- else:
- dev.size = self.lsblkb.get_size(dev)
- def _enrich_swapinfo(self, dev):
- swpinf = self.swapinf.get_swap_info(dev)
- if swpinf is not None:
- dev.size = swpinf[0]
- dev.used = swpinf[1]
- dev.perc = dev.used / dev.size
- else:
- return
- def _enrich_stats(self, dev):
- with open(dev.sysfolder + '/stat') as f:
- line = f.readline()
- dev.stats = [int(i) for i in line.split()]
- def _enrich_device(self, dev):
- self._enrich_stats(dev)
- self._enrich_size(dev)
- # self._enrich_swapinfo(dev)
- self._enrich_fs(dev)
- self._enrich_mount(dev)
- self._enrich_model(dev)
- for x in dev.childs:
- self._enrich_device(x)
- def enrich_devices(self):
- for dev in self.devs:
- self._enrich_device(dev)
- def _traverse(self, dev, depth):
- print(str(dev) + "\n")
- for x in dev.childs:
- self._traverse(x, depth + 1)
- def traverse(self):
- for dev in self.devs:
- self._traverse(dev, 0)
- def _get_device(self, devs, devs1, devs2):
- for dev1, dev2 in zip(devs1, devs2):
- dev2.compute(dev1)
- devs.append(dev2)
- def get_device(self):
- devs2 = self.stack.pop()
- devs1 = self.stack.pop()
- stat = OrderedDict()
- devs = list()
- self._get_device(devs, devs1, devs2)
- return devs
- ddd = DeviceManager()
- ddd.enrich_devices()
- ddd.traverse()
- stdscr = curses.initscr()
- curses.start_color()
- if not __debug__:
- stdscr.border()
- curses.noecho()
- curses.cbreak()
- curses.init_pair(1, curses.COLOR_GREEN, curses.COLOR_BLACK)
- curses.init_pair(2, curses.COLOR_CYAN, curses.COLOR_BLACK)
- curses.init_pair(3, curses.COLOR_WHITE, curses.COLOR_BLACK)
- stdscr.addstr(1, 1, "Devmon 0.1", curses.color_pair(3) | curses.A_BOLD)
- stdscr.addstr(2, 1, "Sample size {0} sec".format(sample_size), curses.color_pair(3) | curses.A_BOLD)
- class Row:
- def __init__(self):
- self.row = 4
- def next(self):
- tmp = self.row
- self.row += 1
- return tmp
- def current(self):
- return self.row
- class Col:
- @staticmethod
- def offset():
- return 1
- @staticmethod
- def device():
- return 0 + Col.offset()
- @staticmethod
- def read():
- return 12 + Col.offset()
- @staticmethod
- def write():
- return 25 + Col.offset()
- @staticmethod
- def size():
- return 40 + Col.offset()
- @staticmethod
- def filesystem():
- return 58 + Col.offset()
- @staticmethod
- def mount():
- return 64 + Col.offset()
- @staticmethod
- def model():
- return 75 + Col.offset()
- class Color:
- @staticmethod
- def autocolor(child):
- if not child:
- return Color.green()
- else:
- return Color.cyan()
- @staticmethod
- def green():
- return curses.color_pair(1) | curses.A_BOLD
- @staticmethod
- def cyan():
- return curses.color_pair(2) | curses.A_BOLD
- @staticmethod
- def white():
- return curses.color_pair(3) | curses.A_BOLD
- while True:
- # try:
- devmg = DeviceManager()
- ns = NetStat()
- row = Row()
- dev_stat = dict()
- dev_part_stat = dict()
- ns.start_rx_tx_record()
- devmg.update()
- sleep(sample_size)
- devmg.update()
- ns.stop_rx_tx_record()
- netdevs = ns.compute_rx_tx_spd()
- stdscr.clrtoeol()
- stdscr.addstr(row.current(), Col.device(), "Device", curses.color_pair(3) | curses.A_BOLD)
- stdscr.clrtoeol()
- stdscr.addstr(row.current(), Col.read(), "Read", curses.color_pair(3) | curses.A_BOLD)
- stdscr.clrtoeol()
- stdscr.addstr(row.current(), Col.write(), "Write", curses.color_pair(3) | curses.A_BOLD)
- stdscr.clrtoeol()
- stdscr.addstr(row.current(), Col.size(), "Size", curses.color_pair(3) | curses.A_BOLD)
- stdscr.clrtoeol()
- stdscr.addstr(row.current(), Col.filesystem(), "FS", curses.color_pair(3) | curses.A_BOLD)
- stdscr.clrtoeol()
- stdscr.addstr(row.current(), Col.mount(), "Mount", curses.color_pair(3) | curses.A_BOLD)
- stdscr.clrtoeol()
- stdscr.addstr(row.current(), Col.model(), "Model", curses.color_pair(3) | curses.A_BOLD)
- stdscr.clrtoeol()
- row.next()
- devs = devmg.get_device()
- for dev in devs:
- stdscr.clrtoeol()
- stdscr.addstr(row.current(), Col.device(), "[/dev/{0}]".format(dev.name), Color.autocolor(dev.child))
- stdscr.clrtoeol()
- stdscr.addstr(row.current(), Col.read(), "{0}".format(dev.perf['read']), Color.autocolor(dev.child))
- stdscr.clrtoeol()
- stdscr.addstr(row.current(), Col.write(), "{0}".format(dev.perf['write']), Color.autocolor(dev.child))
- stdscr.clrtoeol()
- stdscr.addstr(row.current(), Col.size(), "{0}".format(dev.perf['size']), Color.autocolor(dev.child))
- stdscr.clrtoeol()
- stdscr.addstr(row.current(), Col.filesystem(), "{0}".format(dev.fs), Color.autocolor(dev.child))
- stdscr.clrtoeol()
- stdscr.addstr(row.current(), Col.mount(), "{0}".format(dev.mount), Color.autocolor(dev.child))
- stdscr.clrtoeol()
- stdscr.addstr(row.current(), Col.model(), "[{0}]".format(dev.model), Color.autocolor(dev.child))
- stdscr.clrtoeol()
- row.next()
- row.next()
- for netdev in netdevs:
- stdscr.clrtoeol()
- stdscr.addstr(row.current(), Col.device(), "[{0}]".format(netdev.name),
- curses.color_pair(1) | curses.A_BOLD)
- stdscr.clrtoeol()
- stdscr.addstr(row.current(), Col.read(), "{0}/s".format(human_readable(netdev.rx)),
- curses.color_pair(1) | curses.A_BOLD)
- stdscr.clrtoeol()
- stdscr.addstr(row.current(), Col.write(), "{0}/s".format(human_readable(netdev.tx)),
- curses.color_pair(1) | curses.A_BOLD)
- stdscr.clrtoeol()
- row.next()
- stdscr.refresh()
- # except KeyboardInterrupt:
- # break
- # except:
- # sys.stderr.write("Unexpected error: {0}\n".format(sys.exc_info()[0]))
- # break
- if not __debug__:
- curses.echo()
- curses.cbreak()
- curses.endwin()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement