Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

- Added theming support (not exposed to users yet)

- Added --bw/--blackonwhite option to use dark colors on white background
- Allow any plugin to be added by long options (ie. --topbio)
  • Loading branch information...
commit f7381d9da7dcc10da179ca7e36a935fe6fc513a1 1 parent d62de5a
Dag Wieers authored
Showing with 494 additions and 246 deletions.
  1. +4 −1 ChangeLog
  2. +4 −4 TODO
  3. +59 −35 docs/dstat-paper.txt
  4. +5 −2 docs/dstat.1
  5. +4 −1 docs/dstat.1.txt
  6. +253 −135 dstat
  7. +9 −4 examples/mstat.py
  8. +8 −4 examples/read.py
  9. +3 −1 plugins/dstat_battery.py
  10. +3 −1 plugins/dstat_cpufreq.py
  11. +3 −1 plugins/dstat_dbus.py
  12. +3 −1 plugins/dstat_fan.py
  13. +3 −1 plugins/dstat_freespace.py
  14. +3 −1 plugins/dstat_gpfs.py
  15. +3 −1 plugins/dstat_gpfsop.py
  16. +3 −1 plugins/dstat_helloworld.py
  17. +3 −1 plugins/dstat_innodb_buffer.py
  18. +3 −1 plugins/dstat_innodb_io.py
  19. +3 −1 plugins/dstat_innodb_ops.py
  20. +3 −1 plugins/dstat_lustre.py
  21. +3 −1 plugins/dstat_mysql5_com.py
  22. +3 −1 plugins/dstat_mysql5_conn.py
  23. +3 −1 plugins/dstat_mysql5_io.py
  24. +3 −1 plugins/dstat_mysql5_keys.py
  25. +3 −1 plugins/dstat_mysql_io.py
  26. +3 −1 plugins/dstat_mysql_keys.py
  27. +3 −1 plugins/dstat_net_packets.py
  28. +3 −1 plugins/dstat_nfs3.py
  29. +3 −1 plugins/dstat_nfs3op.py
  30. +3 −1 plugins/dstat_nfsd3.py
  31. +3 −1 plugins/dstat_nfsd3op.py
  32. +4 −2 plugins/dstat_ntp.py
  33. +3 −1 plugins/dstat_postfix.py
  34. +3 −1 plugins/dstat_power.py
  35. +3 −1 plugins/dstat_rpc.py
  36. +3 −1 plugins/dstat_rpcd.py
  37. +3 −1 plugins/dstat_sendmail.py
  38. +3 −1 plugins/dstat_snooze.py
  39. +3 −1 plugins/dstat_thermal.py
  40. +6 −4 plugins/dstat_topbio.py
  41. +6 −4 plugins/dstat_topcpu.py
  42. +7 −5 plugins/dstat_topio.py
  43. +5 −3 plugins/dstat_topmem.py
  44. +6 −4 plugins/dstat_topoom.py
  45. +3 −1 plugins/dstat_utmp.py
  46. +3 −1 plugins/dstat_vmkhba.py
  47. +3 −1 plugins/dstat_vmkint.py
  48. +3 −1 plugins/dstat_vmknic.py
  49. +3 −1 plugins/dstat_vmmemctl.py
  50. +3 −1 plugins/dstat_vzcpu.py
  51. +3 −1 plugins/dstat_vzubc.py
  52. +3 −1 plugins/dstat_wifi.py
5 ChangeLog
View
@@ -1,4 +1,4 @@
-* 0.6.9svn - ... - release 28/05/2009
+* 0.6.9svn - Tokyo - release 28/05/2009
- Fixed dstat_disk plugin for total calculation on 2.6.25+ kernels (Noel J. Bergman)
- Precompile regular expressions used as a disk filter (self.diskfilter)
- Raise a warning when discovery returns empty
@@ -13,6 +13,9 @@
- Drop support for Python 1.5
- Introduced splitlines() function that allows a replace/split on readlines()
- Added external dstat_fan plugin to show fan speed
+- Added theming support (not exposed to users yet)
+- Added --bw/--blackonwhite option to use dark colors on white background
+- Allow any plugin to be added by long options (ie. --topbio)
* 0.6.9 - Locarno - release 02/12/2008
- Input text color is now gray (again)
8 TODO
View
@@ -31,7 +31,9 @@ contact me as well. :) Send an email to: Dag Wieers <dag@wieers.com>
### Extending statistics (help welcome!)
+ Add slab plugin (see /proc/slabinfo and slabtop)
+ Add xorg plugin (xdpyinfo, xrestop)
-+ Add icmp and ntp plugin ?
+ - Add 'most expensive X app' (look at xrestop)
+ - Add number of (active) X sessions and X clients
++ Add icmp plugin ?
+ Add application plugin (-a or -A pid,cmd)
+ Add user plugin (number of users logged on, utmp is not that useful, /proc/key-users)
+ Look into interfacing with apps (bind, sendmail, postfix, squid, amavisd, laus, samba)
@@ -42,8 +44,6 @@ contact me as well. :) Send an email to: Dag Wieers <dag@wieers.com>
+ Allow for SNMP counters to be added
+ Add LVM stats
+ Add 'most expensive io app' based on /proc/pid/io (topio_ops)
-+ Add 'most expensive X app' (look at xrestop)
-+ Add number of (active) X sessions and X clients
+ Allow to have multiple '1st expensive ... app' and '2nd expensive ... app'
+ Add 'most iowaiting app' plugin
@@ -58,7 +58,7 @@ contact me as well. :) Send an email to: Dag Wieers <dag@wieers.com>
+ Implement better (?) protection against counter rollovers (see mail from Sebastien Prud'homme)
### Plugin issues
-+ plugins that use /proc/pid are reasonably slow
++ plugins that use /proc/pid are reasonably slow (implement in C and cache file-content between plugins)
+ disk plugin: /proc/partitions can have negative numbers, seen on systems with long uptime. dstat handles this except for calculating the very first stat, no work-around possible?
+ proc plugin: (run and blk) does not work on 2.4.24+, to be confirmed
+ swap plugin: (new one) is slower than swapold
94 docs/dstat-paper.txt
View
@@ -1,6 +1,6 @@
= Dstat: plugin-based real-time monitoring
Dag Wieers <dag@wieers.com>
-5767, Thu Aug 2 2007
+$Id$
== Introduction
Many tools exist to monitor hardware resources and software behaviour, but few
@@ -78,7 +78,7 @@ counters in the shifted output.
=== Colour highlighting units
-After I added colours to help improve indicating unites, I noticed that the
+After I added colours to help improve indicating units, I noticed that the
colours also helped to show patterns. This of course is very limited,
nevertheless it instantly shows when numbers are flat or changes are taking
place.
@@ -178,24 +178,29 @@ as a self-contained file to other systems.
The plugins that have been selected to be part of the Dstat tool itself, and
therefor have no dependencies other than procfs, are:
- - cpu, cpu24: CPU counters
- - disk, disk24, disk24old: disk counters
- - epoch: seconds since Epoch
- - int, int24: interrupts per IRQ
+ - aio: asynchronous I/O counters
+ - cpu, cpu24: CPU counters (+-c+ and +-C+)
+ - disk, disk24, disk24old: disk counters (+-d+ and +-D+)
+ - epoch: seconds since Epoch (+-T+)
+ - fs: file system counters
+ - int, int24: interrupts per IRQ (+-i+ and +-I+)
+ - io: I/O requests completed (+-r+)
- ipc: IPC counters
- - load: load counters
+ - load: load counters (+-l+)
- lock: locking counters
- - mem: memory usage
- - net: network usage
- - page, page24: paging counters
- - proc: process counters
+ - mem: memory usage (+-m+)
+ - net: network usage (+-n+ and +-N+)
+ - page, page24: paging counters (+-g+)
+ - proc: process counters (+-p+)
- raw: raw socket counters
- - swap, swapold: swap usage
- - sys: system (kernel) counters
+ - swap, swapold: swap usage (+-s+ and +-S+)
+ - socket: socket counters
+ - sys: system (kernel) countersA (+-y+)
- tcp: TCP socket counters
- - time: date and time
+ - time: date and time (+-t+)
- udp: UDP socket counters
- unix: unix socket counters
+ - vm: virtual memory counters
For backward compatibility with older kernels there is a cascading system that
selects the most appropriate internal plugin for your kernel. (eg. the
@@ -205,29 +210,41 @@ moment there is no such system for external plugins.
=== External plugins
This basic functionality is easily extended by writing your own plugins
-(subclasses of the Dstat class) which are then inserted at runtime
+(subclasses of the python Dstat class) which are then inserted at runtime
into Dstat. A set of 'external' modules exist for:
- battery: battery usage
- cpufreq: CPU frequency
- dbus: DBUS connections
+ - fan: Fan speed
- freespace: free space on filesystems
- gpfsop: GPFS operations counters
- gpfs: GPFS IO counters
+ - helloworld: Hello world dispenser
+ - innodb_buffer: innodb buffer counters
- innodb_io: innodb I/O counters
- innodb_keys: innodb key operation counters
- innodb_ops: innodb operations counters
+ - lustre: lustre throughput counters
+ - memcache_hits: Memcache hit counters
+ - mysql5_com: MySQL communication counters
+ - mysql5_conn: MySQL connection counters
+ - mysql5_io: MySQL I/O counters
+ - mysql5_keys: MySQL keys counters
- mysql_io: MySQL I/O counters
- mysql_ops: MySQL operations counters
- nfs3op: NFS3 client operations counters
- nfs3: NFS3 client counters
- nfsd3op: NFS3 server operations counters
- nfsd3: NFS3 server counters
+ - ntp: NTP time counters
- postfix: postfix queue counters
+ - power: Power usage counters
- rpcd: RPC server counters
- rpc: RPC client counters
- sendmail: sendmail queue counters
- - thermal: thermal counters
+ - snooze: Dstat time delay counters
+ - thermal: Thermal counters
- topbio: most expensive block I/O process
- topcpu: most expensive cpu process
- topio: most expensive I/O process
@@ -236,6 +253,8 @@ into Dstat. A set of 'external' modules exist for:
- utmp: utmp counters
- vmkhba: VMware kernel HBA counters
- vmkint: VMware kernel interrupt counters
+ - vmknic: VMware kernel NIC counters
+ - vmmemctl: VMware guest memory counters
- vzcpu: OpenVZ CPU counters
- vzubc: OpenVZ user beancounters
- wifi: WIFI quality information
@@ -414,7 +433,7 @@ bad performance with hardware interrupts, you can run a command like:
----
dstat -tyif
-dstat -tyi -I 12,58,ipw2200 -f 5
+dstat -tyi -I 12,58,iwlagn -f 5
----
=== How much ticks per second on my kernel ?
@@ -456,7 +475,7 @@ devices is generating. The 'cpu' stats already show this in percentage as
number of interrupts, but the 'int' stats go into detail. And you can specify
exactly what IRQs you want to watch.
-Much like +watch -n1 -d cat /proc/interrupts+ on speed.
+Much like +watch -n1 -d cat /proc/interrupts+ on steroids.
----
dstat -t -y -i -f
@@ -536,25 +555,28 @@ output.
class dstat_helloworld(dstat):
def __init__(self):
self.name = 'plugin title' <1>
- self.format = ('s', 12, 100) <2>
- self.nick = ('counter',) <3>
- self.vars = ('text',) <4>
- self.init(self.vars, 1) <5>
+ self.type = 's' <2>
+ self.width = 12 <3>
+ self.scale = 100 <4>
+ self.nick = ('counter',) <5>
+ self.vars = ('text',) <6>
+ self.init(self.vars, 1) <7>
def extract(self):
- self.val['text'] = 'Hello world!' <6>
+ self.val['text'] = 'Hello world!' <8>
----
In this example, there are several components:
. +self.name+ contains the plugin's visible title.
- . +self.format+ is a list containing: the counter type, the counter length
- and how the colouring is done.
- . +self.nick+ is a list of the counter names.
- . +self.vars+ is a list of the variable names for each counter.
+ . +self.type+ defines the counter type: string, percentage, integer, float
+ . +self.width+ defines the column width
+ . +self.scale+ influences the coloring and unit type
+ . +self.nick+ is a list of the counter names
+ . +self.vars+ is a list of the variable names for each counter
. +self.init()+ is a function that initialises the counter structures
- (+self.cn1+, +self.cn2+ and +self.val+).
- . +self.val+ contains the counter values that are being displayed.
+ (+self.cn1+, +self.cn2+ and +self.val+)
+ . +self.val+ contains the counter values that are being displayed
=== Parsing counters
@@ -570,7 +592,9 @@ import glob
class dstat_postfix(dstat):
def __init__(self):
self.name = 'postfix'
- self.format = ('d', 4, 100) <2>
+ self.type = 'd' <2>
+ self.width = 4
+ self.scale = 100
self.vars = ('incoming', 'active', 'deferred', 'bounce', 'defer')
self.nick = ('inco', 'actv', 'dfrd', 'bnce', 'defr')
self.init(self.vars, 1)
@@ -588,12 +612,12 @@ class dstat_postfix(dstat):
This example shows the following items:
. Since the plugin is imported at runtime, it is important that these are
- are included in the global scope to reuse them.
- . +self.format+ indicates values are in decimal, counters are 4 characters
- wide and colouring differs every multiplication of 100.
- . The +check()+ method tests conditions and bails out of they are not met.
+ are included in the global scope to reuse them
+ . type, width and scale specify decimal, column width a,d coloring based on
+ multiplication of 100
+ . The +check()+ method tests conditions and bails out of they are not met
. To make processing easier we have opted to use as value names (+self.vars+)
- the name of the postfix queues and store counts in +self.val+.
+ the name of the postfix queues and store counts in +self.val+
=== Opening files
7 docs/dstat.1
View
@@ -2,7 +2,7 @@
.\" It was generated using the DocBook XSL Stylesheets (version 1.69.1).
.\" Instead of manually editing it, you probably should edit the DocBook XML
.\" source for it and then use the DocBook XSL Stylesheets to regenerate it.
-.TH "DSTAT" "1" "04/10/2009" "" ""
+.TH "DSTAT" "1" "10/21/2009" "" ""
.\" disable hyphenation
.nh
.\" disable justification (adjust text to left margin only)
@@ -117,8 +117,11 @@ enable unix stats (datagram, stream, listen, active)
\-\-vm
enable vm stats (hard pagefaults, soft pagefaults, allocated, free))
.TP
+\-\-stat1 \-\-stat2
+enable internal and external plugin stats by plugin name
+.TP
\-M stat1,stat2
-enable internal and external plugin stats
+enable internal and external plugin stats by plugin name
.TP
Possible internal stats are
aio, cpu, cpu24, disk, disk24, disk24old, epoch, fs, int, int24, io, ipc, load, lock, mem, net, page, page24, proc, raw, socket, swap, swapold, sys, tcp, time, udp, unix, vm
5 docs/dstat.1.txt
View
@@ -124,8 +124,11 @@ information.
--vm::
enable vm stats (hard pagefaults, soft pagefaults, allocated, free))
+--stat1 --stat2::
+ enable internal and external plugin stats by plugin name
+
-M stat1,stat2::
- enable internal and external plugin stats
+ enable internal and external plugin stats by plugin name
Possible internal stats are::
aio, cpu, cpu24, disk, disk24, disk24old, epoch, fs, int, int24, io, ipc,
388 dstat
View
@@ -18,9 +18,11 @@ from __future__ import generators
VERSION = '0.6.9svn'
+theme = { 'default': '' }
+
def inspath(path):
if os.path.isdir(path) and path not in sys.path:
- sys.path.insert(1, path)
+ sys.path.insert(0, path)
try:
import sys, os, time, sched, re
@@ -73,6 +75,7 @@ if sys.version_info < (2, 3):
class Options:
def __init__(self, args):
self.args = args
+ self.blackonwhite = False
self.count = -1
self.cpulist = None
self.debug = 0
@@ -89,6 +92,12 @@ class Options:
self.output = False
self.pidfile = False
+ ### List of available modules
+ self.modules = listmodules()
+
+ ### List of modules to show
+ self.modlist = []
+
### Implicit if no terminal is used
if not sys.stdout.isatty():
self.color = False
@@ -104,80 +113,57 @@ class Options:
try:
import getopt
- opts, args = getopt.getopt (args, 'acdfghilmno:prstTvyC:D:I:M:N:S:V',
- ['aio', 'cpu', 'disk', 'epoch', 'fs', 'filesystem', 'int', 'io', 'ipc',
- 'load', 'lock', 'mem', 'net', 'page', 'proc', 'raw', 'socket', 'swap',
- 'sys', 'tcp', 'time', 'udp', 'unix', 'vm',
- 'all', 'debug', 'full', 'help', 'integer', 'list', 'mods', 'modules',
- 'nocolor', 'noheaders', 'noupdate', 'output=', 'pidfile=', 'version',
- 'vmstat'])
+ opts, args = getopt.getopt(args, 'acdfghilmno:prstTvyC:D:I:M:N:S:V',
+ ['all', 'bw', 'blackonwhite', 'debug', 'filesystem', 'full',
+ 'help', 'integer', 'list', 'mods', 'modules', 'nocolor',
+ 'noheaders', 'noupdate', 'output=', 'pidfile=', 'version',
+ 'vmstat'] + self.modules)
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']:
+ if opt in ['-c']:
self.modlist.append('cpu')
elif opt in ['-C']:
self.cpulist = arg.split(',')
- elif opt in ['-d', '--disk']:
+ elif opt in ['-d']:
self.modlist.append('disk')
elif opt in ['-D']:
self.disklist = arg.split(',')
- elif opt in ['-g', '--page']:
+ elif opt in ['--filesystem']:
+ self.modlist.append('fs')
+ elif opt in ['-g']:
self.modlist.append('page')
- elif opt in ['-i', '--int']:
+ elif opt in ['-i']:
self.modlist.append('int')
elif opt in ['-I']:
self.intlist = arg.split(',')
- elif opt in ['-l', '--load']:
+ elif opt in ['-l']:
self.modlist.append('load')
- elif opt in ['-m', '--mem']:
+ elif opt in ['-m']:
self.modlist.append('mem')
elif opt in ['-M', '--mods', '--modules']:
self.modlist = self.modlist + arg.split(',')
- elif opt in ['-n', '--net']:
+ elif opt in ['-n']:
self.modlist.append('net')
elif opt in ['-N']:
self.netlist = arg.split(',')
- elif opt in ['-p', '--proc']:
+ elif opt in ['-p']:
self.modlist.append('proc')
- elif opt in ['-r', '--io']:
+ elif opt in ['-r']:
self.modlist.append('io')
- elif opt in ['-s', '--swap']:
+ elif opt in ['-s']:
self.modlist.append('swap')
elif opt in ['-S']:
self.swaplist = arg.split(',')
- elif opt in ['-t', '--time']:
+ elif opt in ['-t']:
self.modlist.append('time')
- elif opt in ['-T', '--epoch']:
+ elif opt in ['-T']:
self.modlist.append('epoch')
- elif opt in ['-y', '--sys']:
+ elif opt in ['-y']:
self.modlist.append('sys')
- elif opt in ['--aio']:
- self.modlist.append('aio')
- elif opt in ['--fs', '--filesystem']:
- self.modlist.append('fs')
- elif opt in ['--ipc']:
- self.modlist.append('ipc')
- elif opt in ['--lock']:
- self.modlist.append('lock')
- elif opt in ['--raw']:
- self.modlist.append('raw')
- elif opt in ['--socket']:
- self.modlist.append('socket')
- elif opt in ['--tcp']:
- self.modlist.append('tcp')
- elif opt in ['--udp']:
- self.modlist.append('udp')
- elif opt in ['--unix']:
- self.modlist.append('unix')
- elif opt in ['--vm']:
- self.modlist.append('vm')
-
elif opt in ['-a', '--all']:
self.modlist = self.modlist + [ 'cpu', 'disk', 'net', 'page', 'sys' ]
elif opt in ['-v', '--vmstat']:
@@ -185,12 +171,14 @@ class Options:
elif opt in ['-f', '--full']:
self.full = True
+ elif opt in ['--bw', '--black-on-white']:
+ self.blackonwhite = True
elif opt in ['--debug']:
self.debug = self.debug + 1
elif opt in ['--integer']:
self.integer = True
elif opt in ['--list']:
- listmodules()
+ showmodules()
sys.exit(0)
elif opt in ['--nocolor']:
self.color = False
@@ -210,6 +198,11 @@ class Options:
elif opt in ['-V', '--version']:
self.version()
sys.exit(0)
+ elif opt.startswith('--'):
+ self.modlist.append(opt[2:])
+ else:
+ print 'dstat: option %s unknown to getopt, try dstat -h for a list of all the options' % opt
+ sys.exit(1)
if not self.modlist:
self.modlist = [ 'cpu', 'disk', 'net', 'page', 'sys' ]
@@ -249,7 +242,7 @@ class Options:
global op
op = self
- listmodules()
+ showmodules()
def usage(self):
print 'Usage: dstat [-afv] [options..] [delay [count]]'
@@ -297,6 +290,7 @@ Dstat options:
-f, --full expand -C, -D, -I, -N and -S discovery lists
-v, --vmstat equals -pmgdsc -D total
+ --bw, --blackonwhite change colors for white background terminal
--integer show integer values
--nocolor disable colors (implies --noupdate)
--noheaders disable repetitive headers
@@ -313,7 +307,9 @@ class dstat:
vars = None
name = None
nick = None
- format = ()
+ type = 'f'
+ width = 4
+ scale = 1000
### Initialise default variables
def init(self, vars=(), len=0):
@@ -360,49 +356,49 @@ class dstat:
def statwidth(self):
"Return complete stat width"
- return len(self.vars) * self.width() + len(self.vars) - 1
+ return len(self.vars) * self.colwidth() + len(self.vars) - 1
- def width(self):
+ def colwidth(self):
"Return column width"
if isinstance(self.name, types.StringType):
- return self.format[1]
+ return self.width
else:
- return len(self.nick) * self.format[1] + len(self.nick) - 1
+ return len(self.nick) * self.width + len(self.nick) - 1
- def title(self, nr):
+ def printtitle(self, nr):
if nr == 1:
- return self.title1()
+ return self.title()
else:
- return self.title2()
+ return self.subtitle()
- def title1(self):
- ret = ansi['darkblue']
+ def title(self):
+ ret = theme['title']
if isinstance(self.name, types.StringType):
maxlen = self.statwidth()
- return ret + self.name[0:maxlen].center(maxlen).replace(' ', '-') + ansi['default']
+ return ret + self.name[0:maxlen].center(maxlen).replace(' ', '-') + theme['default']
for i, name in enumerate(self.name):
- maxlen = self.width()
+ maxlen = self.colwidth()
ret = ret + name[0:maxlen].center(maxlen).replace(' ', '-')
if i + 1 != len(self.name):
if op.color:
- ret = ret + ansi['blue'] + char['dash'] + ansi['darkblue']
+ ret = ret + theme['frame'] + char['dash'] + theme['title']
else:
ret = ret + char['space']
return ret
- def title2(self):
+ def subtitle(self):
ret = ''
if isinstance(self.name, types.StringType):
for i, nick in enumerate(self.nick):
- ret = ret + ansi['blue'] + ansi['underline'] + nick.center(self.format[1]) + ansi['default']
+ ret = ret + theme['subtitle'] + nick.center(self.width) + theme['default']
if i + 1 != len(self.nick): ret = ret + char['space']
return ret
else:
for i, name in enumerate(self.name):
for j, nick in enumerate(self.nick):
- ret = ret + ansi['blue'] + ansi['underline'] + nick.center(self.format[1]) + ansi['default']
+ ret = ret + theme['subtitle'] + nick.center(self.width) + theme['default']
if j + 1 != len(self.nick): ret = ret + char['space']
- if i + 1 != len(self.name): ret = ret + ansi['gray'] + char['colon']
+ if i + 1 != len(self.name): ret = ret + theme['frame'] + char['colon']
return ret
def titlecsv(self, nr):
@@ -444,7 +440,7 @@ class dstat:
raise Exception, 'No objects found, no stats available'
if not self.discover:
raise Exception, 'No objects discovered, no stats available'
- if self.width():
+ if self.colwidth():
return True
raise Exception, 'Unknown problem, please report'
@@ -456,10 +452,10 @@ class dstat:
line = ''
for i, name in enumerate(self.vars):
if isinstance(self.val[name], types.TupleType) or isinstance(self.val[name], types.ListType):
- line = line + cprintlist(self.val[name], self.format)
- sep = ansi['gray'] + char['colon']
+ line = line + cprintlist(self.val[name], self.type, self.width, self.scale)
+ sep = theme['frame'] + char['colon']
else:
- line = line + cprint(self.val[name], self.format)
+ line = line + cprint(self.val[name], self.type, self.width, self.scale)
sep = char['space']
if i + 1 != len(self.vars):
line = line + sep
@@ -467,9 +463,9 @@ class dstat:
def showend(self, totlist, vislist):
if self is not vislist[-1]:
- return ansi['gray'] + char['pipe']
+ return theme['frame'] + char['pipe']
elif totlist != vislist:
- return ansi['gray'] + char['gt']
+ return theme['frame'] + char['gt']
return ''
def showcsv(self):
@@ -503,7 +499,8 @@ class dstat:
class dstat_aio(dstat):
def __init__(self):
self.name = 'async'
- self.format = ('d', 5, 1000)
+ self.type = 'd'
+ self.width = 5;
self.open('/proc/sys/fs/aio-nr')
self.nick = ('#aio',)
self.vars = ('aio',)
@@ -516,7 +513,9 @@ class dstat_aio(dstat):
class dstat_cpu(dstat):
def __init__(self):
- self.format = ('p', 3, 34)
+ self.type = 'p'
+ self.width = 3
+ self.scale = 34
self.open('/proc/stat')
self.nick = ( 'usr', 'sys', 'idl', 'wai', 'hiq', 'siq' )
self.discover = self.discover()
@@ -578,7 +577,9 @@ class dstat_cpu(dstat):
class dstat_cpu24(dstat):
def __init__(self):
- self.format = ('p', 3, 34)
+ self.type = 'p'
+ self.width = 3
+ self.scale = 34
self.open('/proc/stat')
self.nick = ( 'usr', 'sys', 'idl')
self.discover = self.discover()
@@ -635,7 +636,9 @@ class dstat_cpu24(dstat):
class dstat_disk(dstat):
def __init__(self):
- self.format = ('f', 5, 1024)
+ self.type = 'f'
+ self.width = 5
+ self.scale = 1024
self.diskfilter = re.compile('^(dm-[0-9]+|md[0-9]+|[hs]d[a-z]+[0-9]+)$')
self.open('/proc/diskstats')
self.nick = ('read', 'writ')
@@ -702,7 +705,9 @@ class dstat_disk(dstat):
class dstat_disk24(dstat):
def __init__(self):
- self.format = ('f', 5, 1024)
+ self.type = 'f'
+ self.width = 5
+ self.scale = 1024
self.diskfilter = re.compile('(dm-[0-9]+|md[0-9]+|[hs]d[a-z]+[0-9]+)')
self.open('/proc/partitions')
self.nick = ('read', 'writ')
@@ -767,7 +772,9 @@ class dstat_disk24(dstat):
### FIXME: Needs rework, does anyone care ?
class dstat_disk24old(dstat):
def __init__(self):
- self.format = ('f', 5, 1024)
+ self.type = 'f'
+ self.width = 5
+ self.scale = 1024
self.diskfilter = re.compile('(dm-[0-9]+|md[0-9]+|[hs]d[a-z]+[0-9]+)')
self.open('/proc/stat')
self.nick = ('read', 'writ')
@@ -847,9 +854,13 @@ class dstat_disk24old(dstat):
class dstat_epoch(dstat):
def __init__(self):
self.name = 'epoch'
- self.format = ('t', 10, 0)
+ self.type = 't'
+ self.width = 10
+ self.scale = 0
if op.debug:
- self.format = ('t', 14, 0)
+ self.type = 't'
+ self.width = 14
+ self.scale = 0
self.nick = ('epoch',)
self.vars = self.nick
self.init(self.vars, 1)
@@ -865,7 +876,9 @@ class dstat_epoch(dstat):
class dstat_fs(dstat):
def __init__(self):
self.name = 'filesystem'
- self.format = ('d', 6, 1000)
+ self.type = 'd'
+ self.width = 6
+ self.scale = 1000
self.nick = ('files', 'inodes')
self.vars = self.nick
self.init(self.vars, 1)
@@ -883,7 +896,9 @@ class dstat_fs(dstat):
class dstat_int(dstat):
def __init__(self):
self.name = 'interrupts'
- self.format = ('d', 5, 1000)
+ self.type = 'd'
+ self.width = 5
+ self.scale = 1000
self.open('/proc/stat')
self.discover = self.discover()
self.intmap = self.intmap()
@@ -951,7 +966,9 @@ class dstat_int(dstat):
class dstat_int24(dstat):
def __init__(self):
self.name = 'interrupts'
- self.format = ('d', 5, 1000)
+ self.type = 'd'
+ self.width = 5
+ self.scale = 1000
self.open('/proc/interrupts')
self.discover = self.discover()
self.vars = self.vars()
@@ -1022,7 +1039,9 @@ class dstat_int24(dstat):
class dstat_io(dstat):
def __init__(self):
- self.format = ('f', 5, 1000)
+ self.type = 'f'
+ self.width = 5
+ self.scale = 1000
self.diskfilter = re.compile('(dm-[0-9]+|md[0-9]+|[hs]d[a-z]+[0-9]+)')
self.open('/proc/diskstats')
self.nick = ('read', 'writ')
@@ -1090,7 +1109,9 @@ class dstat_io(dstat):
class dstat_ipc(dstat):
def __init__(self):
self.name = 'sysv ipc'
- self.format = ('d', 3, 10)
+ self.type = 'd'
+ self.width = 3
+ self.scale = 10
self.vars = ('msg', 'sem', 'shm')
self.nick = self.vars
self.init(self.vars, 1)
@@ -1102,7 +1123,9 @@ class dstat_ipc(dstat):
class dstat_load(dstat):
def __init__(self):
self.name = 'load avg'
- self.format = ('f', 4, 10)
+ self.type = 'f'
+ self.width = 4
+ self.scale = 10
self.open('/proc/loadavg')
self.nick = ('1m', '5m', '15m')
self.vars = ('load1', 'load5', 'load15')
@@ -1118,7 +1141,9 @@ class dstat_load(dstat):
class dstat_lock(dstat):
def __init__(self):
self.name = 'file locks'
- self.format = ('f', 3, 10)
+ self.type = 'f'
+ self.width = 3
+ self.scale = 10
self.open('/proc/locks')
self.nick = ('pos', 'lck', 'rea', 'wri')
self.vars = ('posix', 'flock', 'read', 'write')
@@ -1140,7 +1165,9 @@ class dstat_lock(dstat):
class dstat_mem(dstat):
def __init__(self):
self.name = 'memory usage'
- self.format = ('f', 5, 1024)
+ self.type = 'f'
+ self.width = 5
+ self.scale = 1024
self.open('/proc/meminfo')
self.nick = ('used', 'buff', 'cach', 'free')
self.vars = ('MemUsed', 'Buffers', 'Cached', 'MemFree')
@@ -1156,7 +1183,9 @@ class dstat_mem(dstat):
class dstat_net(dstat):
def __init__(self):
- self.format = ('f', 5, 1024)
+ self.type = 'f'
+ self.width = 5
+ self.scale = 1024
self.open('/proc/net/dev')
self.nick = ('recv', 'send')
self.totalfilter = re.compile('^(lo|bond[0-9]+|face|.+\.[0-9]+)$')
@@ -1216,7 +1245,9 @@ class dstat_net(dstat):
class dstat_page(dstat):
def __init__(self):
self.name = 'paging'
- self.format = ('f', 5, 1024)
+ self.type = 'f'
+ self.width = 5
+ self.scale = 1024
self.open('/proc/vmstat')
self.nick = ('in', 'out')
self.vars = ('pswpin', 'pswpout')
@@ -1236,7 +1267,9 @@ class dstat_page(dstat):
class dstat_page24(dstat):
def __init__(self):
self.name = 'paging'
- self.format = ('f', 5, 1024)
+ self.type = 'f'
+ self.width = 5
+ self.scale = 1024
self.open('/proc/stat')
self.nick = ('in', 'out')
self.vars = ('pswpin', 'pswpout')
@@ -1258,7 +1291,9 @@ class dstat_page24(dstat):
class dstat_proc(dstat):
def __init__(self):
self.name = 'procs'
- self.format = ('f', 3, 10)
+ self.type = 'f'
+ self.width = 3
+ self.scale = 10
self.open('/proc/stat')
self.nick = ('run', 'blk', 'new')
self.vars = ('procs_running', 'procs_blocked', 'processes')
@@ -1286,7 +1321,9 @@ class dstat_proc(dstat):
class dstat_raw(dstat):
def __init__(self):
self.name = 'raw'
- self.format = ('d', 3, 100)
+ self.type = 'd'
+ self.width = 3
+ self.scale = 100
self.open('/proc/net/raw')
self.nick = ('raw',)
self.vars = ('sockets',)
@@ -1303,7 +1340,9 @@ class dstat_raw(dstat):
class dstat_socket(dstat):
def __init__(self):
self.name = 'sockets'
- self.format = ('d', 3, 100)
+ self.type = 'd'
+ self.width = 3
+ self.scale = 100
self.open('/proc/net/sockstat')
self.nick = ('tot', 'tcp', 'udp', 'raw', 'frg')
self.vars = ('sockets:', 'TCP:', 'UDP:', 'RAW:', 'FRAG:')
@@ -1318,7 +1357,9 @@ class dstat_socket(dstat):
class dstat_swap(dstat):
def __init__(self):
self.name = 'swap'
- self.format = ('f', 5, 1024)
+ self.type = 'f'
+ self.width = 5
+ self.scale = 1024
self.open('/proc/swaps')
self.nick = ('used', 'free')
self.discover = self.discover()
@@ -1370,7 +1411,9 @@ class dstat_swap(dstat):
class dstat_swapold(dstat):
def __init__(self):
self.name = 'swap'
- self.format = ('f', 5, 1024)
+ self.type = 'f'
+ self.width = 5
+ self.scale = 1024
self.open('/proc/meminfo')
self.nick = ('used', 'free')
self.vars = ('SwapUsed', 'SwapFree')
@@ -1387,7 +1430,9 @@ class dstat_swapold(dstat):
class dstat_sys(dstat):
def __init__(self):
self.name = 'system'
- self.format = ('d', 5, 1000)
+ self.type = 'd'
+ self.width = 5
+ self.scale = 1000
self.open('/proc/stat')
self.nick = ('int', 'csw')
self.vars = ('intr', 'ctxt')
@@ -1407,7 +1452,9 @@ class dstat_sys(dstat):
class dstat_tcp(dstat):
def __init__(self):
self.name = 'tcp sockets'
- self.format = ('f', 3, 100)
+ self.type = 'f'
+ self.width = 3
+ self.scale = 100
self.open('/proc/net/tcp', '/proc/net/tcp6')
self.nick = ('lis', 'act', 'syn', 'tim', 'clo')
self.vars = ('listen', 'established', 'syn', 'wait', 'close')
@@ -1431,10 +1478,12 @@ class dstat_time(dstat):
def __init__(self):
self.name = 'system'
self.timefmt = os.getenv('DSTAT_TIMEFMT') or '%d-%m %H:%M:%S'
+ self.type = 's'
if op.debug:
- self.format = ('s', len(time.strftime(self.timefmt, time.localtime())) + 4, 0)
+ self.width = len(time.strftime(self.timefmt, time.localtime())) + 4
else:
- self.format = ('s', len(time.strftime(self.timefmt, time.localtime())), 0)
+ self.width = len(time.strftime(self.timefmt, time.localtime()))
+ self.scale = 0
self.nick = ('date/time',)
self.vars = ('time',)
self.init(self.vars, 1)
@@ -1448,15 +1497,17 @@ class dstat_time(dstat):
def show(self):
if step == op.delay:
- color = 'silver'
+ color = 'text_lo'
else:
- color = 'gray'
- return ansi[color] + self.val['time']
+ color = 'text_hi'
+ return theme[color] + self.val['time']
class dstat_udp(dstat):
def __init__(self):
self.name = 'udp'
- self.format = ('d', 3, 100)
+ self.type = 'd'
+ self.width = 3
+ self.scale = 100
self.open('/proc/net/udp', '/proc/net/udp6')
self.nick = ('lis', 'act')
self.vars = ('listen', 'established')
@@ -1471,7 +1522,9 @@ class dstat_udp(dstat):
class dstat_unix(dstat):
def __init__(self):
self.name = 'unix sockets'
- self.format = ('d', 3, 100)
+ self.type = 'd'
+ self.width = 3
+ self.scale = 100
self.open('/proc/net/unix')
self.nick = ('dgm', 'str', 'lis', 'act')
self.vars = ('datagram', 'stream', 'listen', 'established')
@@ -1492,7 +1545,9 @@ class dstat_unix(dstat):
class dstat_vm(dstat):
def __init__(self):
self.name = 'virtual memory'
- self.format = ('d', 5, 1000)
+ self.type = 'd'
+ self.width = 5
+ self.scale = 1000
self.open('/proc/vmstat')
self.nick = ('majpf', 'minpf', 'alloc', 'free')
self.vars = ('pgmajfault', 'pgfault', 'pgalloc_normal', 'pgfree')
@@ -1518,9 +1573,9 @@ ansi = {
'darkblue': '\033[0;34m',
'darkmagenta': '\033[0;35m',
'darkcyan': '\033[0;36m',
- 'silver': '\033[0;37m',
+ 'gray': '\033[0;37m',
- 'gray': '\033[1;30m',
+ 'darkgray': '\033[1;30m',
'red': '\033[1;31m',
'green': '\033[1;32m',
'yellow': '\033[1;33m',
@@ -1567,6 +1622,43 @@ char = {
'dash': '-',
}
+def set_theme():
+ if op.blackonwhite:
+ theme = {
+ 'title': ansi['darkblue'],
+ 'subtitle': ansi['darkcyan'] + ansi['underline'],
+ 'frame': ansi['darkgray'],
+ 'default': ansi['default'],
+ 'error': ansi['white'] + ansi['redbg'],
+ 'roundtrip': ansi['darkblue'],
+ 'debug': ansi['darkred'],
+ 'input': ansi['darkgray'],
+ 'text_lo': ansi['black'],
+ 'text_hi': ansi['darkgray'],
+ 'colors_lo': (ansi['darkred'], ansi['darkmagenta'], ansi['darkgreen'], ansi['darkblue'],
+ ansi['darkcyan'], ansi['gray'], ansi['red'], ansi['green']),
+ 'colors_hi': (ansi['red'], ansi['magenta'], ansi['green'], ansi['blue'],
+ ansi['cyan'], ansi['white'], ansi['darkred'], ansi['darkgreen']),
+ }
+ else:
+ theme = {
+ 'title': ansi['darkblue'],
+ 'subtitle': ansi['blue'] + ansi['underline'],
+ 'frame': ansi['darkgray'],
+ 'default': ansi['default'],
+ 'error': ansi['white'] + ansi['redbg'],
+ 'roundtrip': ansi['darkblue'],
+ 'debug': ansi['darkred'],
+ 'input': ansi['darkgray'],
+ 'text_lo': ansi['gray'],
+ 'text_hi': ansi['darkgray'],
+ 'colors_lo': (ansi['red'], ansi['yellow'], ansi['green'], ansi['blue'],
+ ansi['cyan'], ansi['white'], ansi['darkred'], ansi['darkgreen']),
+ 'colors_hi': (ansi['darkred'], ansi['darkyellow'], ansi['darkgreen'], ansi['darkblue'],
+ ansi['darkcyan'], ansi['gray'], ansi['red'], ansi['green']),
+ }
+ return theme
+
def ticks():
"Return the number of 'ticks' since bootup"
try:
@@ -1697,19 +1789,19 @@ def fchg(var, maxlen, base):
c = -1
return ret, c
-def cprintlist(varlist, format):
+def cprintlist(varlist, type, width, scale):
"Return all columns color printed"
ret = sep = ''
for var in varlist:
- ret = ret + sep + cprint(var, format)
+ ret = ret + sep + cprint(var, type, width, scale)
sep = ' '
return ret
-def cprint(var, format = ('f', 4, 1000)):
+def cprint(var, type = 'f', width = 4, scale = 1000):
"Color print one column"
- vartype = format[0]
- maxlen = format[1]
- mp = format[2]
+ vartype = type
+ maxlen = width
+ mp = scale
base = 1000
if mp == 1024:
@@ -1724,9 +1816,9 @@ def cprint(var, format = ('f', 4, 1000)):
### If this is a negative value, return a dash
if var < 0:
if unit:
- return ansi['white'] + ansi['redbg'] + '-'.rjust(maxlen) + ' ' + ansi['default']
+ return theme['error'] + '-'.rjust(maxlen) + ' ' + theme['default']
else:
- return ansi['white'] + ansi['redbg'] + '-'.rjust(maxlen) + ansi['default']
+ return theme['error'] + '-'.rjust(maxlen) + theme['default']
if base == 1024:
units = ('B', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
@@ -1734,9 +1826,9 @@ def cprint(var, format = ('f', 4, 1000)):
units = (' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
if step == op.delay:
- colors = ('red', 'yellow', 'green', 'blue', 'magenta', 'cyan', 'white', 'darkred', 'darkgreen')
+ colors = theme['colors_lo']
else:
- colors = ('darkred', 'darkyellow', 'darkgreen', 'darkblue', 'darkmagenta', 'darkcyan', 'silver', 'red', 'green')
+ colors = theme['colors_hi']
### Convert value to string given base and field-length
if op.integer and vartype in ('d', 'p', 'f'):
@@ -1750,26 +1842,33 @@ def cprint(var, format = ('f', 4, 1000)):
else:
ret, c = str(var), -1
+ if step == op.delay:
+ colors = theme['colors_lo']
+ text = theme['text_lo']
+ else:
+ colors = theme['colors_hi']
+ text = theme['text_hi']
+
### Set the counter color
if ret == '0':
- color = 'default'
+ color = text
elif vartype in ('d', 'p'):
color = colors[int(round(var)/mp)%len(colors)]
elif vartype in ('f'):
color = colors[c%len(colors)]
else:
- color = 'default'
+ color = text
### Justify value to left if string
if vartype in ('s',):
- ret = ansi[color] + ret.ljust(maxlen)
+ ret = color + ret.ljust(maxlen)
else:
- ret = ansi[color] + ret.rjust(maxlen)
+ ret = color + ret.rjust(maxlen)
### Add unit to output
if unit:
if c != -1 and round(var) != 0:
- ret = ret + ansi['default'] + units[c]
+ ret = ret + text + units[c]
else:
ret = ret + ' '
@@ -1778,7 +1877,7 @@ def cprint(var, format = ('f', 4, 1000)):
def showtitle(nr, totlist, vislist, midchar, endchar):
line = ''
for o in vislist:
- line = line + o.title(nr)
+ line = line + o.printtitle(nr)
if o is not vislist[-1]:
line = line + midchar
elif totlist != vislist:
@@ -1961,6 +2060,19 @@ def exit(ret):
sys.exit(ret)
def listmodules():
+ modules = []
+ remod = re.compile('dstat_(.+)$')
+ for filename in globals():
+ if filename.startswith('dstat_'):
+ modules.append(remod.match(filename).groups()[0])
+ remod = re.compile('.+/dstat_(.+).py$')
+ for path in sys.path:
+ for filename in glob.glob(path + '/dstat_*.py'):
+ modules.append(remod.match(filename).groups()[0])
+ modules.sort()
+ return modules
+
+def showmodules():
rows, cols = gettermsize()
print 'internal:\n\t',
remod = re.compile('dstat_(.+)$')
@@ -1995,7 +2107,7 @@ def listmodules():
print
def main():
- global pagesize, cpunr, ansi, outputfile
+ global pagesize, cpunr, ansi, theme, outputfile
global totlist, inittime
global update, missed
@@ -2054,11 +2166,15 @@ def main():
print >>sys.stderr, 'Failed to create pidfile %s' % op.pidfile, e
op.pidfile = False
- ### Empty ansi database if no colors are requested
+ ### Empty ansi and theme database if no colors are requested
if not op.color:
op.update = False
for key in ansi.keys():
ansi[key] = ''
+ for key in theme.keys():
+ theme[key] = ''
+ theme['colors_hi'] = (ansi['default'],)
+ theme['colors_lo'] = (ansi['default'],)
# print ansi['blackbg']
if not op.update:
@@ -2069,7 +2185,7 @@ def main():
totlist = []
for module in op.modlist:
if module in ('list', 'help'):
- listmodules()
+ showmodules()
exit(0)
elif module == 'cpu': mods = ( 'cpu', 'cpu24' )
elif module == 'disk': mods = ( 'disk', 'disk24', 'disk24old' )
@@ -2222,14 +2338,14 @@ def perform(update):
if loop == 0 and totlist != vislist:
print >>sys.stderr, 'Terminal width too small, trimming output.'
showheader = False
- showtitle(1, totlist, vislist, ansi['darkblue'] + char['space'], ansi['darkblue'] + char['gt'])
- showtitle(2, totlist, vislist, ansi['gray'] + char['pipe'], ansi['darkblue'] + char['gt'])
+ showtitle(1, totlist, vislist, theme['frame'] + char['space'], theme['title'] + char['gt'])
+ showtitle(2, totlist, vislist, theme['frame'] + char['pipe'], theme['title'] + char['gt'])
### Prepare the colors for intermediate updates, last step in a loop is definitive
if step == op.delay:
- ansi['default'] = ansi['reset']
+ theme['default'] = ansi['reset']
else:
- ansi['default'] = ansi['gray']
+ theme['default'] = theme['text_lo']
### Calculate all objects (visible, invisible)
line = ''
@@ -2252,32 +2368,34 @@ def perform(update):
if loop == 0:
totaltime = totaltime * step
if op.debug == 1:
- sys.stdout.write('%s%6.2fms%s' % (ansi['darkblue'], totaltime / step, ansi['default']))
+ sys.stdout.write('%s%6.2fms%s' % (theme['roundtrip'], totaltime / step, theme['default']))
elif op.debug == 2:
- sys.stdout.write('%s%6.2f %s%d:%d%s' % (ansi['darkblue'], totaltime / step, ansi['darkred'], loop, step, ansi['default']))
+ sys.stdout.write('%s%6.2f %s%d:%d%s' % (theme['roundtrip'], totaltime / step, theme['debug'], loop, step, theme['default']))
elif op.debug > 2:
- sys.stdout.write('%s%6.2f %s%d:%d:%d%s' % (ansi['darkblue'], totaltime / step, ansi['darkred'], loop, step, update, ansi['default']))
+ sys.stdout.write('%s%6.2f %s%d:%d:%d%s' % (theme['roundtrip'], totaltime / step, theme['debug'], loop, step, update, theme['default']))
if missed > 0:
-# sys.stdout.write(' '+ansi['redbg']+ansi['white']+'= warn =')
- sys.stdout.write(' '+ansi['redbg']+ansi['white']+'missed '+str(missed+1)+' ticks')
+# sys.stdout.write(' '+theme['error']+'= warn =')
+ sys.stdout.write(' '+theme['error']+'missed '+str(missed+1)+' ticks')
missed = 0
### Additional input in gray
- sys.stdout.write(ansi['gray'])
+ sys.stdout.write(theme['input'])
### Finish the line
if not op.update:
sys.stdout.write('\n')
+
### Main entrance
if __name__ == '__main__':
try:
initterm()
op = Options(sys.argv[1:])
+ theme = set_theme()
main()
except KeyboardInterrupt, e:
- print ansi['default']
+ print theme['default']
if op.pidfile and os.path.exists(op.pidfile):
os.remove(op.pidfile)
13 examples/mstat.py
View
@@ -8,6 +8,9 @@
sys.path.insert(0, '/usr/share/dstat/')
import dstat, time
+### Set default theme
+dstat.theme = dstat.set_theme()
+
### Allow arguments
try: delay = float(sys.argv[1])
except: delay = 0.2
@@ -16,6 +19,8 @@
### Load stats
stats = []
+dstat.starttime = time.time()
+dstat.tick = dstat.ticks()
for o in (dstat.dstat_epoch(), dstat.dstat_cpu(), dstat.dstat_mem(), dstat.dstat_load(), dstat.dstat_disk(), dstat.dstat_sys()):
try: o.check()
except Exception, e: print e
@@ -25,11 +30,11 @@
stats[0].format = ('t', 14, 0)
### Print headers
-title1 = title2 = ''
+title = subtitle = ''
for o in stats:
- title1 = title1 + ' ' + o.title1()
- title2 = title2 + ' ' + o.title2()
-print '\n' + title1 + '\n' + title2
+ title = title + ' ' + o.title()
+ subtitle = subtitle + ' ' + o.subtitle()
+print '\n' + title + '\n' + subtitle
### Print stats
for dstat.update in range(count):
12 examples/read.py
View
@@ -7,10 +7,14 @@
sys.path.insert(0, '/usr/share/dstat/')
import dstat
+### Set default theme
+dstat.theme = dstat.set_theme()
+
clear = dstat.ansi['reset']
+dstat.tick = dstat.ticks()
c = dstat.dstat_cpu()
-print c.title1() + '\n' + c.title2()
+print c.title() + '\n' + c.subtitle()
c.extract()
print c.show(), clear
print 'Percentage:', c.val['total']
@@ -18,21 +22,21 @@
print
m = dstat.dstat_mem()
-print m.title1() + '\n' + m.title2()
+print m.title() + '\n' + m.subtitle()
m.extract()
print m.show(), clear
print 'Raw:', m.val
print
l = dstat.dstat_load()
-print l.title1() + '\n' + l.title2()
+print l.title() + '\n' + l.subtitle()
l.extract()
print l.show(), clear
print 'Raw:', l.val
print
d = dstat.dstat_disk()
-print d.title1() + '\n' + d.title2()
+print d.title() + '\n' + d.subtitle()
d.extract()
print d.show(), clear
print 'Raw:', d.val['total']
4 plugins/dstat_battery.py
View
@@ -6,7 +6,9 @@
class dstat_battery(dstat):
def __init__(self):
self.name = 'battery'
- self.format = ('p', 4, 34)
+ self.type = 'p'
+ self.width = 4
+ self.scale = 34
self.vars = []
for battery in os.listdir('/proc/acpi/battery/'):
for line in dopen('/proc/acpi/battery/'+battery+'/state').readlines():
4 plugins/dstat_cpufreq.py
View
@@ -9,7 +9,9 @@
class dstat_cpufreq(dstat):
def __init__(self):
self.name = 'frequency'
- self.format = ('p', 4, 34)
+ self.type = 'p'
+ self.width = 4
+ self.scale = 34
# self.vars = os.listdir('/sys/devices/system/cpu/')
# self.nick = [name.lower() for name in self.vars]
self.vars = []
4 plugins/dstat_dbus.py
View
@@ -6,7 +6,9 @@
class dstat_dbus(dstat):
def __init__(self):
self.name = 'dbus'
- self.format = ('d', 3, 100)
+ self.type = 'd'
+ self.width = 3
+ self.scale = 100
self.nick = ('sys', 'ses')
self.vars = ('system', 'session')
self.init(self.vars, 1)
4 plugins/dstat_fan.py
View
@@ -1,7 +1,9 @@
class dstat_fan(dstat):
def __init__(self):
self.name = 'fan'
- self.format = ('d', 4, 500)
+ self.type = 'd'
+ self.width = 4
+ self.scale = 500
if os.path.exists('/proc/acpi/ibm/fan'):
for line in dopen('/proc/acpi/ibm/fan'):
l = line.split()
4 plugins/dstat_freespace.py
View
@@ -5,7 +5,9 @@
class dstat_freespace(dstat):
def __init__(self):
- self.format = ('f', 5, 1024)
+ self.type = 'f'
+ self.width = 5
+ self.scale = 1024
self.open('/etc/mtab')
self.vars = self.vars()
# self.name = ['/' + os.path.basename(name) for name in self.vars]
4 plugins/dstat_gpfs.py
View
@@ -1,7 +1,9 @@
class dstat_gpfs(dstat):
def __init__(self):
self.name = 'gpfs i/o'
- self.format = ('f', 5, 1024)
+ self.type = 'f'
+ self.width = 5
+ self.scale = 1024
self.vars = ('_br_', '_bw_')
self.nick = ('read', 'write')
self.init(self.vars, 1)
4 plugins/dstat_gpfsop.py
View
@@ -1,7 +1,9 @@
class dstat_gpfsop(dstat):
def __init__(self):
self.name = 'gpfs file operations'
- self.format = ('d', 5, 1000)
+ self.type = 'd'
+ self.width = 5
+ self.scale = 1000
self.vars = ('_oc_', '_cc_', '_rdc_', '_wc_', '_dir_', '_iu_')
self.nick = ('open', 'clos', 'read', 'writ', 'rdir', 'inod')
self.init(self.vars, 1)
4 plugins/dstat_helloworld.py
View
@@ -6,7 +6,9 @@
class dstat_helloworld(dstat):
def __init__(self):
self.name = 'plugin title'
- self.format = ('s', 12, 0)
+ self.type = 's'
+ self.width = 12
+ self.scale = 0
self.nick = ('counter',)
self.vars = ('text',)
self.init(self.vars, 1)
4 plugins/dstat_innodb_buffer.py
View
@@ -4,7 +4,9 @@
class dstat_innodb_buffer(dstat):
def __init__(self):
self.name = 'innodb pool'
- self.format = ('f', 3, 1000)
+ self.type = 'f'
+ self.width = 3
+ self.scale = 1000
self.vars = ('read', 'created', 'written')
self.nick = ('crt', 'rea', 'wri')
self.init(self.vars, 1)
4 plugins/dstat_innodb_io.py
View
@@ -4,7 +4,9 @@
class dstat_innodb_io(dstat):
def __init__(self):
self.name = 'innodb io ops '
- self.format = ('f', 3, 1000)
+ self.type = 'f'
+ self.width = 3
+ self.scale = 1000
self.vars = ('rea', 'wri', 'syn')
self.nick = self.vars
self.init(self.vars, 1)
4 plugins/dstat_innodb_ops.py
View
@@ -4,7 +4,9 @@
class dstat_innodb_ops(dstat):
def __init__(self):
self.name = 'innodb ops'
- self.format = ('f', 3, 1000)
+ self.type = 'f'
+ self.width = 3
+ self.scale = 1000
self.vars = ('inserted', 'updated', 'deleted', 'read')
self.nick = ('ins', 'upd', 'del', 'rea')
self.init(self.vars, 1)
4 plugins/dstat_lustre.py
View
@@ -9,7 +9,9 @@ def __init__(self):
for mount in os.listdir('/proc/fs/lustre/llite'):
self.vars.append(mount)
self.name.append(mount[:mount.rfind('-')])
- self.format = ('f', 5, 1024)
+ self.type = 'f'
+ self.width = 5
+ self.scale = 1024
self.nick = ('read', 'write')
self.init(self.vars, 2)
info(1, 'Module dstat_lustre is still experimental.')
4 plugins/dstat_mysql5_com.py
View
@@ -11,7 +11,9 @@
class dstat_mysql5_com(dstat):
def __init__(self):
self.name = 'mysql5 com'
- self.format = ('i', 5, 1)
+ self.type = 'i'
+ self.width = 5
+ self.scale = 1
self.vars = ('Com_select', 'Com_insert','Com_update','Com_delete')
self.nick = ('sel', 'ins','upd','del')
self.init(self.vars, 1)
4 plugins/dstat_mysql5_conn.py
View
@@ -11,7 +11,9 @@
class dstat_mysql5_conn(dstat):
def __init__(self):
self.name = 'mysql5 conn'
- self.format = ('f', 4, 1)
+ self.type = 'f'
+ self.width = 4
+ self.scale = 1
self.vars = ('Threads_connected', 'Threads')
self.nick = ('ThCon', '%Con')
self.init(self.vars, 1)
4 plugins/dstat_mysql5_io.py
View
@@ -11,7 +11,9 @@
class dstat_mysql5_io(dstat):
def __init__(self):
self.name = 'mysql5 io'
- self.format = ('f', 5, 1024)
+ self.type = 'f'
+ self.width = 5
+ self.scale = 1024
self.vars = ('Bytes_received', 'Bytes_sent')
self.nick = ('recv', 'sent')
self.init(self.vars, 1)
4 plugins/dstat_mysql5_keys.py
View
@@ -11,7 +11,9 @@
class dstat_mysql5_keys(dstat):
def __init__(self):
self.name = 'mysql5 key status'
- self.format = ('f', 4, 1000)
+ self.type = 'f'
+ self.width = 4
+ self.scale = 1000
self.vars = ('Key_blocks_used', 'Key_reads', 'Key_writes', 'Key_read_requests', 'Key_write_requests')
self.nick = ('used', 'read', 'writ', 'rreq', 'wreq')
self.init(self.vars, 1)
4 plugins/dstat_mysql_io.py
View
@@ -4,7 +4,9 @@
class dstat_mysql_io(dstat):
def __init__(self):
self.name = 'mysql io'
- self.format = ('f', 5, 1024)
+ self.type = 'f'
+ self.width = 5
+ self.scale = 1024
self.vars = ('Bytes_received', 'Bytes_sent')
self.nick = ('recv', 'sent')
self.init(self.vars, 1)
4 plugins/dstat_mysql_keys.py
View
@@ -4,7 +4,9 @@
class dstat_mysql_keys(dstat):
def __init__(self):
self.name = 'mysql key status'
- self.format = ('f', 4, 1000)
+ self.type = 'f'
+ self.width = 4
+ self.scale = 1000
self.vars = ('Key_blocks_used', 'Key_reads', 'Key_writes', 'Key_read_requests', 'Key_write_requests')
self.nick = ('used', 'read', 'writ', 'rreq', 'wreq')
self.init(self.vars, 1)
4 plugins/dstat_net_packets.py
View
@@ -1,6 +1,8 @@
class dstat_net_packets(dstat):
def __init__(self):
- self.format = ('f', 5, 1000)
+ self.type = 'f'
+ self.width = 5
+ self.scale = 1000
self.open('/proc/net/dev')
self.nick = ('#recv', '#send')
self.totalfilter = re.compile('^(lo|bond[0-9]+|face|.+\.[0-9]+)$')
4 plugins/dstat_nfs3.py
View
@@ -1,7 +1,9 @@
class dstat_nfs3(dstat):
def __init__(self):
self.name = 'nfs3 client'
- self.format = ('d', 5, 1000)
+ self.type = 'd'
+ self.width = 5
+ self.scale = 1000
self.open('/proc/net/rpc/nfs')
self.vars = ('read', 'write', 'readdir', 'inode', 'filesystem', 'commit')
self.nick = ('read', 'writ', 'rdir', 'inod', 'fs', 'cmmt')
4 plugins/dstat_nfs3op.py
View
@@ -1,7 +1,9 @@
class dstat_nfs3op(dstat):
def __init__(self):
self.name = 'extended nfs3 client operations'
- self.format = ('d', 5, 1000)
+ self.type = 'd'
+ self.width = 5
+ self.scale = 1000
self.open('/proc/net/rpc/nfs')
self.vars = ('null', 'getattr', 'setattr', 'lookup', 'access', 'readlink', 'read', 'write', 'create', 'mkdir', 'symlink', 'mknod', 'remove', 'rmdir', 'rename', 'link', 'readdir', 'readdirplus', 'fsstat', 'fsinfo', 'pathconf', 'commit')
self.nick = ('null', 'gatr', 'satr', 'look', 'aces', 'rdln', 'read', 'writ', 'crea', 'mkdr', 'syml', 'mknd', 'rm', 'rmdr', 'ren', 'link', 'rdir', 'rdr+', 'fstt', 'fsnf', 'path', 'cmmt')
4 plugins/dstat_nfsd3.py
View
@@ -1,7 +1,9 @@
class dstat_nfsd3(dstat):
def __init__(self):
self.name = 'nfs3 server'
- self.format = ('d', 5, 1000)
+ self.type = 'd'
+ self.width = 5
+ self.scale = 1000
self.open('/proc/net/rpc/nfsd')
self.vars = ('read', 'write', 'readdir', 'inode', 'filesystem', 'commit')
self.nick = ('read', 'writ', 'rdir', 'inod', 'fs', 'cmmt')
4 plugins/dstat_nfsd3op.py
View
@@ -1,7 +1,9 @@
class dstat_nfsd3op(dstat):
def __init__(self):
self.name = 'extended nfs3 server operations'
- self.format = ('d', 5, 1000)
+ self.type = 'd'
+ self.width = 5
+ self.scale = 1000
self.open('/proc/net/rpc/nfsd')
self.vars = ('null', 'getattr', 'setattr', 'lookup', 'access', 'readlink', 'read', 'write', 'create', 'mkdir', 'symlink', 'mknod', 'remove', 'rmdir', 'rename', 'link', 'readdir', 'readdirplus', 'fsstat', 'fsinfo', 'pathconf', 'commit')
self.nick = ('null', 'gatr', 'satr', 'look', 'aces', 'rdln', 'read', 'writ', 'crea', 'mkdr', 'syml', 'mknd', 'rm', 'rmdr', 'ren', 'link', 'rdir', 'rdr+', 'fstt', 'fsnf', 'path', 'cmmt')
6 plugins/dstat_ntp.py
View
@@ -22,7 +22,9 @@ def __init__(self):
self.name = 'ntp'
self.timefmt = os.getenv('DSTAT_TIMEFMT') or '%d-%m %H:%M:%S'
self.ntpserver = os.getenv('DSTAT_NTPSERVER') or '0.fedora.pool.ntp.org'
- self.format = ('s', len(time.strftime(self.timefmt, time.localtime())), 0)
+ self.type = 's'
+ self.width = len(time.strftime(self.timefmt, time.localtime()))
+ self.scale = 0
self.nick = ('date/time',)
self.vars = ('time',)
self.epoch = 2208988800L
@@ -59,6 +61,6 @@ def show(self):
if self.val['time']:
return ansi[color] + time.strftime(self.timefmt, time.localtime(self.val['time']))
else:
- return ansi['white'] + ansi['redbg'] + '-'.rjust(self.format[1]-1) + ' ' + ansi['default']
+ return theme['error'] + '-'.rjust(self.width-1) + ' ' + theme['default']
# vim:ts=4:sw=4:et
4 plugins/dstat_postfix.py
View
@@ -4,7 +4,9 @@
class dstat_postfix(dstat):
def __init__(self):
self.name = 'postfix'
- self.format = ('d', 4, 100)
+ self.type = 'd'
+ self.width = 4
+ self.scale = 100
self.vars = ('incoming', 'active', 'deferred', 'bounce', 'defer')
self.nick = ('inco', 'actv', 'dfrd', 'bnce', 'defr')
self.init(self.vars, 1)
4 plugins/dstat_power.py
View
@@ -6,7 +6,9 @@
class dstat_power(dstat):
def __init__(self):
self.name = 'power'
- self.format = ('f', 5, 1)
+ self.type = 'f'
+ self.width = 5
+ self.scale = 1
self.vars = ( 'rate', )
self.nick = ( 'usage', )
self.batteries = []
4 plugins/dstat_rpc.py
View
@@ -1,7 +1,9 @@
class dstat_rpc(dstat):
def __init__(self):
self.name = 'rpc client'
- self.format = ('d', 5, 1000)
+ self.type = 'd'
+ self.width = 5
+ self.scale = 1000
self.open('/proc/net/rpc/nfs')
self.vars = ('calls', 'retransmits', 'autorefreshes')
self.nick = ('call', 'retr', 'refr')
4 plugins/dstat_rpcd.py
View
@@ -1,7 +1,9 @@
class dstat_rpcd(dstat):
def __init__(self):
self.name = 'rpc server'
- self.format = ('d', 5, 1000)
+ self.type = 'd'
+ self.width = 5
+ self.scale = 1000
self.open('/proc/net/rpc/nfsd')
self.vars = ('calls', 'badcalls', 'badauth', 'badclnt', 'xdrcall')
self.nick = ('call', 'erca', 'erau', 'ercl', 'xdrc')
4 plugins/dstat_sendmail.py
View
@@ -5,7 +5,9 @@
class dstat_sendmail(dstat):
def __init__(self):
self.name = 'sendmail'
- self.format = ('d', 4, 100)
+ self.type = 'd'
+ self.width = 4
+ self.scale = 100
self.vars = ('queue',)
self.nick = ('queu',)
self.init(self.vars, 1)
4 plugins/dstat_snooze.py
View
@@ -1,7 +1,9 @@
class dstat_snooze(dstat):
def __init__(self):
self.name = 'snooze'
- self.format = ('s', 6, 0)
+ self.type = 's'
+ self.width = 6
+ self.scale = 0
self.nick = ('snooze',)
self.vars = self.nick
self.before = time.time()
4 plugins/dstat_thermal.py
View
@@ -1,7 +1,9 @@
class dstat_thermal(dstat):
def __init__(self):
self.name = 'thermal'
- self.format = ('d', 3, 20)
+ self.type = 'd'
+ self.width = 3
+ self.scale = 20
if os.path.exists('/proc/acpi/ibm/thermal'):
self.namelist = ['cpu', 'pci', 'hdd', 'cpu', 'ba0', 'unk', 'ba1', 'unk']
self.nick = []
10 plugins/dstat_topbio.py
View
@@ -6,7 +6,9 @@
class dstat_topbio(dstat):
def __init__(self):
self.name = 'most expensive'
- self.format = ('s', 22, 0)
+ self.type = 's'
+ self.width = 22
+ self.scale = 0
self.nick = ('block i/o process',)
self.vars = self.nick
self.pid = str(os.getpid())
@@ -66,7 +68,7 @@ def extract(self):
self.val['process'] = os.path.basename(self.val['name'])
### Debug (show PID)
-# self.val['process'] = '%*s %-*s' % (5, self.val['pid'], self.format[1]-6, self.val['name'])
+# self.val['process'] = '%*s %-*s' % (5, self.val['pid'], self.width-6, self.val['name'])
if step == op.delay:
for pid in self.cn2.keys():
@@ -74,9 +76,9 @@ def extract(self):
def show(self):
if self.val['usage'] == 0.0:
- return '%-*s' % (self.format[1], '')
+ return '%-*s' % (self.width, '')
else:
- return '%s%-*s%s:%s' % (ansi['default'], self.format[1]-11, self.val['process'][0:self.format[1]-11], cprint(self.val['read_usage'], ('f', 5, 1024)), cprint(self.val['write_usage'], ('f', 5, 1024)))
+ return '%s%-*s%s:%s' % (ansi['default'], self.width-11, self.val['process'][0:self.width-11], cprint(self.val['read_usage'], 'f', 5, 1024), cprint(self.val['write_usage'], 'f', 5, 1024))
def showcsv(self):
return '%s / %d:%d' % (self.val['name'], self.val['read_usage'], self.val['write_usage'])
10 plugins/dstat_topcpu.py
View
@@ -8,7 +8,9 @@
class dstat_topcpu(dstat):
def __init__(self):
self.name = 'most expensive'
- self.format = ('s', 16, 0)
+ self.type = 's'
+ self.width = 16
+ self.scale = 0
self.nick = ('cpu process',)
self.vars = self.nick
self.pid = str(os.getpid())
@@ -72,16 +74,16 @@ def extract(self):
# break
### Debug (show PID)
-# self.val['process'] = '%*s %-*s' % (5, self.val['pid'], self.format[1]-6, self.val['name'])
+# self.val['process'] = '%*s %-*s' % (5, self.val['pid'], self.width-6, self.val['name'])
if step == op.delay:
self.cn1.update(self.cn2)
def show(self):
if self.val['max'] == 0.0:
- return '%-*s' % (self.format[1], '')
+ return '%-*s' % (self.width, '')
else:
- return '%s%-*s%s' % (ansi['default'], self.format[1]-3, self.val['process'][0:self.format[1]-3], cprint(self.val['max'], ('p', 3, 34)))
+ return '%s%-*s%s' % (theme['default'], self.width-3, self.val['process'][0:self.width-3], cprint(self.val['max'], 'p', 3, 34))
def showcsv(self):
return '%s / %d%%' % (self.val['name'], self.val['max'])
12 plugins/dstat_topio.py
View
@@ -6,7 +6,9 @@
class dstat_topio(dstat):
def __init__(self):
self.name = 'most expensive'
- self.format = ('s', 22, 0)
+ self.type = 's'
+ self.width = 22
+ self.scale = 0
self.nick = ('i/o process',)
self.vars = self.nick
self.pid = str(os.getpid())
@@ -65,10 +67,10 @@ def extract(self):
if self.val['usage'] == 0.0:
self.val['process'] = ''
else:
- self.val['process'] = self.val['name']
+ self.val['process'] = os.path.basename(self.val['name'])
### Debug (show PID)
-# self.val['process'] = '%*s %-*s' % (5, self.val['pid'], self.format[1]-6, self.val['name'])
+# self.val['process'] = '%*s %-*s' % (5, self.val['pid'], self.width-6, self.val['name'])
if step == op.delay:
for pid in self.cn2.keys():
@@ -76,9 +78,9 @@ def extract(self):
def show(self):
if self.val['usage'] == 0.0:
- return '%-*s' % (self.format[1], '')
+ return '%-*s' % (self.width, '')
else:
- return '%s%-*s%s:%s' % (ansi['default'], self.format[1]-11, self.val[