#!/usr/bin/env python """ Extract iperf data from json blob and format for gnuplot. """ import json import os import sys from optparse import OptionParser import pprint # for debugging, so output to stderr to keep verbose # output out of any redirected stdout. pp = pprint.PrettyPrinter(indent=4, stream=sys.stderr) def generate_output(iperf, options): """Do the actual formatting.""" for i in iperf.get('intervals'): for ii in i.get('streams'): if options.verbose: pp.pprint(ii) row = '{0} {1} {2} {3} {4}\n'.format( round(float(ii.get('start')), 4), ii.get('bytes'), # to Gbits/sec round(float(ii.get('bits_per_second')) / (1000*1000*1000), 3), ii.get('retransmits'), round(float(ii.get('snd_cwnd')) / (1000*1000), 2) ) yield row def summed_output(iperf, options): """Format summed output.""" row_header = '???' # XXX get this value byte = list() bits_per_second = list() retransmits = list() snd_cwnd = list() for i in iperf.get('intervals'): for ii in i.get('streams'): if options.verbose: pp.pprint(i) byte.append(ii.get('bytes')) bits_per_second.append(float(ii.get('bits_per_second')) / (1000*1000*1000)) retransmits.append(ii.get('retransmits')) snd_cwnd.append(float(ii.get('snd_cwnd')) / (1000*1000)) row = '{h} {b} {bps} {r} {s}\n'.format( h=row_header, b=sum(byte), bps=round(sum(bits_per_second), 3), r=sum(retransmits), s=round(sum(snd_cwnd) / len(snd_cwnd), 2) ) return row def main(): """Execute the read and formatting.""" usage = '%prog [ -f FILE | -o OUT | -v ]' parser = OptionParser(usage=usage) parser.add_option('-f', '--file', metavar='FILE', type='string', dest='filename', help='Input filename.') parser.add_option('-o', '--output', metavar='OUT', type='string', dest='output', help='Optional file to append output to.') parser.add_option('-s', '--sum', dest='summed', action='store_true', default=False, help='Summed version of the output.') parser.add_option('-v', '--verbose', dest='verbose', action='store_true', default=False, help='Verbose debug output to stderr.') options, _ = parser.parse_args() if not options.filename: parser.error('Filename is required.') file_path = os.path.normpath(options.filename) if not os.path.exists(file_path): parser.error('{f} does not exist'.format(f=file_path)) with open(file_path, 'r') as fh: data = fh.read() try: iperf = json.loads(data) except Exception as ex: # pylint: disable=broad-except parser.error('Could not parse JSON from file (ex): {0}'.format(str(ex))) if options.output: absp = os.path.abspath(options.output) output_dir, _ = os.path.split(absp) if not os.path.exists(output_dir): parser.error('Output file directory path {0} does not exist'.format(output_dir)) fh = open(absp, 'a') else: fh = sys.stdout if options.summed: fmt = summed_output else: fmt = generate_output for i in fmt(iperf, options): fh.write(i) if __name__ == '__main__': main()