#!/opt/rocks/bin/python # Ganglia plugin to monitor disk statistics from iostat # want to get extended output as in iostat command: # iostat -k -x 1 2 # potential problem is that the above takes 1s to run # reference: http://sourceforge.net/apps/trac/ganglia/browser/trunk/monitor-core/gmond/python_modules/network/tcpconn.py import os import re import subprocess import sys import time # globals to hold iostat output (should be in a class, probably) _iostat_data = {} _iostat_time = 0.0 _iostat_interval = 2.0 _iostat_lifetime = 30.0 def fill_iostat(): # Actually call the iostat command and save output global _iostat_data global _iostat_time global _iostat_interval global _iostat_lifetime interval = str(int(_iostat_interval)) iostat_cmd = [ '/usr/bin/iostat', '-k', '-t', '-x', interval, '2' ] iostat_output = subprocess.Popen(iostat_cmd, stdout=subprocess.PIPE) # skip the first batch of output flag = 'Time:' saw_flag = False for aline in iostat_output.stdout: aline = aline.rstrip('\r\n') words = aline.split() if words == []: continue if words[0] == flag: if saw_flag: break else: saw_flag = True # now read second batch of data, storing output # assumming data lines start with "sd" _iostat_data = {} for aline in iostat_output.stdout: aline = aline.rstrip('\r\n') words = aline.split() if words == []: continue if re.search('^sd', words[0]): mydev = words[0] mydata = { 'rrqmhz' : words[1], 'wrqmhz' : words[2], 'rhz' : words[3], 'whz' : words[4], 'rkbhz' : words[5], 'wkbhz' : words[6], 'avgrq-sz' : words[7], 'avgqu-sz' : words[8], 'await' : words[9], 'svctm' : words[10], 'util' : words[11] } _iostat_data[mydev] = mydata _iostat_time = time.time() #print _iostat_data #print 'sda is', _iostat_data['sda'] return def get_iostat(device, stat): # return data item from _iostat_data structure # update _iostat_data if outdated global _iostat_data global _iostat_time global _iostat_interval global _iostat_lifetime now = time.time() #print "delta time", now - _iostat_time, "lifetime is", _iostat_lifetime if (now - _iostat_time) > _iostat_lifetime: fill_iostat() result = _iostat_data[device][stat] return result def iostat_handler(name): adev, astat = name.split('_') result = 0.0 result = float(get_iostat(adev, astat)) print "for device", adev, "stat", astat, "have", result return result # global list that defines generalities of metrics. # these get modfied with specific mount or device names # before being returned to gmond during initialization. _generic_desc = [ {'name' : 'rrqmhz', 'call_back': iostat_handler, 'time_max': 90, 'value_type': 'float', 'units': 'Hz', 'slope': 'both', 'format': '%f', 'description': 'Disk read requests merged queued per second', 'groups': 'iostat' }, {'name' : 'wrqmhz', 'call_back': iostat_handler, 'time_max': 90, 'value_type': 'float', 'units': 'Hz', 'slope': 'both', 'format': '%f', 'description': 'Disk write requests merged queued per second', 'groups': 'iostat' }, {'name' : 'rhz', 'call_back': iostat_handler, 'time_max': 90, 'value_type': 'float', 'units': 'Hz', 'slope': 'both', 'format': '%f', 'description': 'Disk read requests to device per second', 'groups': 'iostat' }, {'name' : 'whz', 'call_back': iostat_handler, 'time_max': 90, 'value_type': 'float', 'units': 'Hz', 'slope': 'both', 'format': '%f', 'description': 'Disk write requests to device per second', 'groups': 'iostat' }, {'name' : 'rkbhz', 'call_back': iostat_handler, 'time_max': 90, 'value_type': 'float', 'units': 'kB Hz', 'slope': 'both', 'format': '%f', 'description': 'Disk read kiloBytes per second', 'groups': 'iostat' }, {'name' : 'wkbhz', 'call_back': iostat_handler, 'time_max': 90, 'value_type': 'float', 'units': 'kB Hz', 'slope': 'both', 'format': '%f', 'description': 'Disk write kiloBytes per second', 'groups': 'iostat' }, {'name' : 'avgrq-sz', 'call_back': iostat_handler, 'time_max': 90, 'value_type': 'float', 'units': '512 byte sectors', 'slope': 'both', 'format': '%f', 'description': 'Disk average device request size in sectors', 'groups': 'iostat' }, {'name' : 'avgqu-sz', 'call_back': iostat_handler, 'time_max': 90, 'value_type': 'float', 'units': 'N Queued', 'slope': 'both', 'format': '%f', 'description': 'Disk average queue length of requests issued to device', 'groups': 'iostat' }, {'name' : 'await', 'call_back': iostat_handler, 'time_max': 90, 'value_type': 'float', 'units': 'ms', 'slope': 'both', 'format': '%f', 'description': 'Disk average total request service time', 'groups': 'iostat' }, {'name' : 'svctm', 'call_back': iostat_handler, 'time_max': 90, 'value_type': 'float', 'units': 'ms', 'slope': 'both', 'format': '%f', 'description': 'Disk average device request service time', 'groups': 'iostat' }, {'name' : 'util', 'call_back': iostat_handler, 'time_max': 90, 'value_type': 'float', 'units': 'Percent', 'slope': 'both', 'format': '%f', 'description': 'Disk percent utilization', 'groups': 'iostat' } ] def metric_init(params): global descriptors descriptors = [] global _iostat_interval global _iostat_lifetime #print params # if these params defined in config, use them if params.has_key('iostatinterval'): _iostat_interval = float(params['iostatinterval']) if params.has_key('iostatlifetime'): _iostat_lifetime = float(params['iostatlifetime']) #print "lifetime is", _iostat_lifetime #print "interval is ", _iostat_interval for aparam, avalue in params.iteritems(): #print avalue if avalue == 'disk': adev, astat = aparam.split('_') #print "device is", adev, "stat is", astat adict = {} for adict in _generic_desc: if adict['name'] == astat: adesc = adict adesc['name'] = aparam descriptors.append(adesc) return descriptors def metric_cleanup(): '''Clean up the metric module.''' pass #This code is for debugging and unit testing if __name__ == '__main__': metric_init(None) for d in descriptors: v = d['call_back'](d['name']) print 'value for %s is %s' % (d['name'], v)