Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Tree: ac280dec40
Fetching contributors…

Cannot retrieve contributors at this time

executable file 1461 lines (1295 sloc) 41.65 kB
#!/usr/bin/env python
### This program is free software; you can redistribute it and/or modify
### it under the terms of the GNU Library General Public License as published by
### the Free Software Foundation; version 2 only
###
### This program is distributed in the hope that it will be useful,
### but WITHOUT ANY WARRANTY; without even the implied warranty of
### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
### GNU Library General Public License for more details.
###
### You should have received a copy of the GNU Library General Public License
### along with this program; if not, write to the Free Software
### Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
### Copyright 2004 Dag Wieers <dag@wieers.com>
from __future__ import generators
import fcntl, struct, types
import os, sys, re, getopt, time, termios
import ConfigParser, urlparse, signal, resource
#import curses
VERSION = '0.5.8'
enable = ('yes', 'on', 'true', '1')
disable = ('no', 'off', 'false', '0')
class Options:
def __init__(self, args):
self.args = args
self.count = -1
self.cpulist = None
self.csv = False
self.delay = 1
self.disklist = None
self.full = False
self.integer = False
self.intlist = None
self.netlist = None
self.nolimit = False
self.color = True
self.update = True
self.header = True
try:
opts, args = getopt.getopt (args, 'acdfghilmnpstuvyC:D:I:M:N:V',
['all', 'cpu', 'disk', 'help', 'int', 'load', 'mem', 'net', 'page', 'proc',
'swap', 'sys', 'tcp', 'time', 'udp', 'user', 'version', 'vmstat',
'csv', 'full', 'integer', 'mods', 'modules', 'nocolor', 'noheaders', 'noupdate'])
except getopt.error, exc:
print 'dstat: %s, try dstat -h for a list of all the options' % str(exc)
sys.exit(1)
self.modlist = []
for opt, arg in opts:
if opt in ['-c', '--cpu']:
self.modlist.append('cpu')
elif opt in ['-C']:
self.cpulist = arg.split(',')
elif opt in ['-d', '--disk']:
self.modlist.append('disk')
elif opt in ['-D']:
self.disklist = arg.split(',')
elif opt in ['-i', '--int']:
self.modlist.append('int')
elif opt in ['-g', '--page']:
self.modlist.append('page')
elif opt in ['-I']:
self.intlist = arg.split(',')
elif opt in ['-m', '--mem']:
self.modlist.append('mem')
elif opt in ['-M', '--mods', '--modules']:
self.modlist = self.modlist + arg.split(',')
elif opt in ['-l', '--load']:
self.modlist.append('load')
elif opt in ['-n', '--net']:
self.modlist.append('net')
elif opt in ['-N']:
self.netlist = arg.split(',')
elif opt in ['-p', '--proc']:
self.modlist.append('proc')
elif opt in ['-s', '--swap']:
self.modlist.append('swap')
elif opt in ['--tcp']:
self.modlist.append('tcp')
elif opt in ['-t', '--time']:
self.modlist.append('time')
elif opt in ['-u', '--user']:
self.modlist.append('user')
elif opt in ['--udp']:
self.modlist.append('udp')
elif opt in ['-y', '--sys']:
self.modlist.append('sys')
elif opt in ['-a', '--all']:
self.modlist = self.modlist + [ 'cpu', 'disk', 'net', 'page', 'sys', 'load' ]
elif opt in ['-v', '--vmstat']:
self.modlist = self.modlist + [ 'proc', 'mem', 'page', 'disk', 'sys', 'cpu' ]
self.disklist = ('total',)
elif opt in ['--csv']:
self.csv = True
elif opt in ['-f', '--full']:
self.full = True
elif opt in ['--integer']:
self.integer = True
elif opt in ['--nocolor']:
self.color = False
self.update = False
elif opt in ['--noheaders']:
self.header = False
elif opt in ['--noupdate']:
self.update = False
elif opt in ['-h', '--help']:
self.usage()
self.help()
sys.exit(0)
elif opt in ['-V', '--version']:
self.version()
sys.exit(0)
if not self.modlist:
self.modlist = [ 'cpu', 'disk', 'net', 'page', 'sys' ]
try:
if len(args) > 0: self.delay = int(args[0])
if len(args) > 1: self.count = int(args[1])
except:
print 'dstat: incorrect argument, try dstat -h for the correct syntax'
sys.exit(1)
if self.delay == 0:
print 'dstat: delay must be an integer, greater than zero'
sys.exit(1)
if self.csv:
self.color = False
self.header = False
self.nolimit = True
self.update = False
def version(self):
print 'Dstat %s' % VERSION
print 'Written by Dag Wieers <dag@wieers.com>'
print 'Homepage at http://dag.wieers.com/home-made/dstat/'
print
print 'Platform %s/%s' % (os.name, sys.platform)
print 'Kernel %s' % os.uname()[2]
print 'Python %s' % sys.version
print
print 'Processors: %d' % getcpunr()
print 'Pagesize: %d' % resource.getpagesize()
print 'Clock ticks per secs: %d' % os.sysconf('SC_CLK_TCK')
def usage(self):
print 'usage: dstat [-afv] [-cdgilmnpsty] [-D..] [-I..] [-N..] [delay [count]]'
def help(self):
print '''Versatile tool for generating system resource statistics
Dstat options:
-c, --cpu enable cpu stats
-C 0,3, include cpu0, cpu3 and total
-d, --disk enable disk stats
-D total,hda include hda and total
-g, --page enable page stats
-i, --int enable interrupt stats
-I 5,eth2 include int5 and interrupt used by eth2
-l, --load enable load stats
-m, --mem enable memory stats
-n, --net enable network stats
-N eth1,total include eth1 and total
-p, --proc enable process stats
-s, --swap enable swap stats
-t, --time enable time counter
-u, --user enable user stats
-y, --sys enable system stats
-M stat1,stat2 enable specific stats
--mods stat1,stat2
Possible stats are:
cpu, disk, page, int, load, mem, net, proc,
swap, sys, tcp, time, udp, user
-a, --all equals -cdngyl
-v, --vmstat equals -pmgdsc -D total
-f, --full expand -D, -I and -N discovery lists
--csv output CSV format
--integer show integer values
--nocolor disable colors (implies --noupdate)
--noheaders disable repetitive headers
--noupdate disable intermediate updates when delay > 1
delay is the delay in seconds between each update
count is the number of updates to display before exiting
The default delay is zero and count is one
'''
class Config:
def __init__(self):
self.configfile = op.configfile
self.cfg = ConfigParser.ConfigParser()
(s,b,p,q,f,o) = urlparse.urlparse(self.configfile)
if s in ('http', 'ftp', 'file'):
configfh = urllib.urlopen(self.configfile)
try:
self.cfg.readfp(configfh)
except ConfigParser.MissingSectionHeaderError, e:
die(6, 'Error accessing URL: %s' % self.configfile)
else:
if os.access(self.configfile, os.R_OK):
try:
self.cfg.read(self.configfile)
except:
die(7, 'Syntax error reading file: %s' % self.configfile)
else:
die(6, 'Error accessing file: %s' % self.configfile)
def getoption(self, section, option, var):
"Get an option from a section from configfile"
try:
var = self.cfg.get(section, option)
info(3, 'Setting option %s in section [%s] to: %s' % (option, section, var))
except ConfigParser.NoSectionError, e:
info(4, 'Failed to find section [%s] in %s' % (section, op.configfile))
except ConfigParser.NoOptionError, e:
# info(4, 'Failed to find option %s in [%s], set to default: %s' % (option, section, var))
info(4, 'Setting option %s in section [%s] to: %s (default)' % (option, section, var))
return var
class dstat:
def init(self):
### Initialise default variables
self.val = {}; self.cn1 = {}; self.cn2 = {}
for i in self.vars: self.val[i] = self.cn1[i] = self.cn2[i] = 0
def varwidth(self):
return len(self.vars) * self.width() + len(self.vars) - 1
def width(self):
if isinstance(self.name, types.StringType):
return self.len
else:
for name in self.cn2.keys():
return len(self.cn2[name]) * self.len + len(self.cn2[name]) - 1
return 0
def title1(self):
if op.csv:
if isinstance(self.name, types.StringType):
return '"' + self.name + '"' + ',' * (len(self.nick) - 1)
else:
ret = ''
for i, name in enumerate(self.name):
ret = ret + '"' + name + '"' + ',' * (len(self.nick) - 1)
if i + 1 != len(self.name): ret = ret + ','
return ret
else:
if isinstance(self.name, types.StringType):
max = self.varwidth()
return ansi['darkblue'] + self.name[0:max].center(max).replace(' ', '-') + ansi['default']
else:
ret = ''
for i, name in enumerate(self.name):
max = self.width()
ret = ret + name[0:max].center(max).replace(' ', '-')
if i + 1 != len(self.name): ret = ret + '-'
return ansi['darkblue'] + ret
def title2(self):
if op.csv:
if isinstance(self.name, types.StringType):
ret = ''
for i, nick in enumerate(self.nick):
ret = ret + '"' + nick + '"'
if i + 1 != len(self.nick): ret = ret + ','
return ret
else:
ret = ''
for i, name in enumerate(self.name):
for j, nick in enumerate(self.nick):
ret = ret + '"' + nick + '"'
if j + 1 != len(self.nick): ret = ret + ','
if i + 1 != len(self.name): ret = ret + ','
return ret
else:
if isinstance(self.name, types.StringType):
ret = ''
for i, nick in enumerate(self.nick):
ret = ret + nick.center(self.len).replace(' ', '_')
if i + 1 != len(self.nick): ret = ret + ' '
return ansi['blue'] + ret
else:
ret = ''
for i, name in enumerate(self.name):
for j, nick in enumerate(self.nick):
ret = ret + ansi['blue'] + nick.center(self.len).replace(' ', '_')
if j + 1 != len(self.nick): ret = ret + ' '
if i + 1 != len(self.name): ret = ret + ' '
return ansi['blue'] + ret
def check(self):
if self.discover() and self.width():
return True
return False
def discover(self):
return True
def stats(self):
pass
def show(self):
sep = ' '
for i, name in enumerate(self.vars):
if self.format in ('%s', '%bs'):
sys.stdout.write('%s' % conv(self.len, self.val[name], 1024))
elif self.format == '%ds':
sys.stdout.write('%s' % conv(self.len, self.val[name], 1000))
elif self.format == '%ps':
sys.stdout.write('%s' % conv(self.len, self.val[name], 100))
elif self.format == '%is':
sys.stdout.write('%s' % conv(self.len, self.val[name], 10))
elif self.format == '%f':
sys.stdout.write('%s' % conv(self.len, self.val[name], 1))
elif self.format in ('%s %s', '%s:%s', '%s-%s'):
sys.stdout.write(self.format % convlist(self.len, self.val[name]))
sep = ansi['default'] + char['colon']
elif self.format in ('%s %s %s', '%s %s %s %s %s %s'):
sys.stdout.write(self.format % convlist(self.len, self.val[name], 100))
sep = ansi['default'] + char['colon']
else:
sys.stdout.write(self.format % self.val[name])
if i + 1 != len(self.vars):
sys.stdout.write(sep)
def showcsv(self):
def printcsv(var):
if var != round(var):
sys.stdout.write('%.2f' % var)
else:
sys.stdout.write('%d' % round(var))
for i, name in enumerate(self.vars):
if isinstance(self.val[name], types.ListType) or isinstance(self.val[name], types.TupleType):
for j, val in enumerate(self.val[name]):
printcsv(val)
if j + 1 != len(self.val[name]):
sys.stdout.write(',')
else:
printcsv(self.val[name])
if i + 1 != len(self.vars):
sys.stdout.write(',')
class dstat_cpu(dstat):
def __init__(self):
self.len = 3
self.format = '%s %s %s %s %s %s'
self.nick = ( 'usr', 'sys', 'idl', 'wai', 'hiq', 'siq' )
self.vars = self.vars()
self.name = []
for name in self.vars:
if name:
self.name.append('cpu' + name + ' usage')
else:
self.name.append('total cpu usage')
self.init()
for name in self.vars: self.cn1[name] = (0, 0, 0, 0, 0, 0); self.cn1[''] = (0, 0, 0, 0, 0, 0)
for name in self.vars: self.cn2[name] = (0, 0, 0, 0, 0, 0); self.cn2[''] = (0, 0, 0, 0, 0, 0)
for name in self.vars: self.val[name] = [0, 0, 0, 0, 0, 0]; self.val[''] = [0, 0, 0, 0, 0, 0]
def discover(self, *list):
ret = []
if os.path.exists('/proc/stat'):
for line in open('/proc/stat', 'r').readlines():
l = line.split()
if len(l) < 8 or l[0][0:3] != 'cpu': continue
ret.append(l[0][3:])
ret.sort()
for item in list: ret.append(item)
return ret
def vars(self):
ret = []
if op.cpulist:
list = op.cpulist
else:
list = ('', )
for name in list:
if name in self.discover(''):
ret.append(name)
return ret
def stats(self):
for line in open('/proc/stat', 'r').readlines():
l = line.split()
for name in self.vars:
if len(l) < 8 or l[0] != 'cpu' + name: continue
self.cn2[name] = ( long(l[1]) + long(l[2]), long(l[3]), long(l[4]), long(l[5]), long(l[6]), long(l[7]) )
for name in self.vars:
for i in (0, 1, 2, 3, 4, 5):
self.val[name][i] = 100.0 * (self.cn2[name][i] - self.cn1[name][i]) / (total(self.cn2[name]) - total(self.cn1[name]))
if step == op.delay:
self.cn1.update(self.cn2)
class dstat_cpu24(dstat):
def __init__(self):
self.len = 3
self.format = '%s %s %s'
self.nick = ( 'usr', 'sys', 'idl')
self.vars = self.vars()
self.name = []
for name in self.vars:
if name:
self.name.append('cpu' + name)
else:
self.name.append('cpu total')
self.init()
for name in self.vars: self.cn1[name] = (0, 0, 0); self.cn1[''] = (0, 0, 0)
for name in self.vars: self.cn2[name] = (0, 0, 0); self.cn2[''] = (0, 0, 0)
for name in self.vars: self.val[name] = [0, 0, 0]; self.val[''] = [0, 0, 0]
def discover(self, *list):
ret = []
if os.path.exists('/proc/stat'):
for line in open('/proc/stat', 'r').readlines():
l = line.split()
if len(l) != 5 or l[0][0:3] != 'cpu': continue
ret.append(l[0][3:])
ret.sort()
for item in list: ret.append(item)
return ret
def vars(self):
ret = []
if op.cpulist:
list = op.cpulist
else:
list = ('',)
for name in list:
if name in self.discover(''):
ret.append(name)
return ret
def stats(self):
for line in open('/proc/stat', 'r').readlines():
l = line.split()
for name in self.vars:
if len(l) < 5 or l[0] != 'cpu' + name: continue
self.cn2[name] = ( long(l[1]) + long(l[2]), long(l[3]), long(l[4]) )
for name in self.vars:
for i in (0, 1, 2):
self.val[name][i] = 100.0 * (self.cn2[name][i] - self.cn1[name][i]) / (total(self.cn2[name]) - total(self.cn1[name]))
if step == op.delay:
self.cn1.update(self.cn2)
class dstat_disk(dstat):
def __init__(self):
self.format = '%s %s'
self.len = 5
self.nick = ('read', 'write')
### Temporary hardcoded for my own project
self.diskset = {
'local': ('sda', 'hda', 'hdc'),
'lores': ('sdb', 'sdc', 'sdd', 'sde', 'sdf', 'sdg', 'sdh', 'sdi', 'sdj', 'sdk', 'sdv', 'sdw', 'sdx', 'sdy', 'sdz', 'sdaa', 'sdab', 'sdac', 'sdad', 'sdae'),
'hires': ('sdl', 'sdm', 'sdn', 'sdo', 'sdp', 'sdq', 'sdr', 'sds', 'sdt', 'sdu', 'sdaf', 'sdag', 'sdah', 'sdai', 'sdaj', 'sdak', 'sdal', 'sdam', 'sdan', 'sdao'),
}
self.vars = self.vars()
self.name = []
for name in self.vars:
self.name.append('disk/' + name)
self.init()
for name in self.vars: self.cn1[name] = (0, 0); self.cn1['total'] = (0, 0)
for name in self.vars: self.cn2[name] = (0, 0); self.cn2['total'] = (0, 0)
for name in self.vars: self.val[name] = [0, 0]; self.val['total'] = [0, 0]
def discover(self, *list):
ret = []
if os.path.exists('/proc/diskstats'):
for line in open('/proc/diskstats', 'r').readlines():
l = line.split()
if len(l) < 13 or l[3] == '0': continue
name = l[2]
if not re.match('^(ram\d+|loop\d+)$', name):
ret.append(name)
# ret.sort()
for item in list: ret.append(item)
return ret
def vars(self):
ret = []
if op.disklist:
list = op.disklist
else:
list = self.discover()
if not op.full and len(list) > 2: list = list[0:2]
list.sort()
for name in list:
if name in self.discover('total') + self.diskset.keys():
ret.append(name)
return ret
def stats(self):
for name in self.vars: self.cn2[name] = (0, 0)
for line in open('/proc/diskstats', 'r').readlines():
l = line.split()
if len(l) < 13: continue
name = l[2]
if name in self.vars:
self.cn2[name] = ( self.cn2[name][0] + long(l[5]), self.cn2[name][1] + long(l[9]) )
for set in self.vars:
if set in self.diskset.keys() and name in self.diskset[set]:
self.cn2[set] = ( self.cn2[set][0] + long(l[5]), self.cn2[set][1] + long(l[9]) )
self.cn2['total'] = ( self.cn2['total'][0] + long(l[5]), self.cn2['total'][1] + long(l[9]) )
if update:
for name in self.cn2.keys():
self.val[name] = (
(self.cn2[name][0] - self.cn1[name][0]) * 512.0 / step,
(self.cn2[name][1] - self.cn1[name][1]) * 512.0 / step,
)
if step == op.delay:
self.cn1.update(self.cn2)
class dstat_disk24(dstat_disk):
def discover(self, *list):
ret = []
if os.path.exists('/proc/partitions') and not os.path.exists('/proc/diskstats'):
for line in open('/proc/partitions', 'r').readlines():
l = line.split()
if len(l) < 15 or l[0] == 'major' or int(l[1]) % 16 != 0: continue
name = l[3]
if not re.match('^(ram\d+|loop\d+|name)$', name):
ret.append(name)
# ret.sort()
for item in list: ret.append(item)
return ret
def vars(self):
ret = []
if op.disklist:
list = op.disklist
else:
list = self.discover()
if not op.full and len(list) > 2: list = list[0:2]
list.sort()
for name in list:
if name in self.discover('total') + self.diskset.keys():
ret.append(name)
return ret
def stats(self):
for name in self.vars: self.cn2[name] = (0, 0)
for line in open('/proc/partitions', 'r').readlines():
l = line.split()
if len(l) < 15: continue
name = l[3]
if name == 'name': continue
if name in self.vars:
self.cn2[name] = ( self.cn2[name][0] + long(l[6]), self.cn2[name][1] + long(l[10]) )
for set in self.vars:
if set in self.diskset.keys() and name in self.diskset[set]:
self.cn2[set] = ( self.cn2[set][0] + long(l[6]), self.cn2[set][1] + long(l[10]) )
self.cn2['total'] = ( self.cn2['total'][0] + long(l[6]), self.cn2['total'][1] + long(l[10]))
if update:
for name in self.cn2.keys():
self.val[name] = (
(self.cn2[name][0] - self.cn1[name][0]) * 512.0 / step,
(self.cn2[name][1] - self.cn1[name][1]) * 512.0 / step,
)
if step == op.delay:
self.cn1.update(self.cn2)
### FIXME: Needs rework, does anyone care ?
class dstat_disk24old(dstat_disk24):
def discover(self, *list):
ret = []
if os.path.exists('/proc/stat') and not os.path.exists('/proc/partitions') and not os.path.exists('/proc/diskstats'):
for line in open('/proc/stat', 'r').readlines():
l = line.split()
if len(l) < 15: continue
ret.append(l[3])
# ret.sort()
for item in list: ret.append(item)
return ret
def vars(self):
ret = []
if op.disklist:
list = op.disklist
else:
list = self.discover()
if not op.full and len(list) > 2: list = list[0:2]
list.sort()
for name in list:
if name in self.discover('total') + self.diskset.keys():
ret.append(name)
return ret
def stats(self):
for name in self.vars: self.cn2[name] = (0, 0)
for line in open('/proc/stat', 'r').readlines():
l = line.split(':')
if len(l) < 3: continue
name = l[0]
if name == 'disk_io':
for pair in line.split()[1:]:
m = re.match('^\((\d+),(\d+)\):\(\d+,\d+,(\d+),\d+,(\d+)\)$', pair)
if m:
l = m.groups()
name = dev(int(l[0]), int(l[1]))
self.cn2[name] = ( long(l[2]), long(l[3]) )
for set in self.vars:
if set in self.diskset.keys() and name in self.diskset[set]:
self.cn2[set] = ( self.cn2[set][0] + long(l[2]), self.cn2[set][1] + long(l[3]) )
self.cn2['total'] = ( self.cn2['total'][0] + long(l[2]), self.cn2['total'][1] + long(l[3]) )
if update:
for name in self.cn2.keys():
self.val[name] = (
(self.cn2[name][0] - self.cn1[name][0]) * 512.0 / step,
(self.cn2[name][1] - self.cn1[name][1]) * 512.0 / step,
)
if step == op.delay:
self.cn1.update(self.cn2)
class dstat_int(dstat):
def __init__(self):
self.len = 5
self.format = '%ds'
self.name = 'interrupts'
self.vars = self.vars()
self.nick = self.vars
self.init()
def discover(self):
ret = []
if os.path.exists('/proc/stat'):
for line in open('/proc/stat', 'r').readlines():
l = line.split()
if l[0] != 'intr': continue
for name, i in enumerate(l[2:]):
if long(i) > 10: ret.append(str(name))
return ret
def vars(self):
ret = []
if op.intlist:
list = op.intlist
else:
list = self.discover()
for name in list:
if name in ('0', '1', '2', '8', 'NMI', 'LOC', 'MIS', 'CPU0'):
list.remove(name)
if not op.full and len(list) > 3: list = list[-3:]
for name in list:
if name in self.discover():
ret.append(name)
return ret
def stats(self):
for line in open('/proc/stat', 'r').readlines():
l = line.split()
if l[0] != 'intr': continue
for name in self.vars:
self.cn2[name] = long(l[int(name) + 2])
if update:
for name in self.vars:
self.val[name] = (self.cn2[name] - self.cn1[name]) * 1.0 / step
if step == op.delay:
self.cn1.update(self.cn2)
class dstat_int24(dstat):
def __init__(self):
self.len = 5
self.format = '%ds'
self.name = 'interrupts'
self.vars = self.vars()
self.nick = self.vars
self.init()
def discover(self):
ret = []
if os.path.exists('/proc/interrupts'):
for line in open('/proc/interrupts', 'r').readlines():
l = line.split()
if len(l) < procs+1: continue
name = l[0].split(':')[0]
if long(l[1]) > 10:
ret.append(name)
return ret
def check(self):
for line in open('/proc/stat', 'r').readlines():
l = line.split()
if l[0] != 'intr' or len(l) > 2: continue
if self.discover():
return True
return False
def vars(self):
ret = []
if op.intlist:
list = op.intlist
else:
list = self.discover()
for name in list:
if name in ('0', '1', '2', '8', 'NMI', 'LOC', 'MIS', 'CPU0'):
list.remove(name)
if not op.full and len(list) > 3: list = list[-3:]
for name in list:
if name in self.discover():
ret.append(name)
return ret
def stats(self):
for line in open('/proc/interrupts', 'r').readlines():
l = line.split()
if len(l) < procs+1: continue
name = l[0].split(':')[0]
if name in self.vars:
self.cn2[name] = 0
for i in l[1:1+procs]:
self.cn2[name] = self.cn2[name] + long(i)
# elif len(l) > 2 + procs:
# for hw in self.vars:
# for mod in l[2+procs:]:
# self.cn2[mod] = long(l[1])
if update:
for name in self.cn2.keys():
self.val[name] = (self.cn2[name] - self.cn1[name]) * 1.0 / step
if step == op.delay:
self.cn1.update(self.cn2)
class dstat_load(dstat):
def __init__(self):
self.len = 4
self.format = '%f'
self.name = 'load avg'
self.vars = ('load1', 'load5', 'load15')
self.nick = ('1m', '5m', '15m')
self.init()
def check(self):
if os.path.exists('/proc/loadavg'):
return True
return False
def stats(self):
for line in open('/proc/loadavg', 'r').readlines():
l = line.split()
if len(l) < 3: continue
self.val['load1'] = float(l[0])
self.val['load5'] = float(l[1])
self.val['load15'] = float(l[2])
class dstat_mem(dstat):
def __init__(self):
self.name = 'memory usage'
self.len = 5
self.format = '%s'
self.vars = ('MemUsed', 'Buffers', 'Cached', 'MemFree')
self.nick = ('used', 'buff', 'cach', 'free')
self.init()
def check(self):
if os.path.exists('/proc/meminfo'):
return True
return False
def stats(self):
for line in open('/proc/meminfo', 'r').readlines():
l = line.split()
if len(l) < 2: continue
name = l[0].split(':')[0]
if name in self.vars + ('MemTotal',):
self.val[name] = long(l[1]) * 1024.0
self.val['MemUsed'] = self.val['MemTotal'] - self.val['MemFree'] - self.val['Buffers'] - self.val['Cached']
class dstat_net(dstat):
def __init__(self):
self.len = 5
self.format = '%s %s'
self.vars = self.vars()
self.name = []
for name in self.vars:
self.name.append('net/' + name)
self.nick = ('recv', 'send')
self.init()
for name in self.vars: self.cn1[name] = (0, 0); self.cn1['total'] = (0, 0)
for name in self.vars: self.cn2[name] = (0, 0); self.cn2['total'] = (0, 0)
for name in self.vars: self.val[name] = [0, 0]; self.val['total'] = [0, 0]
def discover(self, *list):
ret = []
if os.path.exists('/proc/net/dev'):
for line in open('/proc/net/dev', 'r').readlines():
l = line.split()
if len(l) < 2: continue
name = l[0].split(':')[0]
if l[1] == '0': continue
if not re.match('^(Inter-\||face|lo)$', name):
ret.append(name)
ret.sort()
for item in list: ret.append(item)
return ret
def vars(self):
ret = []
if op.netlist:
list = op.netlist
else:
list = self.discover()
if not op.full and len(list) > 2: list = list[0:2]
for name in list:
if name in self.discover('total'):
ret.append(name)
return ret
def stats(self):
self.cn2['total'] = [0, 0]
for line in open('/proc/net/dev', 'r').readlines():
l = line.split()
if len(l) < 1: continue
l2 = l[0].split(':')
if len(l2) < 1: continue
name = l2[0]
if len(l2) > 1 and l2[1].strip():
l = l2[1:] + l[1:]
else:
l = l[1:]
if len(l) < 9: continue
if name in (self.vars) :
self.cn2[name] = ( long(l[0]), long(l[8]) )
if not re.match('^(Inter-\||face|lo)$', name):
self.cn2['total'] = ( self.cn2['total'][0] + long(l[0]), self.cn2['total'][1] + long(l[8]))
if update:
for name in self.cn2.keys():
self.val[name] = (
(self.cn2[name][0] - self.cn1[name][0]) * 1.0 / step,
(self.cn2[name][1] - self.cn1[name][1]) * 1.0 / step,
)
if step == op.delay:
self.cn1.update(self.cn2)
class dstat_page(dstat):
def __init__(self):
self.name = 'paging'
self.format = '%s'
self.len = 5
self.vars = ('pswpin', 'pswpout')
self.nick = ('in', 'out')
self.init()
def check(self):
if os.path.exists('/proc/vmstat'):
return True
return False
def stats(self):
for line in open('/proc/vmstat', 'r').readlines():
l = line.split()
if len(l) < 2: continue
name = l[0]
if name in self.vars:
self.cn2[name] = long(l[1])
if update:
for name in self.vars:
self.val[name] = (self.cn2[name] - self.cn1[name]) * pagesize * 1.0 / step
if step == op.delay:
self.cn1.update(self.cn2)
class dstat_page24(dstat_page):
def check(self):
if os.path.exists('/proc/stat') and not os.path.exists('/proc/vmstat'):
return True
return False
def stats(self):
for line in open('/proc/stat', 'r').readlines():
l = line.split()
if len(l) < 3: continue
name = l[0]
if name == 'swap':
self.cn2['pswpin'] = long(l[1])
self.cn2['pswpout'] = long(l[2])
if update:
for name in self.vars:
self.val[name] = (self.cn2[name] - self.cn1[name]) * pagesize * 1.0 / step
if step == op.delay:
self.cn1.update(self.cn2)
class dstat_proc(dstat):
def __init__(self):
self.name = 'procs'
self.format = '%is'
self.len = 3
self.vars = ('procs_running', 'procs_blocked', 'processes')
# self.vars = ('procs_running', 'procs_blocked')
self.nick = ('run', 'blk', 'new')
# self.nick = ('ru', 'bl')
self.init()
def check(self):
if os.path.exists('/proc/stat'):
return True
return False
def stats(self):
for line in open('/proc/stat', 'r').readlines():
l = line.split()
if len(l) < 2: continue
name = l[0]
if name == 'processes':
self.val['processes'] = 0
self.cn2[name] = long(l[1])
elif name == 'procs_running':
self.cn2[name] = self.cn2[name] + long(l[1]) - 1
elif name == 'procs_blocked':
self.cn2[name] = self.cn2[name] + long(l[1])
if update:
self.val['processes'] = (self.cn2['processes'] - self.cn1['processes']) * 1.0 / step
for name in ('procs_running', 'procs_blocked'):
self.val[name] = self.cn2[name] * 1.0 / step
if step == op.delay:
self.cn1.update(self.cn2)
for name in ('procs_running', 'procs_blocked'):
self.cn2[name] = 0
class dstat_swap(dstat):
def __init__(self):
self.name = 'swap'
self.len = 5
self.format = '%s'
self.vars = ('SwapUsed', 'SwapFree')
self.nick = ('used', 'free')
self.init()
def check(self):
if os.path.exists('/proc/meminfo'):
return True
return False
def stats(self):
for line in open('/proc/meminfo', 'r').readlines():
l = line.split()
if len(l) < 2: continue
name = l[0].split(':')[0]
if name in self.vars + ('SwapTotal',):
self.val[name] = long(l[1]) * 1024.0
self.val['SwapUsed'] = self.val['SwapTotal'] - self.val['SwapFree']
class dstat_sys(dstat):
def __init__(self):
self.name = 'system'
self.format = '%ds'
self.len = 5
self.vars = ('intr', 'ctxt')
self.nick = ('int', 'csw')
self.init()
def check(self):
if os.path.exists('/proc/stat'):
return True
return False
def stats(self):
for line in open('/proc/stat', 'r').readlines():
l = line.split()
if len(l) < 2: continue
name = l[0]
if name in self.vars:
self.cn2[name] = long(l[1])
if update:
for name in self.vars:
self.val[name] = (self.cn2[name] - self.cn1[name]) * 1.0 / step
if step == op.delay:
self.cn1.update(self.cn2)
class dstat_tcp(dstat):
def __init__(self):
self.name = 'tcp'
self.format = '%is'
self.len = 3
self.vars = ('listen', 'established', 'syn_sent', 'time_wait')
self.nick = ('lis', 'act', 'syn', 'tim')
self.init()
def check(self):
if os.path.exists('/proc/net/tcp'):
return True
return False
def stats(self):
self.val['listen'] = self.val['established'] = self.val['syn_sent'] = self.val['time_wait'] = 0
for line in open('/proc/net/tcp', 'r').readlines():
l = line.split()
if len(l) < 12: continue
if l[3] == '0A': self.val['listen'] = self.val['listen'] + 1
elif l[3] == '01': self.val['established'] = self.val['established'] + 1
elif l[3] == '02': self.val['syn_sent'] = self.val['syn_sent'] + 1
elif l[3] == '06': self.val['time_wait'] = self.val['time_wait'] + 1
class dstat_time(dstat):
def __init__(self):
self.name = 'time'
self.format = '%10d'
self.len = 10
### Nice for debugging timer
# self.format = '%13.3f'
# self.len = 14
self.nick = ('epoch',)
self.vars = ('epoch',)
self.init()
def stats(self):
self.val['epoch'] = time.time()
def show(self):
sys.stdout.write(self.format % self.val['epoch'])
class dstat_udp(dstat):
def __init__(self):
self.name = 'udp'
self.format = '%is'
self.len = 3
self.nick = ('con', )
self.vars = ('connections', )
self.init()
def check(self):
if os.path.exists('/proc/net/udp'):
return True
return False
def stats(self):
self.val['connections'] = 0
for line in open('/proc/net/udp', 'r').readlines():
l = line.split()
if l[3] == '07': self.val['connections'] = self.val['connections'] + 1
class dstat_user(dstat):
def __init__(self):
self.name = 'users'
self.format = '%is'
self.len = 3
self.nick = ('usr', 'adm' )
self.vars = ('users', 'root')
self.init()
def check(self):
try:
import utmp
return True
except:
print 'The user stat needs the python-utmp module.'
return False
def stats(self):
import utmp
u = utmp.UtmpRecord()
self.val['users'] = 0
self.val['root'] = 0
for i in u:
if i.ut_type == utmp.USER_PROCESS:
self.val['users'] = self.val['users'] + 1
if i.ut_user == 'root':
self.val['root'] = self.val['root'] + 1
ansi = {
'black': '\033[0;30m',
'darkred': '\033[0;31m',
'darkgreen': '\033[0;32m',
'darkyellow': '\033[0;33m',
'darkblue': '\033[0;34m',
'darkmagenta': '\033[0;35m',
'darkcyan': '\033[0;36m',
'silver': '\033[0;37m',
'gray': '\033[1;30m',
'red': '\033[1;31m',
'green': '\033[1;32m',
'yellow': '\033[1;33m',
'blue': '\033[1;34m',
'magenta': '\033[1;35m',
'cyan': '\033[1;36m',
'white': '\033[1;37m',
'blackbg': '\033[40m',
'redbg': '\033[41m',
'greenbg': '\033[42m',
'yellowbg': '\033[43m',
'bluebg': '\033[44m',
'magentabg': '\033[45m',
'cyanbg': '\033[46m',
'whitebg': '\033[47m',
'reset': '\033[0;0m',
'bold': '\033[1m',
'reverse': '\033[2m',
'underline': '\033[4m',
'clear': '\033[2J',
'clearline': '\033[K',
'save': '\033[s',
'restore': '\033[u',
'up': '\033[1A',
'default': '\033[0;0m',
}
char = {
'pipe': '|',
'colon': ':',
'gt': '>',
'space': ' ',
}
def total(list):
ret = 0
for i in list:
ret = ret + i
return ret
def convlist(max, list, base = 1024):
# max = max / len(list)
retlist = ()
for var in list:
retlist = retlist + (conv(max, var, base), )
return retlist
#def convlist(max, list):
# return map(conv, list)
### Use capabilities like: float=true, base=nr, color=true
def conv(max, var, base = 1024):
if var < 0:
return ansi['default'] + '- '.rjust(max)
if step == op.delay:
color = ('red', 'yellow', 'green', 'blue', 'magenta', 'cyan', 'white', 'darkred', 'darkgreen')
else:
color = ('darkred', 'darkyellow', 'darkgreen', 'darkblue', 'darkmagenta', 'darkcyan', 'silver', 'red', 'green')
if base in (0, 1, 10):
unit = ('', '', '', '', '', '', '', '', '', '', '')
elif base == 100:
if round(var) == 0:
return ansi['default'] + '0'.rjust(max)
else:
return ansi[color[long(round(var)/34)]] + str(long(round(var))).rjust(max)
elif base == 1000:
unit = (' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
elif base == 1024:
### lowercase (b) is better for the eyes than uppercase
unit = ('B', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
else:
return ansi['default'] + '? '.rjust(max)
c = 0
while True:
repr = str(long(round(var))) + unit[c]
if len(repr) <= max:
if not op.integer and (base != 1000 or c > 0):
if var != round(var) and len('%1.2f' % var + unit[c]) <= max:
repr = '%1.2f' % var + unit[c]
elif var != round(var) and len('%1.1f' % var + unit[c]) <= max:
repr = '%1.1f' % var + unit[c]
else:
var = long(round(var))
break
var = var / base
c = c + 1
if var == 0:
return ansi['default'] + ('0' + ' ' * len(unit[0])).rjust(max)
return ansi[color[c]] + repr.rjust(max)
def info(level, str):
"Output info message"
# if level <= op.verbose:
print str
def die(ret, str):
"Print error and exit with errorcode"
info(0, str)
sys.exit(ret)
def getwinsize():
if op.nolimit:
return 1024, 1024
# curses.wrapper(lambda s:curses.setupterm())
# return curses.wrapper(lambda s:curses.tigetnum('lines')), curses.wrapper(lambda s:curses.tigetnum('cols'))
try:
s = struct.pack('HHHH', 0, 0, 0, 0)
x = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, s)
return struct.unpack('HHHH', x)[:2]
except:
try:
return int(os.environ['LINES']), int(os.environ['COLUMNS'])
except:
return 25, 80
def getcpunr():
procs = -1
for line in open('/proc/stat', 'r').readlines():
if line[0:3] == 'cpu':
procs = procs + 1
return procs
def scsidev(nr):
if nr < 26:
return 'sd' + chr(ord('a') + nr)
else:
return 'sd' + chr(ord('a') - 1 + nr / 26) + chr(ord('a') + nr % 26)
def dev(maj, min):
scsi = [8, 65, 66, 67, 68, 69, 70, 71, 128, 129, 130, 131, 132, 133, 134, 135]
ide = [3, 22, 33, 34, 56, 57, 88, 89, 90, 91]
if maj in scsi:
nr = scsi.index(maj) * 16 + min
# nr = scsi.index(maj) * 16 + min / 16
return scsidev(nr)
elif maj in ide:
nr = ide.index(maj) * 2 + min / 64
return 'hd' + chr(ord('a') + nr)
#def mountpoint(dev):
# "Return the mountpoint of a mounted device/file"
# for entry in open('/etc/mtab', 'r').readlines():
# if entry:
# list = entry.split()
# if dev == list[0]:
# return list[1]
def signaler(signum, frame):
signal.alarm(interval)
def main():
global update, loop, step, pagesize, procs, ansi, interval
loop = update = 0
step = op.delay
pagesize = resource.getpagesize()
procs = getcpunr()
# hz = os.sysconf('SC_CLK_TCK')
interval = 1
if not op.update:
interval = op.delay
### Build list of requested modules
olist = []
for mod in op.modlist:
if mod == 'cpu':
olist.append(dstat_cpu())
olist.append(dstat_cpu24())
elif mod == 'disk':
olist.append(dstat_disk())
olist.append(dstat_disk24())
olist.append(dstat_disk24old())
elif mod == 'int':
olist.append(dstat_int())
olist.append(dstat_int24())
elif mod == 'load': olist.append(dstat_load())
elif mod == 'mem': olist.append(dstat_mem())
elif mod == 'net': olist.append(dstat_net())
elif mod == 'page':
olist.append(dstat_page())
olist.append(dstat_page24())
elif mod == 'proc': olist.append(dstat_proc())
elif mod == 'swap': olist.append(dstat_swap())
elif mod == 'sys': olist.append(dstat_sys())
elif mod == 'tcp': olist.append(dstat_tcp())
elif mod == 'time': olist.append(dstat_time())
elif mod == 'udp': olist.append(dstat_udp())
elif mod == 'user': olist.append(dstat_user())
else:
info(1, 'Module \'%s\' does not exist or failed to load.' % mod)
### Check terminal capabilities
# if not sys.stdout.isatty() or not curses.wrapper(lambda s:curses.has_colors()):
if not sys.stdout.isatty() or os.environ.get('TERM',None) not in ('ansi', 'linux', 'rxvt', 'screen', 'screen-w', 'xterm'):
op.color = False
op.nolimit = True
op.update = False
rows, cols = getwinsize()
### Empty ansi database if no colors are requested
if not op.color:
op.update = False
for key in ansi.keys():
ansi[key] = ''
if op.csv:
for key in char.keys():
char[key] = ','
### Remove defect objects and calculate line length
linewidth = 0
for o in olist + []:
if o.check():
linewidth = linewidth + o.varwidth() + 1
else:
olist.remove(o)
if not olist:
die(8, 'None of the stats you selected are available.')
if not op.nolimit:
if linewidth > cols:
print 'Screen width too small, trimming output.'
if op.csv:
import socket
print '"Dstat %s CSV output"' % VERSION
print '"Author:","Dag Wieers <dag@wieers.com>",,,,"URL:","http://dag.wieers.com/home-made/dstat/"'
print '"Host:","%s",,,,"Date:","%s"' % (socket.gethostbyaddr(socket.gethostname())[0], time.strftime('%d %b %Y %H:%M:%S %Z', time.localtime()))
print '"Cmd:","dstat %s"\n' % ' '.join(op.args)
oldplist = []
### Increase precision if we're root (does not have effect)
# if os.geteuid() == 0:
# os.nice(-20)
# sys.setcheckinterval(op.delay / 10000)
signal.signal(signal.SIGALRM, signaler)
signal.alarm(interval)
### Always show header the first time
showheader = True
### Let the games begin
while update <= op.delay * op.count or op.count == -1:
### Trim object list to what is visible on screen
(rows, cols) = getwinsize()
plist = []
curwidth = 0
for o in olist:
if curwidth + o.varwidth() + 1 <= cols:
plist.append(o)
curwidth = curwidth + o.varwidth() + 1
### Check when to display the header
if op.header:
if oldplist != plist:
showheader = True
elif step == 1 and loop % (rows - 1) == 0:
showheader = True
if showheader:
showheader = False
for o in plist:
sys.stdout.write(o.title1())
if o is not plist[-1]:
sys.stdout.write(ansi['darkblue'] + char['space'])
elif olist != plist:
sys.stdout.write(ansi['darkblue'] + char['gt'])
sys.stdout.write('\n')
for o in plist:
sys.stdout.write(o.title2())
if o is not plist[-1]:
sys.stdout.write(ansi['silver'] + char['pipe'])
elif olist != plist:
sys.stdout.write(ansi['darkblue'] + char['gt'])
sys.stdout.write('\n')
oldplist = plist
### Prepare the colors for intermediate updates, last step in a loop is definitive
if step == op.delay:
ansi['default'] = ansi['reset']
else:
ansi['default'] = ansi['gray']
sys.stdout.write(ansi['default'])
### Debugging info
# sys.stdout.write('[%d:%d:%d]' % (loop, step, update))
### Show the stats, calculate all objects (visible, invisible)
for o in olist:
o.stats()
if o in plist:
if op.csv:
o.showcsv()
else:
o.show()
if o is not plist[-1]:
sys.stdout.write(ansi['default'] + char['pipe'])
elif o is not olist[-1]:
sys.stdout.write(ansi['default'] + char['gt'])
sys.stdout.write(ansi['default'])
### If intermediate results, update increases with 1 sec (=interval)
update = update + interval
### Do not pause when this is the final loop
if update <= op.delay * op.count or op.count == -1:
signal.pause()
### The last step in a loop is to show the definitive line on its own line
if step == op.delay:
sys.stdout.write('\n' + ansi['reset'] + ansi['clearline'] + ansi['save'])
else:
sys.stdout.write(ansi['clearline'] + ansi['restore'])
loop = (update + op.delay - 1) / op.delay
step = ((update - 1) % op.delay) + 1
### Unbuffered sys.stdout
sys.stdout = os.fdopen(1, 'w', 0)
### Workaround for python <= 2.2.1
try:
True, False
except NameError:
True = 1
False = 0
Yes = yes = On = on = True
No = no = Off = off = False
### Workaround for python < 2.3
def enumerate(sequence):
index = 0
for item in sequence:
yield index, item
index = index + 1
### Main entrance
if __name__ == '__main__':
op=Options(sys.argv[1:])
# cf=Config()
try:
main()
except KeyboardInterrupt, e:
signal.signal(signal.SIGALRM, signal.SIG_DFL)
print ansi['reset']
except OSError, e:
signal.signal(signal.SIGALRM, signal.SIG_DFL)
# print e.errno
print
print ansi['reset'] + 'OSError: %s' %e
sys.exit(7)
sys.exit(0)
# vim:ts=4:sw=4
Jump to Line
Something went wrong with that request. Please try again.