#!/usr/bin/python # # This program collects 'counters' from 'statistics' channel. # It accepts one command: 'Boss' group 'shutdown' import isc.cc import time import select import os bossgroup = 'Boss' myname = 'statsd' debug = 0 def total(s): def totalsub(d,s): for k in s.keys(): if (k == 'component' or k == 'version' or k == 'timestamp' or k == 'from'): continue if (k in d): if (isinstance(s[k], dict)): totalsub(d[k], s[k]) else: d[k] = s[k] + d[k] else: d[k] = s[k] if (len(s) == 0): return {} if (len(s) == 1): for k in s.keys(): out = s[k] out['components'] = 1 out['timestamp2'] = out['timestamp'] del out['from'] return out _time1 = 0 _time2 = 0 out = {} for i in s.values(): if (_time1 == 0 or _time1 < i['timestamp']): _time1 = i['timestamp'] if (_time2 == 0 or _time2 > i['timestamp']): _time2 = i['timestamp'] totalsub(out, i) out['components'] = len(s) out['timestamp'] = _time1; out['timestamp2'] = _time2; return out def dicttoxml(stats, level = 0): def dicttoxmlsub(s, level): output = '' spaces = ' ' * level for k in s.keys(): if (isinstance(s[k], dict)): output += spaces + ('<%s>\n' %k) \ + dicttoxmlsub(s[k], level+1) \ + spaces + '\n' %k else: output += spaces + '<%s>%s\n' % (k, s[k], k) return output for k in stats.keys(): space = ' ' * level output = space + '\n' % k s = stats[k] if ('component' in s or 'components' in s): output += dicttoxmlsub(s, level+1) else: for l in s.keys(): output += space + ' \n' % l \ + dicttoxmlsub(s[l], level+2) \ + space + ' \n' output += space + '\n' return output def dump_stats(statpath, statcount, stat, statraw): newfile = open(statpath + '.new', 'w') newfile.write('\n') newfile.write('\n') newfile.write('\n') newfile.write(' \n') newfile.write(' \n') newfile.write(dicttoxml(stat, 3)) newfile.write(' \n') newfile.write(' \n') newfile.write(dicttoxml(statraw, 3)) newfile.write(' \n') newfile.write(' \n') newfile.write('\n') newfile.close() loop = statcount while(loop > 0): old = statpath + '.%d' % loop loop -= 1 new = statpath + '.%d' % loop if (os.access(new, os.F_OK)): os.rename(new, old) if (os.access(statpath, os.F_OK)): os.rename(statpath, new) os.rename(statpath + '.new', statpath) def collector(statgroup,step,statpath,statcount): cc = isc.cc.Session() if debug: print ("cc.lname=",cc.lname) cc.group_subscribe(statgroup) cc.group_subscribe(bossgroup, myname) wrote_time = -1 last_wrote_time = -1 last_recvd_time = -1 stats = {} statstotal = {} while 1: wait = wrote_time + step - time.time() if wait <= 0 and last_recvd_time > wrote_time: if debug: print ("dump stats") dump_stats(statpath, statcount, statstotal, stats) last_wrote_time = wrote_time; wrote_time = time.time(); wait = last_wrote_time + step - time.time() if wait < 0: wait = step r,w,e = select.select([cc._socket],[],[], wait) for sock in r: if sock == cc._socket: data,envelope = cc.group_recvmsg(False) if (envelope['group'] == bossgroup): if ('shutdown' in data): exit() if (envelope['group'] == statgroup): # Check received data if (not('component' in data and 'version' in data and 'stats' in data)): continue component = data['component'] _from = envelope['from'] data['from'] = _from if debug: print ("received from ",_from) if (not (component in stats)): stats[component] = {} (stats[component])[_from] = data; statstotal[component] = total(stats[component]) last_recvd_time = time.time() if __name__ == '__main__': collector('statistics', 10, '/tmp/stats.xml', 100)