#!/usr/bin/python import re import sys def ParseLine(line): m = re.search(r'^\[(\d*):(\d*):(\d*).*\] XXX (.*)$', line) if not m: return None parsed = {} parsed['t'] = int(m.group(3)) msg = m.group(4) m = re.search(r'^Received request \[(.*)\] (.*)\s*$', msg) if m: parsed['type'] = 'request' parsed['phase'] = 'start' parsed['id'] = m.group(1) parsed['hostname'] = m.group(2) return parsed m = re.search(r'^Finished request \[(.*)\] (.*)\s*$', msg) if m: parsed['type'] = 'request' parsed['phase'] = 'end' parsed['id'] = m.group(1) parsed['hostname'] = m.group(2) return parsed m = re.search(r'^Canceled request \[(.*)\] (.*)\s*$', msg) if m: parsed['type'] = 'request' parsed['phase'] = 'end' parsed['cancelled'] = True parsed['id'] = m.group(1) parsed['hostname'] = m.group(2) return parsed m = re.search(r'^Running resolve for (.*) \[@(.*)\]\s*$', msg) if m: parsed['type'] = 'thread' parsed['phase'] = 'start' parsed['hostname'] = m.group(1) parsed['id'] = m.group(2) return parsed m = re.search(r'^Completed resolve for (.*) \[@(.*)\]\s*$', msg) if m: parsed['type'] = 'thread' parsed['phase'] = 'end' parsed['hostname'] = m.group(1) parsed['id'] = m.group(2) return parsed return None def ParseFile(path): f = open(path, 'r') entries = [] for line in f: parsed = ParseLine(line) if parsed: entries.append(parsed) f.close() return entries def FindEndEntry(entries, start_index): start_entry = entries[start_index] for i in range(start_index + 1, len(entries)): e = entries[i] if (e['phase'] == 'end' and e['type'] == start_entry['type'] and e['id'] == start_entry['id'] and e['hostname'] == start_entry['hostname']): return e return None def GetGroupEntries(entries): grouped = [] for i in range(len(entries)): e1 = entries[i] if e1['phase'] == 'start': # Clone e1 (mostly). e = {} for prop in ['id', 'type', 'hostname', 't']: e[prop] = e1[prop] # Find the end entry, and update end information. e2 = FindEndEntry(entries, i) if e2: e['dt'] = e2['t'] - e1['t'] e['cancelled'] = e2.get('cancelled', False) e2['phase'] = '' # Make sure it isn't re-used later. grouped.append(e) return grouped def FindMaxTime(entries): t_max = 0 for e in entries: t_max = max(t_max, e['t'] + e.get('dt', 0)) return t_max row_height = 40 max_width = 800 def PrintEntryRow(entries, i, max_t): entry = entries[i] min_width = 2 top_px = i * row_height left_px = int(entry['t'] * max_width / max_t) dt = entry.get('dt', max_t - entry['t']) width_px = max(min_width, int(dt * max_width / max_t)) caption_offset_x = width_px + 15 caption_offset_y = 4 # Print a box on the timeline. bg = '' if entry['type'] == 'request': bg = 'blue' if entry['type'] == 'thread': bg = 'purple' if entry.get('cancelled', False): bg = 'red' print ('
 
') % (top_px, left_px, width_px, row_height, bg) # Print a caption besides it. msg = '' if entry['type'] == 'thread': msg = "Started thread for \"%s\" at t=%d (%d in progress), took %s ms" % (entry['hostname'], entry['t'], GetNumLiveThreads(entries, entry['t']), str(entry.get('dt', '???'))) else: msg = "Issued request for \"%s\" at t=%d, took %s ms" % (entry['hostname'], entry['t'], str(entry.get('dt', '???'))) if entry.get('cancelled', False): msg += " (was cancelled)" print ('%s') % (top_px + caption_offset_y, left_px + caption_offset_x, msg) def GetNumLiveThreads(entries, t): total = 0 for e in entries: if e['type'] == 'thread' and t >= e['t'] and (t <= (e['t'] + e.get('dt', t))): total += 1 return total def PrintEntries(entries): max_t = FindMaxTime(entries) print ('') print ('
' % (max_width, row_height * len(entries))) for i in range(len(entries)): PrintEntryRow(entries, i, max_t) print ('
') print ('") sys.exit(1) raw_entries = ParseFile(sys.argv[1]) entries = GetGroupEntries(raw_entries) # Normalize the timestamps so first entry starts at t=0. start_t = entries[0]['t'] for e in entries: e['t'] -= start_t PrintEntries(entries) def RunTests(): print ParseLine('[4756:3868:687396750:INFO:host_resolver_impl.cc(513)] XXX Received request [c] top3.mail.ru') print ParseLine('[4756:2752:687396890:INFO:host_resolver_impl.cc(60)] XXX Completed resolve for counter.rambler.ru [@25498708]') print ParseLine('[4756:5996:687396875:INFO:host_resolver_impl.cc(50)] XXX Running resolve for images.rambler.ru [@11157428]') print ParseLine('[4756:3868:687396968:INFO:host_resolver_impl.cc(536)] XXX Finished request [c] top3.mail.ru') print ParseLine('[4756:3868:687399171:INFO:host_resolver_impl.cc(560)] XXX Canceled request [2c] clients1.google.lv') if __name__ == "__main__": main()