statsd.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. #!/usr/bin/python
  2. #
  3. # This program collects 'counters' from 'statistics' channel.
  4. # It accepts one command: 'Boss' group 'shutdown'
  5. import isc.cc
  6. import time
  7. import select
  8. import os
  9. bossgroup = 'Boss'
  10. myname = 'statsd'
  11. debug = 0
  12. def total(s):
  13. def totalsub(d,s):
  14. for k in s.keys():
  15. if (k == 'component' or k == 'version'
  16. or k == 'timestamp' or k == 'from'):
  17. continue
  18. if (k in d):
  19. if (isinstance(s[k], dict)):
  20. totalsub(d[k], s[k])
  21. else:
  22. d[k] = s[k] + d[k]
  23. else:
  24. d[k] = s[k]
  25. if (len(s) == 0):
  26. return {}
  27. if (len(s) == 1):
  28. for k in s.keys():
  29. out = s[k]
  30. out['components'] = 1
  31. out['timestamp2'] = out['timestamp']
  32. del out['from']
  33. return out
  34. _time1 = 0
  35. _time2 = 0
  36. out = {}
  37. for i in s.values():
  38. if (_time1 == 0 or _time1 < i['timestamp']):
  39. _time1 = i['timestamp']
  40. if (_time2 == 0 or _time2 > i['timestamp']):
  41. _time2 = i['timestamp']
  42. totalsub(out, i)
  43. out['components'] = len(s)
  44. out['timestamp'] = _time1;
  45. out['timestamp2'] = _time2;
  46. return out
  47. def dicttoxml(stats, level = 0):
  48. def dicttoxmlsub(s, level):
  49. output = ''
  50. spaces = ' ' * level
  51. for k in s.keys():
  52. if (isinstance(s[k], dict)):
  53. output += spaces + ('<%s>\n' %k) \
  54. + dicttoxmlsub(s[k], level+1) \
  55. + spaces + '</%s>\n' %k
  56. else:
  57. output += spaces + '<%s>%s</%s>\n' % (k, s[k], k)
  58. return output
  59. for k in stats.keys():
  60. space = ' ' * level
  61. output = space + '<component component="%s">\n' % k
  62. s = stats[k]
  63. if ('component' in s or 'components' in s):
  64. output += dicttoxmlsub(s, level+1)
  65. else:
  66. for l in s.keys():
  67. output += space + ' <from from="%s">\n' % l \
  68. + dicttoxmlsub(s[l], level+2) \
  69. + space + ' </from>\n'
  70. output += space + '</component>\n'
  71. return output
  72. def dump_stats(statpath, statcount, stat, statraw):
  73. newfile = open(statpath + '.new', 'w')
  74. newfile.write('<?xml version="1.0" encoding="UTF-8"?>\n')
  75. newfile.write('<!-- created at '+time.strftime('%Y%m%d %H%M%S')+' -->\n')
  76. newfile.write('<isc version="0.0">\n')
  77. newfile.write(' <bind10>\n')
  78. newfile.write(' <total>\n')
  79. newfile.write(dicttoxml(stat, 3))
  80. newfile.write(' </total>\n')
  81. newfile.write(' <each>\n')
  82. newfile.write(dicttoxml(statraw, 3))
  83. newfile.write(' </each>\n')
  84. newfile.write(' </bind10>\n')
  85. newfile.write('</isc>\n')
  86. newfile.close()
  87. loop = statcount
  88. while(loop > 0):
  89. old = statpath + '.%d' % loop
  90. loop -= 1
  91. new = statpath + '.%d' % loop
  92. if (os.access(new, os.F_OK)):
  93. os.rename(new, old)
  94. if (os.access(statpath, os.F_OK)):
  95. os.rename(statpath, new)
  96. os.rename(statpath + '.new', statpath)
  97. def collector(statgroup,step,statpath,statcount):
  98. cc = isc.cc.Session()
  99. if debug:
  100. print ("cc.lname=",cc.lname)
  101. cc.group_subscribe(statgroup)
  102. cc.group_subscribe(bossgroup, myname)
  103. wrote_time = -1
  104. last_wrote_time = -1
  105. last_recvd_time = -1
  106. stats = {}
  107. statstotal = {}
  108. while 1:
  109. wait = wrote_time + step - time.time()
  110. if wait <= 0 and last_recvd_time > wrote_time:
  111. if debug:
  112. print ("dump stats")
  113. dump_stats(statpath, statcount, statstotal, stats)
  114. last_wrote_time = wrote_time;
  115. wrote_time = time.time();
  116. wait = last_wrote_time + step - time.time()
  117. if wait < 0:
  118. wait = step
  119. r,w,e = select.select([cc._socket],[],[], wait)
  120. for sock in r:
  121. if sock == cc._socket:
  122. data,envelope = cc.group_recvmsg(False)
  123. if (envelope['group'] == bossgroup):
  124. if ('shutdown' in data):
  125. exit()
  126. if (envelope['group'] == statgroup):
  127. # Check received data
  128. if (not('component' in data and 'version' in data
  129. and 'stats' in data)):
  130. continue
  131. component = data['component']
  132. _from = envelope['from']
  133. data['from'] = _from
  134. if debug:
  135. print ("received from ",_from)
  136. if (not (component in stats)):
  137. stats[component] = {}
  138. (stats[component])[_from] = data;
  139. statstotal[component] = total(stats[component])
  140. last_recvd_time = time.time()
  141. if __name__ == '__main__':
  142. collector('statistics', 10, '/tmp/stats.xml', 100)