├── pollster ├── __init__.py ├── PollsterClass.py ├── load.py ├── uptime.py ├── mem.py ├── util.py ├── cpu.py ├── net.py └── disk.py ├── restart.sh ├── stop.sh ├── README.md ├── start.sh ├── PollManager.py ├── HttpServer.py ├── DaemonClass.py └── statistic.py /pollster/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pollster/PollsterClass.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -* 2 | # Copyright © 2013 Computer Network Information Center, Chinese Academy of Sciences 3 | # 4 | # Author: Jing Shao 5 | 6 | ''' 7 | The base class of pollster 8 | ''' 9 | class Pollster(object): 10 | def __init__(self, name): 11 | self.name = name 12 | 13 | def getSample(self): 14 | pass 15 | -------------------------------------------------------------------------------- /restart.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | workspace=$(cd `dirname $0`; pwd) 4 | 5 | # Stop polling 6 | PID_poll=`ps -ef | grep PollManager.py | grep -v grep | awk '{print $2}'` 7 | if [ -n "$PID_poll" ] 8 | then 9 | python ${workspace}/PollManager.py stop 10 | echo "Stop Polling task done" 11 | fi 12 | 13 | ps -ef | grep HttpServer.py | grep -v grep | awk '{print $ 2}' | xargs kill 14 | 15 | if [ -f "/tmp/httpsvr.log" ]; then 16 | rm /tmp/httpsvr.log 17 | fi 18 | 19 | echo "Stop HttpServer done" 20 | 21 | nohup python ${workspace}/HttpServer.py ${workspace} > /tmp/httpsvr.log 2>&1 & 22 | echo "Start HttpServer done" 23 | 24 | sleep .5 25 | 26 | python ${workspace}/PollManager.py start 27 | python ${workspace}/PollManager.py setintvl 10 28 | python ${workspace}/PollManager.py setpoll "['pollster.cpu.CPUUsagePollster','pollster.mem.MemInfoPollster','pollster.load.LoadStatPollster','pollster.disk.DiskUsagePollster','pollster.net.NetStatPollster','pollster.uptime.UptimePollster']" 29 | echo "Start Polling task done" 30 | -------------------------------------------------------------------------------- /stop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | workspace=$(cd `dirname $0`; pwd) 4 | 5 | # Stop polling 6 | PID_poll=`ps -ef | grep PollManager.py | grep -v grep | awk '{print $2}'` 7 | 8 | if [ -n "$PID_poll" ] 9 | then 10 | python ${workspace}/PollManager.py stop 11 | fi 12 | 13 | sleep 1 14 | 15 | # Stop HttpServer 16 | ps -ef | grep HttpServer.py | grep -v grep | awk '{print $ 2}' | xargs kill 17 | 18 | # remove check task from /etc/cron.d 19 | cron_procagent="/etc/cron.d/procagent" 20 | 21 | if [ -f "$cron_procagent" ]; then 22 | rm ${cron_procagent} 23 | 24 | /etc/init.d/cron restart 25 | 26 | echo "Remove crontab done" 27 | fi 28 | 29 | if [ -f "/tmp/httpsvr.log" ]; then 30 | rm /tmp/httpsvr.log 31 | fi 32 | 33 | if [ -f "/etc/rc.d/rc.local" ]; then 34 | sed -i "/procagent/d" /etc/rc.d/rc.local 35 | echo "Remove task from /etc/rc.d/rc.local" 36 | elif [ -f "/etc/rc.local" ]; then 37 | sed -i "/procagent/d" /etc/rc.local 38 | echo "Remove task from /etc/rc.local" 39 | fi 40 | 41 | echo "Terminate all" 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #procagent 2 | 3 | A linux monitor agent. Fetch data from procfs. 4 | 5 | ##Usage: 6 | 7 | ###1. Start polling task and http server. 8 | ./start.sh 9 | 10 | ###2. Stop polling task and http server. 11 | ./stop.sh 12 | 13 | ###3. Get monitor data through http server. 14 | curl -X GET http://IP_ADDR:8655/getdata 15 | 16 | ###4. Get polling interval through http server. 17 | curl -X GET http://IP_ADDR:8655/getintvl 18 | 19 | ###5. Get pollsters list through http server. 20 | curl -X GET http://IP_ADDR:8655/getpollsters 21 | 22 | ###6. Start polling task through shell 23 | python PollManager.py start 24 | 25 | ###7. Stop polling task through shell 26 | python PollManager.py stop 27 | 28 | ###8. Restart polling task through shell 29 | python PollManager.py restart 30 | 31 | ###9. Set polling interval as 10 sec through shell 32 | python PollManager.py setintvl 10 33 | 34 | ###10. Set pollsters 35 | python PollManager.py setpoll "['pollster.cpu.CPUUsagePollster','pollster.mem.MemInfoPollster']" 36 | 37 | ####PS. Add pollster in procagent/pollster if you like. 38 | 39 | Edit by Kevin Shaw dysj4099@gmail.com 40 | -------------------------------------------------------------------------------- /pollster/load.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -* 2 | # Copyright © 2013 Computer Network Information Center, Chinese Academy of Sciences 3 | # 4 | # Author: Jing Shao 5 | 6 | import util 7 | import os 8 | from PollsterClass import Pollster 9 | 10 | ''' 11 | Get load average info from /proc/loadavg 12 | 13 | example: 14 | cat /proc/loadavg 15 | 0.00 0.02 0.05 1/226 3941 16 | 0.00 - load avg 1 min 17 | 0.02 - load avg 5 min 18 | 0.05 - load avg 15 min 19 | 1/226 - num of running proc/proc total 20 | 3941 - last pid 21 | ''' 22 | class LoadStatPollster(Pollster): 23 | def __init__(self, name='load_stat'): 24 | super(LoadStatPollster, self).__init__(name=name) 25 | 26 | def getSample(self): 27 | load_stat = {} 28 | load_info = None 29 | f = None 30 | 31 | try: 32 | if util.is_exist('/proc/loadavg'): 33 | f = open('/proc/loadavg') 34 | load_info = f.read().split() 35 | if load_info and len(load_info) == 5: 36 | load_stat['load_1_min'] = {'volume':float(load_info[0]), 'unit':''} 37 | load_stat['load_5_min'] = {'volume':float(load_info[1]), 'unit':''} 38 | load_stat['load_15_min'] = {'volume':float(load_info[2]), 'unit':''} 39 | load_stat['nr_thread'] = load_info[3] 40 | load_stat['last_pid'] = load_info[4] 41 | except: 42 | print "Unexpected error:", sys.exc_info()[1] 43 | finally: 44 | if f: 45 | f.close() 46 | return load_stat 47 | 48 | if __name__=='__main__': 49 | load = LoadStatPollster(name='load') 50 | util.print_list(load.getSample()) 51 | -------------------------------------------------------------------------------- /pollster/uptime.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -* 2 | # Copyright © 2013 Computer Network Information Center, Chinese Academy of Sciences 3 | # 4 | # Author: Jing Shao 5 | 6 | from collections import OrderedDict 7 | import pprint 8 | import util 9 | import time 10 | from PollsterClass import Pollster 11 | 12 | 13 | class UptimePollster(Pollster): 14 | def __init__(self, name='uptime_info'): 15 | super(UptimePollster, self).__init__(name=name) 16 | 17 | def getSample(self): 18 | cpu_info = OrderedDict() 19 | proc_info = OrderedDict() 20 | uptime_info = {} 21 | 22 | nprocs = 0 23 | 24 | try: 25 | # Get cpu number 26 | if util.is_exist('/proc/cpuinfo'): 27 | with open('/proc/cpuinfo') as f: 28 | for line in f: 29 | if not line.strip(): 30 | nprocs += 1 31 | # Get uptime and idletime 32 | if util.is_exist('/proc/uptime'): 33 | with open('/proc/uptime') as f: 34 | for line in f: 35 | if line.strip(): 36 | if len(line.split(' ')) == 2: 37 | uptime_info['uptime'] = {'volume':float(line.split(' ')[0].strip()),'unit':'s'} 38 | uptime_info['idletime'] = {'volume':float(line.split(' ')[1].strip()),'unit':'s'} 39 | uptime_info['cpu_num'] = {'volume':nprocs,'unit':''} 40 | # Compute idle rate 41 | uptime_info['idle_rate'] = {'volume':(uptime_info['idletime']['volume'] * 100) / (uptime_info['cpu_num']['volume'] * uptime_info['uptime']['volume']),'unit':'%'} 42 | except: 43 | print "Unexpected error:", sys.exc_info()[1] 44 | finally: 45 | return uptime_info 46 | 47 | if __name__=='__main__': 48 | print UptimePollster().getSample() 49 | -------------------------------------------------------------------------------- /pollster/mem.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -* 2 | # Copyright © 2013 Computer Network Information Center, Chinese Academy of Sciences 3 | # 4 | # Author: Jing Shao 5 | 6 | from collections import OrderedDict 7 | from PollsterClass import Pollster 8 | import util 9 | 10 | class MemInfoPollster(Pollster): 11 | def __init__(self, name='mem_info'): 12 | super(MemInfoPollster, self).__init__(name=name) 13 | 14 | def _changeUnit(self, value, force_unit=None): 15 | unit_list = ('KB', 'MB', 'GB') 16 | rate_list = (1, 17 | 1024, 18 | 1024*1024) 19 | 20 | if force_unit: 21 | if force_unit in unit_list: 22 | tmp_value = float(value)/rate_list[unit_list.index(force_unit)] 23 | return {'volume':round(tmp_value, 2), 'unit':force_unit} 24 | else: 25 | return {'volume':round(value, 2), 'unit':'KB'} 26 | else: 27 | for unit, rate in zip(unit_list, rate_list): 28 | tmp_value = float(value)/rate 29 | if (tmp_value >= 0 and tmp_value < 1024) or (unit_list.index(unit) == len(unit_list)-1): 30 | return {'volume':round(tmp_value, 2), 'unit':unit} 31 | 32 | def getSample(self): 33 | mem_info = OrderedDict() 34 | 35 | try: 36 | if util.is_exist('/proc/meminfo'): 37 | #close file is unnecessary 38 | with open('/proc/meminfo') as f: 39 | for line in f: 40 | tmp = line.split(':') 41 | if len(tmp) == 2: 42 | vol_unit = tmp[1].strip().split(' ') 43 | if len(vol_unit) == 2: 44 | tmp_value = self._changeUnit(value=long(vol_unit[0]), force_unit='MB') 45 | elif len(vol_unit) == 1: 46 | tmp_value = {'volume':long(long(vol_unit[0])), 'unit':''} 47 | mem_info[tmp[0].strip()] = tmp_value 48 | except: 49 | print "Unexpected error:", sys.exc_info()[1] 50 | finally: 51 | return mem_info 52 | 53 | if __name__=='__main__': 54 | mem = MemInfoPollster() 55 | util.print_list(mem.getSample()) 56 | -------------------------------------------------------------------------------- /start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | workspace=$(cd `dirname $0`; pwd) 4 | 5 | # check if HttpServer is running 6 | PID_httpsvr=`ps -ef | grep HttpServer.py | grep -v grep | awk '{print $2}'` 7 | 8 | if [ -z "$PID_httpsvr" ] 9 | then 10 | nohup python ${workspace}/HttpServer.py ${workspace} > /tmp/httpsvr.log 2>&1 & 11 | echo "Start HttpServer done" 12 | fi 13 | 14 | sleep 1 15 | 16 | # check if PollManager is running 17 | PID_poll=`ps -ef | grep PollManager.py | grep -v grep | awk '{print $2}'` 18 | 19 | if [ -z "$PID_poll" ] 20 | then 21 | python ${workspace}/PollManager.py start 22 | python ${workspace}/PollManager.py setintvl 6 23 | python ${workspace}/PollManager.py setpoll "['pollster.cpu.CPUUsagePollster','pollster.mem.MemInfoPollster','pollster.load.LoadStatPollster','pollster.disk.DiskUsagePollster','pollster.net.NetStatPollster','pollster.uptime.UptimePollster']" 24 | echo "Start Polling task done" 25 | fi 26 | 27 | # add start.sh to rc.local 28 | rc_local_file="null" 29 | command="/bin/bash $workspace/start.sh" 30 | 31 | if [ -d "/etc/rc.d" ];then 32 | rc_local_file="/etc/rc.d/rc.local" 33 | else 34 | rc_local_file="/etc/rc.local" 35 | fi 36 | 37 | if [ -f "$rc_local_file" ]; then 38 | is_exist=`grep -n "$command" $rc_local_file` 39 | has_exit_0=`grep -n "exit 0" $rc_local_file` 40 | 41 | if [ -z "$is_exist" ]; then 42 | if [ -z "$has_exit_0" ]; then 43 | echo $command >> $rc_local_file 44 | else 45 | sed -i "/exit 0/ i $command" $rc_local_file 46 | fi 47 | fi 48 | else 49 | cat > $rc_local_file << _done_ 50 | #!/bin/sh 51 | $command 52 | exit 0 53 | _done_ 54 | chmod a+x $rc_local_file 55 | systemctl start rc-local.service 56 | fi 57 | 58 | # add check task to /etc/cron.d 59 | cron_procagent="/etc/cron.d/procagent" 60 | cron_path="/usr/sbin/cron" 61 | crond_path="/usr/sbin/crond" 62 | 63 | if [ ! -f "$cron_procagent" ]; then 64 | 65 | cat > ${cron_procagent} << _done_ 66 | SHELL=/bin/sh 67 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 68 | */5 * * * * root /bin/bash ${workspace}/start.sh 69 | _done_ 70 | if [ -f "$cron_path" ]; then 71 | service cron restart 72 | elif [ -f "$crond_path" ]; then 73 | service crond restart 74 | fi 75 | 76 | echo "Add crontab done" 77 | fi 78 | 79 | echo "Agent running OK" 80 | -------------------------------------------------------------------------------- /pollster/util.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -* 2 | # Copyright © 2013 Computer Network Information Center, Chinese Academy of Sciences 3 | # 4 | # Author: Jing Shao 5 | 6 | import os 7 | import json 8 | import importlib 9 | import urllib2 10 | 11 | ''' 12 | Check the file. 13 | ''' 14 | def is_exist(filename): 15 | return os.path.exists(filename) 16 | 17 | ''' 18 | Print list or object. 19 | ''' 20 | def print_list(objList): 21 | jsonDumpsIndentStr = json.dumps(objList, indent=1) 22 | print jsonDumpsIndentStr 23 | 24 | ''' 25 | Append file. 26 | ''' 27 | def append_file(content, filename): 28 | if len(content) != 0: 29 | output = open(filename, 'a') 30 | output.write(content) 31 | output.close() 32 | else: 33 | return 34 | 35 | ''' 36 | Load module and class 37 | ''' 38 | def load_class(clsname): 39 | cls = None 40 | bse_name = None 41 | try: 42 | r = clsname.rfind('.') 43 | dft_name = '__main__' 44 | bse_name = clsname 45 | if r >= 0: 46 | dft_name = clsname[0:r] 47 | bse_name = clsname[r+1:] 48 | #mod = __import__(dft_name) 49 | mod = importlib.import_module(dft_name) 50 | cls = getattr(mod, bse_name) 51 | except: 52 | return None 53 | finally: 54 | return bse_name, cls 55 | 56 | def load_conf(confname): 57 | paras = {} 58 | if is_exist(confname): 59 | with open(confname) as f: 60 | for line in f: 61 | tmp = line.strip().split('=') 62 | if len(tmp) == 2: 63 | paras[tmp[0]] = tmp[1] 64 | return paras 65 | 66 | def update_conf(confname, paras): 67 | w_str = '' 68 | if paras: 69 | for p in paras: 70 | w_str += '%s=%s\n' %(p, paras[p]) 71 | if w_str: 72 | try: 73 | output = open(confname, 'w') 74 | output.write(w_str) 75 | except: 76 | print 'Update conf error!' 77 | finally: 78 | if output: 79 | output.close() 80 | 81 | def rd_data(url): 82 | '''Read data/parameter through HttpServer.''' 83 | 84 | res = None 85 | try: 86 | req = urllib2.Request(url) 87 | res = urllib2.urlopen(req, timeout=5) 88 | return res.read() 89 | except urllib2.URLError, e: 90 | return False 91 | except urllib2.HTTPError, e: 92 | return False 93 | finally: 94 | if res: 95 | res.close() 96 | 97 | def wr_data(url, obj): 98 | '''Write data/parameter through HttpServer.''' 99 | data = json.dumps(obj) 100 | res = None 101 | try: 102 | req = urllib2.Request(url, data, {'Content-Type': 'application/json'}) 103 | res = urllib2.urlopen(req, timeout=5) 104 | return res.read() 105 | except urllib2.URLError, e: 106 | print e.reason 107 | return False 108 | except urllib2.HTTPError, e: 109 | print e.code 110 | return False 111 | finally: 112 | if res: 113 | res.close() 114 | 115 | if __name__=='__main__': 116 | print load_class('cpu.CPUInfoPollster') 117 | -------------------------------------------------------------------------------- /pollster/cpu.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -* 2 | # Copyright © 2013 Computer Network Information Center, Chinese Academy of Sciences 3 | # 4 | # Author: Jing Shao 5 | 6 | from collections import OrderedDict 7 | import pprint 8 | import util 9 | import time 10 | from PollsterClass import Pollster 11 | 12 | class CPUInfoPollster(Pollster): 13 | def __init__(self, name='cpu_info'): 14 | super(CPUInfoPollster, self).__init__(name=name) 15 | 16 | def getSample(self): 17 | cpu_info = OrderedDict() 18 | proc_info = OrderedDict() 19 | 20 | nprocs = 0 21 | 22 | try: 23 | if util.is_exist('/proc/cpuinfo'): 24 | with open('/proc/cpuinfo') as f: 25 | for line in f: 26 | if not line.strip(): 27 | cpu_info['proc%s' % nprocs] = proc_info 28 | nprocs += 1 29 | proc_info = OrderedDict() 30 | else: 31 | if len(line.split(':')) == 2: 32 | proc_info[line.split(':')[0].strip()] = line.split(':')[1].strip() 33 | else: 34 | proc_info[line.split(':')[0].strip()] = '' 35 | except: 36 | print "Unexpected error:", sys.exc_info()[1] 37 | finally: 38 | return cpu_info 39 | 40 | class CPUUsagePollster(Pollster): 41 | def __init__(self, name='cpu_info'): 42 | super(CPUUsagePollster, self).__init__(name=name) 43 | 44 | ''' 45 | Read CPU stat from /proc/stat. 46 | ''' 47 | def _read_proc_stat(self): 48 | cpu_line = OrderedDict() 49 | f = None 50 | 51 | try: 52 | if util.is_exist('/proc/stat'): 53 | f = open('/proc/stat') 54 | lines = f.readlines() 55 | for line in lines: 56 | if line.startswith('cpu'): 57 | tmp = line.strip().split() 58 | cpu_line[tmp[0]] = tmp[1:len(tmp)] 59 | except: 60 | print "Unexpected error: ", sys.exc_info[1] 61 | finally: 62 | if f: 63 | f.close() 64 | return cpu_line 65 | 66 | def getSample(self): 67 | cpu_usage = {} 68 | cpu_line = self._read_proc_stat() 69 | total_1 = {} 70 | idle_1 = {} 71 | total_2 = {} 72 | idle_2 = {} 73 | 74 | if cpu_line: 75 | for item in cpu_line: 76 | total_1[item] = float(cpu_line[item][0]) + float(cpu_line[item][1]) + \ 77 | float(cpu_line[item][2]) + float(cpu_line[item][3]) + \ 78 | float(cpu_line[item][4]) + float(cpu_line[item][5]) + float(cpu_line[item][6]) 79 | idle_1[item] = float(cpu_line[item][3]) 80 | 81 | time.sleep(1) 82 | 83 | cpu_line_2 = self._read_proc_stat() 84 | 85 | if cpu_line_2: 86 | for item in cpu_line_2: 87 | total_2[item] = float(cpu_line_2[item][0]) + float(cpu_line_2[item][1]) + \ 88 | float(cpu_line_2[item][2]) + float(cpu_line_2[item][3]) + \ 89 | float(cpu_line_2[item][4]) + float(cpu_line_2[item][5]) + float(cpu_line_2[item][6]) 90 | idle_2[item] = float(cpu_line_2[item][3]) 91 | 92 | if total_1 and total_2: 93 | for item in total_1: 94 | cpu_usage[item] = {'volume':round(100 * (1 - float(idle_2[item] - idle_1[item])/float(total_2[item] - total_1[item])), 2), 'unit':'%'} 95 | return cpu_usage 96 | 97 | -------------------------------------------------------------------------------- /PollManager.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -* 2 | # Copyright © 2013 Computer Network Information Center, Chinese Academy of Sciences 3 | # 4 | # Author: Jing Shao 5 | 6 | import sys, time, datetime 7 | import json, re, socket 8 | from collections import OrderedDict 9 | from DaemonClass import Daemon 10 | from pollster import util 11 | 12 | class PollManager(Daemon): 13 | _intvl = None 14 | _pollsters = OrderedDict() 15 | _wr_url = None 16 | 17 | def __init__(self, 18 | pidfile='/tmp/daemoncls.pid', 19 | stdin='/dev/null', 20 | stdout='/dev/null', 21 | #stdout='/tmp/poll_stdout.out', 22 | stderr='/dev/null', 23 | intvl=10, 24 | wr_url='http://127.0.0.1:8655/'): 25 | super(PollManager, self).__init__(pidfile=pidfile, stdin=stdin, stdout=stdout, stderr=stderr) 26 | self._wr_url = wr_url 27 | 28 | # Read interval 29 | tmp_str = util.rd_data('%s%s' %(self._wr_url, 'getintvl')) 30 | if tmp_str: 31 | self._intvl = int(tmp_str) 32 | else: 33 | self._intvl = intvl 34 | 35 | # Read pollsters 36 | tmp_str = util.rd_data('%s%s' %(self._wr_url, 'getpollsters')) 37 | if tmp_str: 38 | tmp_list = eval(tmp_str) 39 | if type(tmp_list) == type(''): 40 | tmp_list = eval(tmp_list) 41 | for poll in tmp_list: 42 | p_name, cls = util.load_class(poll) 43 | if p_name and cls: 44 | self._pollsters[p_name] = cls() 45 | else: 46 | self._pollsters = OrderedDict() 47 | 48 | def set_intvl(self, intvl): 49 | '''Set interval of polling''' 50 | if intvl >= 1: 51 | self._intvl = intvl 52 | util.wr_data('%s%s' %(self._wr_url, 'setintvl'), intvl) 53 | self.restart() 54 | 55 | def set_pollsters(self, pollsters): 56 | '''Set pollster list''' 57 | poll_list = eval(pollsters) 58 | self._pollsters = OrderedDict() 59 | for poll in poll_list: 60 | p_name, cls = util.load_class(poll) 61 | if p_name and cls: 62 | self._pollsters[p_name] = cls() 63 | util.wr_data('%s%s' %(self._wr_url, 'setpollsters'), pollsters) 64 | self.restart() 65 | 66 | def _poll(self): 67 | '''Execute poll task''' 68 | poll_data = OrderedDict() 69 | if self._pollsters: 70 | for pollster in self._pollsters: 71 | poll_data[pollster] = {} 72 | poll_data[pollster]['timestamp'] = time.asctime(time.localtime()) 73 | #poll_data[pollster]['timestamp'] = time.time() 74 | poll_data[pollster]['data'] = self._pollsters[pollster].getSample() 75 | return poll_data 76 | 77 | def run(self): 78 | c = 0 79 | while True: 80 | wr_obj = {} 81 | try: 82 | wr_obj['data'] = self._poll() 83 | wr_obj['timestamp'] = time.asctime(time.localtime()) 84 | wr_obj['hostname'] = socket.gethostname() 85 | wr_obj['ip_address'] = socket.gethostbyname(wr_obj['hostname']) 86 | except socket.gaierror, e: 87 | wr_obj['ip_address'] = '' 88 | finally: 89 | util.wr_data('%s%s' %(self._wr_url, 'setdata'), wr_obj) 90 | time.sleep(self._intvl) 91 | c += 1 92 | 93 | if __name__ == "__main__": 94 | daemon = PollManager(pidfile='/tmp/polling_task.pid', 95 | intvl=10) 96 | if len(sys.argv) == 2: 97 | if 'start' == sys.argv[1]: 98 | daemon.start() 99 | elif 'stop' == sys.argv[1]: 100 | daemon.stop() 101 | elif 'restart' == sys.argv[1]: 102 | daemon.restart() 103 | else: 104 | print 'Unknown command' 105 | sys.exit(2) 106 | elif len(sys.argv) == 3: 107 | if 'setintvl' == sys.argv[1]: 108 | if re.match(r'^-?\d+$', sys.argv[2]) or re.match(r'^-?(\.\d+|\d+(\.\d+)?)', sys.argv[2]): 109 | daemon.set_intvl(int(sys.argv[2])) 110 | print 'Set interval: %s' %sys.argv[2] 111 | elif 'setpoll' == sys.argv[1]: 112 | poll_list = None 113 | try: 114 | poll_list = eval(sys.argv[2]) 115 | except: 116 | print '%s is not a list.' %sys.argv[2] 117 | if poll_list: 118 | daemon.set_pollsters(sys.argv[2]) 119 | else: 120 | print 'USAGE: %s start/stop/restart' % sys.argv[0] 121 | sys.exit(2) 122 | 123 | -------------------------------------------------------------------------------- /HttpServer.py: -------------------------------------------------------------------------------- 1 | from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler 2 | from SocketServer import ThreadingMixIn 3 | import threading 4 | import json 5 | from datetime import datetime 6 | import time 7 | import subprocess 8 | import sys 9 | 10 | # Look up the full hostname using gethostbuaddr() is too slow. 11 | import BaseHTTPServer 12 | def not_insance_address_string(self): 13 | host, port = self.client_address[:2] 14 | # Just only return host. 15 | return '%s (no getfqdn)' % host 16 | BaseHTTPServer.BaseHTTPRequestHandler.address_string = not_insance_address_string 17 | 18 | class Handler(BaseHTTPRequestHandler): 19 | content = {} 20 | intvl = 10 21 | pollsters = ['pollster.cpu.CPUUsagePollster','pollster.mem.MemInfoPollster','pollster.load.LoadStatPollster','pollster.disk.DiskUsagePollster','pollster.net.NetStatPollster'] 22 | 23 | poll_path = '/usr/local/procagent' 24 | 25 | # timestamp of get from host 26 | ts_get = '' 27 | 28 | def do_GET(self): 29 | if self.path == '/getdata': 30 | self.send_response(200) 31 | self.send_header("Content-type", "text/json") 32 | Handler.ts_get = time.asctime(time.localtime()) 33 | 34 | t_content = datetime.strptime(Handler.content['timestamp'], "%a %b %d %H:%M:%S %Y") 35 | t_last_get = datetime.strptime(Handler.ts_get, "%a %b %d %H:%M:%S %Y") 36 | 37 | if (t_last_get - t_content).seconds < 60: 38 | Handler.content['status'] = 'NORMAL' 39 | else: 40 | Handler.content['status'] = 'POLLING_TIMEOUT' 41 | Handler.content['data'] = {} 42 | pingPopen = subprocess.Popen(args='python %s/PollManager.py restart' % (Handler.poll_path), shell=True) 43 | obj_str = json.dumps(Handler.content) 44 | self.send_header("Content-Length", str(len(obj_str))) 45 | self.end_headers() 46 | self.wfile.write(obj_str.encode()) 47 | self.wfile.write('\n') 48 | elif self.path == '/getintvl': 49 | self.send_response(200) 50 | self.end_headers() 51 | self.wfile.write(Handler.intvl) 52 | self.wfile.write('\n') 53 | elif self.path == '/getpollsters': 54 | self.send_response(200) 55 | self.send_header("Content-type", "text/json") 56 | poll_str = json.dumps(Handler.pollsters) 57 | self.send_header("Content-Length", str(len(poll_str))) 58 | self.end_headers() 59 | self.wfile.write(poll_str.encode()) 60 | self.wfile.write('\n') 61 | elif self.path == '/rstsvr': 62 | pingPopen = subprocess.Popen(args='python %s/PollManager.py restart' % (Handler.poll_path), shell=True) 63 | self.send_response(200) 64 | self.end_headers() 65 | self.wfile.write('Restart server ok!') 66 | self.wfile.write('\n') 67 | else: 68 | self.send_response(404) 69 | self.end_headers() 70 | 71 | def do_POST(self): 72 | if self.path == '/setdata': 73 | length = self.headers['content-length'] 74 | data = self.rfile.read(int(length)) 75 | Handler.content = eval(data.decode()) 76 | self.send_response(200) 77 | self.end_headers() 78 | self.wfile.write(str(Handler.content)) 79 | self.wfile.write('\n') 80 | elif self.path == '/setintvl': 81 | length = self.headers['content-length'] 82 | data = self.rfile.read(int(length)) 83 | Handler.intvl = eval(data.decode()) 84 | self.send_response(200) 85 | self.end_headers() 86 | self.wfile.write(str(Handler.intvl)) 87 | self.wfile.write('\n') 88 | elif self.path == '/setpollsters': 89 | length = self.headers['content-length'] 90 | data = self.rfile.read(int(length)) 91 | Handler.pollsters = eval(data.decode()) 92 | self.send_response(200) 93 | self.end_headers() 94 | self.wfile.write(str(Handler.pollsters)) 95 | self.wfile.write('\n') 96 | else: 97 | self.send_response(404) 98 | self.end_headers() 99 | 100 | class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): 101 | """Handle requests in a separate thread.""" 102 | 103 | if __name__ == '__main__': 104 | server = None 105 | try: 106 | server = ThreadedHTTPServer(('0.0.0.0', 8655), Handler) 107 | if sys.argv[1]: 108 | Handler.poll_path = sys.argv[1] 109 | print 'Starting server, use to stop' 110 | server.serve_forever() 111 | except: 112 | if server: 113 | server.socket.close() 114 | -------------------------------------------------------------------------------- /pollster/net.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -* 2 | # Copyright © 2013 Computer Network Information Center, Chinese Academy of Sciences 3 | # 4 | # Author: Jing Shao 5 | 6 | from collections import OrderedDict 7 | from PollsterClass import Pollster 8 | import pprint 9 | import util 10 | import sys 11 | import time 12 | 13 | ''' 14 | cat /proc/net/dev 15 | 16 | Inter-| Receive | Transmit 17 | face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed 18 | eth0: 30172565 287376 0 0 0 0 0 0 1735683 10611 0 0 0 0 0 0 19 | lo: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 20 | ''' 21 | class NetStatPollster(Pollster): 22 | def __init__(self, name='net_stat'): 23 | super(NetStatPollster, self).__init__(name=name) 24 | 25 | def _get_data(self): 26 | net_state = OrderedDict() 27 | title = OrderedDict() 28 | total_item = 0 29 | 30 | try: 31 | if util.is_exist('/proc/net/dev'): 32 | with open('/proc/net/dev') as f: 33 | for line in f: 34 | ''' 35 | Read items 36 | ''' 37 | if line.strip().startswith('Inter'): 38 | tmp = line.strip().split('|') 39 | for i in range(1, len(tmp)): 40 | title[tmp[i].strip()] = [] 41 | elif line.strip().startswith('face'): 42 | tmp = line.strip().split('|') 43 | for i in range(1, len(tmp)): 44 | title[title.items()[i-1][0]] = tmp[i].strip().split() 45 | total_item += len(title.items()[i-1][1]) 46 | else: 47 | tmp = line.strip().split(':') 48 | tmp_data = OrderedDict() 49 | 50 | value = tmp[1].strip().split() 51 | if len(value) == total_item: 52 | cnt = 0 53 | for t_item in title.items(): 54 | tmp_data[t_item[0]] = {} 55 | for it in t_item[1]: 56 | tmp_data[t_item[0]][it] = value[cnt] 57 | cnt += 1 58 | else: 59 | print 'number of items error' 60 | 61 | net_state[tmp[0]] = tmp_data 62 | 63 | total_data = {'net_bytes_in':0, 64 | 'net_bytes_out':0, 65 | 'net_pkts_in':0, 66 | 'net_pkts_out':0} 67 | for key, value in net_state.items(): 68 | if key.startswith('eth'): 69 | total_data['net_bytes_in'] += int(value['Receive']['bytes']) 70 | total_data['net_bytes_out'] += int(value['Transmit']['bytes']) 71 | total_data['net_pkts_in'] += int(value['Receive']['packets']) 72 | total_data['net_pkts_out'] += int(value['Transmit']['packets']) 73 | except: 74 | print "Unexpected error:", sys.exc_info()[1] 75 | finally: 76 | return net_state, total_data 77 | 78 | def getSample(self): 79 | intvl = .5 80 | 81 | net_state_1, total_data_1 = self._get_data() 82 | time.sleep(intvl) 83 | net_state_2, total_data_2 = self._get_data() 84 | 85 | flow_data={} 86 | flow_data['net_bytes_in'] = {'volume':int((total_data_2['net_bytes_in'] - total_data_1['net_bytes_in'])/intvl), 'unit':'B/s'} 87 | flow_data['net_bytes_out'] = {'volume':int((total_data_2['net_bytes_out'] - total_data_1['net_bytes_out'])/intvl), 'unit':'B/s'} 88 | flow_data['net_pkts_in'] = {'volume':int((total_data_2['net_pkts_in'] - total_data_1['net_pkts_in'])/intvl), 'unit':'p/s'} 89 | flow_data['net_pkts_out'] = {'volume':int((total_data_2['net_pkts_out'] - total_data_1['net_pkts_out'])/intvl), 'unit':'p/s'} 90 | flow_data['net_bytes_in_sum'] = {'volume':int(total_data_2['net_bytes_in']), 'unit':'B'} 91 | flow_data['net_bytes_out_sum'] = {'volume':int(total_data_2['net_bytes_out']), 'unit':'B'} 92 | 93 | return flow_data 94 | 95 | def test(self): 96 | net_state, total_data = self._get_data() 97 | 98 | util.print_list(net_state) 99 | util.print_list(total_data) 100 | 101 | if __name__=='__main__': 102 | net_stat = NetStatPollster() 103 | net_stat.test() 104 | -------------------------------------------------------------------------------- /DaemonClass.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys, os, time 4 | import atexit 5 | from signal import SIGTERM 6 | from collections import OrderedDict 7 | 8 | class Daemon(object): 9 | ''' 10 | Usage: subclass the Daemon class and override the run() method 11 | ''' 12 | 13 | def __init__(self, 14 | pidfile, 15 | stdin='/dev/stdin', 16 | stdout='/dev/stdout', 17 | stderr='/dev/stderr'): 18 | self.stdin = stdin 19 | self.stdout = stdout 20 | self.stderr = stderr 21 | self.pidfile = pidfile 22 | 23 | def daemonize(self): 24 | try: 25 | pid = os.fork() 26 | if pid > 0: 27 | sys.exit(0) 28 | except OSError, e: 29 | sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) 30 | sys.exit(1) 31 | 32 | # decouple from parent environment 33 | os.chdir("/") 34 | os.setsid() 35 | os.umask(0) 36 | 37 | # do second fork 38 | try: 39 | pid = os.fork() 40 | if pid > 0: 41 | # exit from second parent 42 | sys.exit(0) 43 | except OSError, e: 44 | sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) 45 | sys.exit(1) 46 | 47 | # redirect standard file descriptors 48 | sys.stdout.flush() 49 | sys.stderr.flush() 50 | si = file(self.stdin, 'r') 51 | so = file(self.stdout, 'a+') 52 | se = file(self.stderr, 'a+', 0) 53 | os.dup2(si.fileno(), sys.stdin.fileno()) 54 | os.dup2(so.fileno(), sys.stdout.fileno()) 55 | os.dup2(se.fileno(), sys.stderr.fileno()) 56 | 57 | # write pidfile 58 | atexit.register(self.delpid) 59 | pid = str(os.getpid()) 60 | file(self.pidfile,'w+').write("%s\n" % pid) 61 | 62 | def delpid(self): 63 | os.remove(self.pidfile) 64 | 65 | def start(self): 66 | """ 67 | Start the daemon 68 | """ 69 | # Check for a pidfile to see if the daemon already runs 70 | try: 71 | pf = file(self.pidfile,'r') 72 | pid = int(pf.read().strip()) 73 | pf.close() 74 | except IOError: 75 | pid = None 76 | 77 | if pid: 78 | message = "pidfile %s already exist. Daemon already running?\n" 79 | sys.stderr.write(message % self.pidfile) 80 | sys.exit(1) 81 | 82 | # Start the daemon 83 | self.daemonize() 84 | self.run() 85 | 86 | def stop(self): 87 | """ 88 | Stop the daemon 89 | """ 90 | # Get the pid from the pidfile 91 | try: 92 | pf = file(self.pidfile,'r') 93 | pid = int(pf.read().strip()) 94 | pf.close() 95 | except IOError: 96 | pid = None 97 | 98 | if not pid: 99 | message = "pidfile %s does not exist. Daemon not running?\n" 100 | sys.stderr.write(message % self.pidfile) 101 | return # not an error in a restart 102 | 103 | # Try killing the daemon process 104 | try: 105 | while 1: 106 | os.kill(pid, SIGTERM) 107 | time.sleep(0.1) 108 | except OSError, err: 109 | err = str(err) 110 | if err.find("No such process") > 0: 111 | if os.path.exists(self.pidfile): 112 | os.remove(self.pidfile) 113 | else: 114 | print str(err) 115 | sys.exit(1) 116 | 117 | def restart(self): 118 | """ 119 | Restart the daemon 120 | """ 121 | self.stop() 122 | self.start() 123 | 124 | def run(self): 125 | c = 0 126 | while True: 127 | poll_info = poll() 128 | content = time.asctime(time.localtime()) + '\n' 129 | for item in poll_info: 130 | content += '%s: %s\n' %(item, poll_info[item]) 131 | content += '----------------------------\n\n' 132 | appendFile(content, '/opt/testwrite.log') 133 | time.sleep(3) 134 | c = c + 1 135 | 136 | if __name__ == "__main__": 137 | daemon = Daemon('/tmp/daemon-example.pid') 138 | if len(sys.argv) == 2: 139 | if 'start' == sys.argv[1]: 140 | daemon.start() 141 | elif 'stop' == sys.argv[1]: 142 | daemon.stop() 143 | elif 'restart' == sys.argv[1]: 144 | daemon.restart() 145 | else: 146 | print 'Unknown command' 147 | sys.exit(2) 148 | else: 149 | print 'USAGE: %s start/stop/restart' % sys.argv[0] 150 | sys.exit(2) 151 | -------------------------------------------------------------------------------- /statistic.py: -------------------------------------------------------------------------------- 1 | #!/usr/env python 2 | import sys 3 | import time 4 | import string 5 | import datetime 6 | import pymongo 7 | import getopt 8 | import pytz 9 | from functools import wraps 10 | from pollster import util 11 | 12 | COUNTER_NAME_FILTER = {'instance.cpu.usage':{'avg':'counter_volume', 'peak':'counter_volume'}, 13 | 'instance.mem.usage':{'avg':'counter_volume', 'peak':'counter_volume'}, 14 | 'instance.net.in.bytes':{'cum':'bytes_in_sum', 'avg':'counter_volume', 'peak':'counter_volume'}, 15 | 'instance.net.out.bytes':{'cum':'bytes_out_sum', 'avg':'counter_volume', 'peak':'counter_volume'},} 16 | 17 | TIME_FORMAT = "%Y-%m-%d %H:%M:%S" 18 | TZ = pytz.timezone('Asia/Taipei') 19 | 20 | def timeit(func): 21 | @wraps(func) 22 | def wrapper(*args, **kwargs): 23 | start = time.time() 24 | result = func(*args, **kwargs) 25 | end = time.time() 26 | print 'cost:%s sec' %(round(end-start, 4)) 27 | return result 28 | return wrapper 29 | 30 | @timeit 31 | def run_statistic(st, et, conn): 32 | db = conn['ceilometer'] 33 | col = db['meter'] 34 | 35 | data_dict = {} 36 | for k, v in COUNTER_NAME_FILTER.items(): 37 | query = {'counter_name':k, 'timestamp':{'$gte':st, '$lte':et}} 38 | cursor = col.find(query).sort('timestamp', pymongo.DESCENDING) 39 | 40 | instance_dict = {} 41 | for item in cursor: 42 | if not instance_dict.has_key(item['resource_id']): 43 | # when meet a new instance 44 | tmp = {} 45 | for v_k, v_v in v.items(): 46 | if v_k == 'avg': 47 | tmp['avg'] = item[v_v] 48 | elif v_k == 'peak': 49 | tmp['peak'] = item[v_v] 50 | #tmp['peak_time'] = item['timestamp'].strftime(TIME_FORMAT) 51 | tmp['peak_time'] = item['timestamp'].replace(tzinfo=pytz.utc).astimezone(TZ).strftime(TIME_FORMAT) 52 | elif v_k == 'cum': 53 | tmp['cum'] = item['resource_metadata'][v_v] 54 | tmp['cum_last'] = item['resource_metadata'][v_v] 55 | tmp['cnt'] = 1 56 | instance_dict[item['resource_id']] = tmp 57 | else: 58 | for v_k, v_v in v.items(): 59 | if v_k == 'avg': 60 | instance_dict[item['resource_id']]['avg'] += item[v_v] 61 | elif v_k == 'peak' and instance_dict[item['resource_id']]['peak'] < item[v_v]: 62 | instance_dict[item['resource_id']]['peak'] = item[v_v] 63 | #instance_dict[item['resource_id']]['peak_time'] = item['timestamp'].strftime(TIME_FORMAT) 64 | instance_dict[item['resource_id']]['peak_time'] = item['timestamp'].replace(tzinfo=pytz.utc).astimezone(TZ).strftime(TIME_FORMAT) 65 | elif v_k == 'cum': 66 | if instance_dict[item['resource_id']]['cum_last'] > item['resource_metadata'][v_v]: 67 | # reboot or clean cumulative value 68 | instance_dict[item['resource_id']]['cum'] += item['resource_metadata'][v_v] 69 | else: 70 | instance_dict[item['resource_id']]['cum'] += item['resource_metadata'][v_v] - instance_dict[item['resource_id']]['cum_last'] 71 | instance_dict[item['resource_id']]['cum_last'] = item['resource_metadata'][v_v] 72 | instance_dict[item['resource_id']]['cnt'] += 1 73 | for ins_k, ins_v in instance_dict.items(): 74 | if ins_v.has_key('avg'): 75 | ins_v['avg'] = float(ins_v['avg']) / ins_v['cnt'] 76 | data_dict[k] = instance_dict 77 | return data_dict 78 | 79 | if __name__=='__main__': 80 | conn_mongo = None 81 | host = None 82 | port = None 83 | st = None 84 | et = None 85 | 86 | opts, args = getopt.getopt(sys.argv[1:], "a:s:e:h") 87 | for op, value in opts: 88 | if op == "-a": 89 | host = value[0:value.rindex(':')] 90 | port = string.atoi(value[value.rindex(':')+1:len(value)]) 91 | elif op == "-s": 92 | st = datetime.datetime.strptime(value, TIME_FORMAT) 93 | st = st.replace(tzinfo=TZ).astimezone(pytz.utc) 94 | st = TZ.normalize(st) 95 | elif op == "-e": 96 | et = datetime.datetime.strptime(value, TIME_FORMAT) 97 | et = et.replace(tzinfo=TZ).astimezone(pytz.utc) 98 | et = TZ.normalize(et) 99 | elif op == "-h": 100 | print 'python statistic.py -a 127.0.0.1:27017 -s "start_time" -e "end_time"' 101 | 102 | if host and port and st: 103 | if not et: 104 | et = datetime.datetime.now() 105 | et = et.replace(tzinfo=TZ).astimezone(pytz.utc) 106 | et = TZ.normalize(et) 107 | conn_mongo = pymongo.Connection(host, port) 108 | util.print_list(run_statistic(st=st, et=et, conn=conn_mongo)) 109 | conn_mongo.close() 110 | -------------------------------------------------------------------------------- /pollster/disk.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -* 2 | # Copyright © 2013 Computer Network Information Center, Chinese Academy of Sciences 3 | # 4 | # Author: Jing Shao 5 | 6 | import os 7 | import time 8 | from collections import OrderedDict 9 | from PollsterClass import Pollster 10 | import util 11 | 12 | class DiskUsagePollster(Pollster): 13 | def __init__(self, name='disk_stat'): 14 | super(DiskUsagePollster, self).__init__(name=name) 15 | 16 | def _changeUnit(self, value, force_unit=None): 17 | unit_list = ('B', 'KB', 'MB', 'GB', 'TB', 'PB') 18 | rate_list = (1, 19 | 1024, 20 | 1024*1024, 21 | 1024*1024*1024, 22 | 1024*1024*1024*1024, 23 | 1024*1024*1024*1024*1024,) 24 | 25 | if force_unit: 26 | if force_unit in unit_list: 27 | tmp_value = float(value)/rate_list[unit_list.index(force_unit)] 28 | return {'volume':round(tmp_value, 2), 'unit':force_unit} 29 | else: 30 | return {'volume':round(value, 2), 'unit':'B'} 31 | else: 32 | for unit, rate in zip(unit_list, rate_list): 33 | tmp_value = float(value)/rate 34 | if tmp_value >= 1 and tmp_value < 1024: 35 | return {'volume':round(tmp_value, 2), 'unit':unit} 36 | 37 | def _read_diskstats(self, dev): 38 | if dev: 39 | f = open("/proc/diskstats", "r") 40 | dev_data = {} 41 | for line in f: 42 | tmp = line.strip().split() 43 | if dev.has_key(tmp[2]): 44 | # Kernel > 2.6 45 | dev_data[tmp[2]] = {} 46 | dev_data[tmp[2]]['f1'] = float(tmp[3]) # of reads completed 47 | # dev_data[tmp[2]]['f2'] = float(tmp[4]) # of reads merged 48 | dev_data[tmp[2]]['f3'] = float(tmp[5]) # of sectors read 49 | # dev_data[tmp[2]]['f4'] = float(tmp[6]) # of milliseconds spent reading 50 | dev_data[tmp[2]]['f5'] = float(tmp[7]) # of writes completed 51 | # dev_data[tmp[2]]['f6'] = float(tmp[8]) # of writes merged 52 | dev_data[tmp[2]]['f7'] = float(tmp[9]) # of sectors written 53 | # dev_data[tmp[2]]['f8'] = float(tmp[10]) # of milliseconds spent writing 54 | # dev_data[tmp[2]]['f9'] = float(tmp[11]) # of I/Os currently in progress 55 | # dev_data[tmp[2]]['f10'] = float(tmp[12]) # of milliseconds spent doing I/Os 56 | # dev_data[tmp[2]]['f11'] = float(tmp[13]) # weight of of milliseconds spent doing I/Os 57 | return dev_data 58 | else: 59 | return {} 60 | 61 | def _getDiskIO(self, dev_list): 62 | if dev_list: 63 | dev_data = {} 64 | for item in dev_list: 65 | dev_short = item['dev'][item['dev'].rfind('/')+1:] 66 | dev_data[dev_short] = {} 67 | 68 | intvl = 1 69 | disk_stats_1 = self._read_diskstats(dev_data) 70 | time.sleep(intvl) 71 | disk_stats_2 = self._read_diskstats(dev_data) 72 | 73 | disk_io = {} 74 | for disk in disk_stats_2: 75 | disk_io[disk] = {} 76 | 77 | # disk_io[disk]['rrqm/s'] = disk_stats_2[disk]['f2'] - disk_stats_1[disk]['f2'] 78 | # disk_io[disk]['wrqm/s'] = disk_stats_2[disk]['f6'] - disk_stats_1[disk]['f6'] 79 | disk_io[disk]['r/s'] = {'volume':disk_stats_2[disk]['f1'] - disk_stats_1[disk]['f1'], 'unit':''} 80 | disk_io[disk]['w/s'] = {'volume':disk_stats_2[disk]['f5'] - disk_stats_1[disk]['f5'], 'unit':''} 81 | # disk_io[disk]['rsec/s'] = disk_stats_2[disk]['f3'] - disk_stats_1[disk]['f3'] 82 | # disk_io[disk]['wsec/s'] = disk_stats_2[disk]['f7'] - disk_stats_1[disk]['f7'] 83 | rsec_s = disk_stats_2[disk]['f3'] - disk_stats_1[disk]['f3'] 84 | wsec_s = disk_stats_2[disk]['f7'] - disk_stats_1[disk]['f7'] 85 | disk_io[disk]['rkB/s'] = {'volume':rsec_s * 0.5, 'unit':'KB/s'} 86 | disk_io[disk]['wkB/s'] = {'volume':wsec_s * 0.5, 'unit':'KB/s'} 87 | # disk_io[disk]['avgrq-sz'] = round((disk_io[disk]['rsec/s'] + disk_io[disk]['wsec/s'])/(disk_io[disk]['r/s'] + disk_io[disk]['w/s']), 2) 88 | # disk_io[disk]['avgqu-sz'] = round(disk_stats_2[disk]['f11'] - disk_stats_1[disk]['f11'], 2) 89 | # disk_io[disk]['await'] = round(((disk_stats_2[disk]['f4'] - disk_stats_1[disk]['f4'])+(disk_stats_2[disk]['f8'] - disk_stats_1[disk]['f8']))/(disk_io[disk]['r/s']+disk_io[disk]['w/s']), 2) 90 | # disk_io[disk]['r_await'] = round((disk_stats_2[disk]['f4'] - disk_stats_1[disk]['f4'])/disk_io[disk]['r/s'], 2) 91 | # disk_io[disk]['w_await'] = round((disk_stats_2[disk]['f8'] - disk_stats_1[disk]['f8'])/disk_io[disk]['w/s'], 2) 92 | #disk_io[disk]['util'] = 93 | #http://hi.baidu.com/casualfish/item/0126b4b7dbde13e94fc7fdb0 94 | return disk_io 95 | else: 96 | return {} 97 | 98 | def _getDiskPartitions(self, all=False): 99 | """Return all mountd partitions as a nameduple. 100 | If all == False return phyisical partitions only. 101 | """ 102 | key_list = ['dev', 'mnt', 'fstype'] 103 | 104 | phydevs = [] 105 | f = open("/proc/filesystems", "r") 106 | for line in f: 107 | if not line.startswith("nodev"): 108 | phydevs.append(line.strip()) 109 | 110 | # Add nfs4 and glusterfs 111 | if 'nfs4' not in phydevs: 112 | phydevs.append('nfs4') 113 | if 'fuse.glusterfs' not in phydevs: 114 | phydevs.append('fuse.glusterfs') 115 | 116 | retlist = [] 117 | f = open('/etc/mtab', "r") 118 | for line in f: 119 | #if not all and line.startswith('none'): 120 | if not all and line.startswith('none'): 121 | continue 122 | fields = line.split() 123 | device = fields[0] 124 | mountpoint = fields[1] 125 | fstype = fields[2] 126 | if not all and fstype not in phydevs: 127 | continue 128 | if device == 'none': 129 | device = '' 130 | 131 | retlist.append(dict(zip(key_list, fields))) 132 | return retlist 133 | 134 | def _getDiskUsage(self, path): 135 | hd = {} 136 | disk = os.statvfs(path) 137 | ch_rate = 1024 * 1024 * 1024 138 | # Free blocks available to non-super user 139 | hd['available'] = disk.f_bsize * disk.f_bavail 140 | # Total number of free blocks 141 | hd['free'] = disk.f_bsize * disk.f_bfree 142 | # Total number of blocks in filesystem 143 | hd['capacity'] = disk.f_bsize * disk.f_blocks 144 | hd['used'] = float(hd['capacity'] - hd['free'])/hd['capacity'] 145 | return hd 146 | 147 | def getSample(self): 148 | disk_list = self._getDiskPartitions() 149 | # disk io 150 | disk_io = self._getDiskIO(disk_list) 151 | 152 | total_available = 0 153 | total_capacity = 0 154 | total_free = 0 155 | 156 | disk_usage = {} 157 | for item in disk_list: 158 | usg = self._getDiskUsage(item['mnt']) 159 | 160 | dev_short = item['dev'][item['dev'].rfind('/')+1:] 161 | disk_usage[dev_short] = {} 162 | disk_usage[dev_short]['mnt'] = item['mnt'] 163 | disk_usage[dev_short]['fstype'] = item['fstype'] 164 | disk_usage[dev_short]['dev'] = item['dev'] 165 | disk_usage[dev_short]['available'] = self._changeUnit(value=usg['available'], force_unit='GB') 166 | total_available += disk_usage[dev_short]['available']['volume'] 167 | 168 | disk_usage[dev_short]['used'] = round(usg['used'], 4) 169 | disk_usage[dev_short]['capacity'] = self._changeUnit(value=usg['capacity'], force_unit='GB') 170 | total_capacity += disk_usage[dev_short]['capacity']['volume'] 171 | 172 | disk_usage[dev_short]['free'] = self._changeUnit(value=usg['free'], force_unit='GB') 173 | total_free += disk_usage[dev_short]['free']['volume'] 174 | 175 | if disk_io.has_key(dev_short): 176 | disk_usage[dev_short]['io_stat'] = disk_io[dev_short] 177 | 178 | disk_usage['total_available'] = total_available 179 | disk_usage['total_capacity'] = total_capacity 180 | disk_usage['total_free'] = total_free 181 | 182 | return disk_usage 183 | 184 | def test(self): 185 | disk_list = self._getDiskPartitions() 186 | return self._getDiskIO(disk_list) 187 | 188 | if __name__=='__main__': 189 | disk = DiskUsagePollster() 190 | util.print_list(disk.getSample()) 191 | --------------------------------------------------------------------------------