|  | #!/usr/bin/env python | 
|  |  | 
|  | ## | 
|  | ## chewie.py | 
|  | ## chews browser http log.  draws graph of connections | 
|  | ## Be sure there is only one pageload in the log. | 
|  | ## | 
|  | ## you'll want to | 
|  | ##   sudo apt-get install python-matplotlib | 
|  | ## before running this | 
|  | ## | 
|  |  | 
|  | import sys, pylab | 
|  |  | 
|  | # can't just use a dict, because there can be dups | 
|  | class Queue: | 
|  | def __init__(self): | 
|  | self.queue = [] | 
|  |  | 
|  | def add(self, url, time): | 
|  | self.queue.append([url, time]) | 
|  |  | 
|  | def get(self, url): | 
|  | for x in range(len(self.queue)): | 
|  | rec = self.queue[x] | 
|  | if rec[0] == url: | 
|  | del self.queue[x] | 
|  | return rec[1] | 
|  |  | 
|  | ## pull out request lag -- queue to start to done | 
|  | def lag(): | 
|  |  | 
|  | font = {'color': '#909090', 'fontsize': 6} | 
|  | extractMe = { | 
|  | 'RequestQueue.queueRequest': "Q", | 
|  | 'Connection.openHttpConnection()': "O", | 
|  | 'Request.sendRequest()': "S", | 
|  | 'Request.requestSent()': "T", | 
|  | 'processRequests()': 'R', | 
|  | 'Request.readResponse():': "D",         # done | 
|  | 'clearPipe()': 'U',	                    # unqueue | 
|  | 'Request.readResponse()': 'B',          # read data block | 
|  | 'Request.readResponseStatus():': 'HR',  # read http response line | 
|  | 'hdr': 'H',                             # http header | 
|  | } | 
|  | keys = extractMe.keys() | 
|  |  | 
|  | f = open(sys.argv[1], "r") | 
|  |  | 
|  | t0 = None | 
|  |  | 
|  | # thread, queued, opened, send, sent, reading, read, uri, server, y | 
|  | # 0       1       2       3     4     5        6     7    8       9 | 
|  | vals = [] | 
|  |  | 
|  | queued = Queue() | 
|  | opened = {"http0": None, | 
|  | "http1": None, | 
|  | "http2": None, | 
|  | "http3": None, | 
|  | "http4": None, | 
|  | "http5": None} | 
|  | active = {"http0": [], | 
|  | "http1": [], | 
|  | "http2": [], | 
|  | "http3": [], | 
|  | "http4": [], | 
|  | "http5": []} | 
|  | connectionCount = 0 | 
|  | byteCount = 0 | 
|  | killed = [[], []] | 
|  |  | 
|  | while (True): | 
|  | line = f.readline() | 
|  | if len(line) == 0: break | 
|  |  | 
|  | splitup = line.split() | 
|  |  | 
|  | # http only | 
|  | if splitup[0] != "V/http": continue | 
|  |  | 
|  | x = splitup[3:] | 
|  |  | 
|  | # filter to named lines | 
|  | if x[2] not in keys: continue | 
|  | x[2] = extractMe[x[2]] | 
|  |  | 
|  | # normalize time | 
|  | if t0 == None: t0 = int(x[0]) | 
|  | x[0] = int(x[0]) - t0 | 
|  |  | 
|  | thread, action = x[1], x[2] | 
|  | if action == "Q": | 
|  | time, url = x[0], x[3] | 
|  | queued.add(url, time) | 
|  | elif action == "O": | 
|  | # save opened time and server for this thread, so we can stuff it in l8r | 
|  | time, thread, host = x[0], x[1], x[4] | 
|  | opened[thread] = [time, host, connectionCount] | 
|  | connectionCount += 1 | 
|  | elif action == "S": | 
|  | time, thread, url = x[0], x[1], x[3] | 
|  | opentime, host, connection = opened[thread] | 
|  | qtime = queued.get(url) | 
|  | record = [thread, qtime, opentime, time, None, None, None, url, host, connection] | 
|  | active[thread].append(record) | 
|  | elif action == "T": | 
|  | time, thread = x[0], x[1] | 
|  | record = active[thread][-1] | 
|  | record[4] = time | 
|  | elif action == "R": | 
|  | print x | 
|  | if x[3] in ["sleep", "no", "wait"]: continue | 
|  | time, thread, = x[0], x[1] | 
|  | record = active[thread][0] | 
|  | record[5] = time | 
|  | elif action == 'U': | 
|  | thread = x[1] | 
|  | record = active[thread][0] | 
|  | killed[0].append(record[9]) | 
|  | killed[1].append(x[0]) | 
|  | queued.add(record[7], record[1]) | 
|  | del active[thread][0] | 
|  | elif action == "D": | 
|  | time, thread = x[0], x[1] | 
|  | record = active[thread][0] | 
|  | record[6] = time | 
|  | vals.append(record) | 
|  | del active[thread][0] | 
|  | print record | 
|  | # print record[3] / 1000, record[6] / 1000, record[7] | 
|  | elif action == "B": | 
|  | byteCount += int(x[3]) | 
|  | elif action == "HR": | 
|  | byteCount += int(x[2]) | 
|  |  | 
|  | f.close() | 
|  |  | 
|  | rng = range(connectionCount) | 
|  |  | 
|  | opened = [] | 
|  | drawn = [False for x in rng] | 
|  | for val in vals: | 
|  | y= val[9] | 
|  | if not drawn[y]: | 
|  | drawn[y] = True | 
|  | opened.append(val[2]) | 
|  | pylab.text(0, y - 0.25, "%s %s %s" % (val[9], val[0][4], val[8]), font) | 
|  |  | 
|  | # define limits | 
|  | # pylab.plot([vals[-1][6]], rng) | 
|  |  | 
|  | print opened, rng | 
|  | pylab.plot(opened, rng, 'ro') | 
|  | pylab.plot(killed[1], killed[0], 'rx') | 
|  |  | 
|  | for val in vals: | 
|  | thread, queued, opened, send, sent, reading, read, uri, server, y = val | 
|  | # send arrow | 
|  | arrow = pylab.Arrow(send, y, sent - send, 0) | 
|  | arrow.set_facecolor("g") | 
|  | ax = pylab.gca() | 
|  | ax.add_patch(arrow) | 
|  | # read arrow | 
|  | arrow = pylab.Arrow(reading, y, read - reading, 0) | 
|  | arrow.set_facecolor("r") | 
|  | ax = pylab.gca() | 
|  | ax.add_patch(arrow) | 
|  |  | 
|  | caption = \ | 
|  | "\nrequests: %s\n" % len(vals) + \ | 
|  | "byteCount: %s\n" % byteCount + \ | 
|  | "data rate: %s\n" % (1000 * byteCount / vals[-1][6])+ \ | 
|  | "connections: %s\n" % connectionCount | 
|  |  | 
|  | pylab.figtext(0.82, 0.30, caption, bbox=dict(facecolor='lightgrey', alpha=0.5)) | 
|  |  | 
|  | # print lines, [[x, x] for x in range(len(vals))] | 
|  | # pylab.plot(lines, [[x, x] for x in range(len(vals))], 'r-') | 
|  |  | 
|  | pylab.grid() | 
|  | pylab.show() | 
|  |  | 
|  | if __name__ == '__main__': lag() |