import cairo
FONT_NAME = "Bitstream Vera Sans"
-FONT_SIZE = 9
-PIXELS_PER_SECOND = 1000
-PIXELS_PER_LINE = 12
+FONT_SIZE = 8
+# how many pixels for a second on the timeline
+PIXELS_PER_SECOND = 300
+# how many pixels for one line of log
+PIXELS_PER_LINE = 10
PLOT_WIDTH = 1400
TIME_SCALE_WIDTH = 20
SYSCALL_MARKER_WIDTH = 20
BACKGROUND_COLOR = (0, 0, 0)
# assumes GST_DEBUG_LOG_COLOR=1
-mark_regex = re.compile (r'^(\d:\d\d:\d\d\.\d+) \d+ 0x[0-9a-f]+ [A-Z]+ +([a-zA-Z_]+ )(.*)')
+# timestamp pid thread level category,file,line,msg
+mark_regex = re.compile (r'^(\d+:\d+:\d+\.\d+) +\d+ +0?x?[0-9a-f]+ [A-Z]+ +([-a-zA-Z0-9_]+ )(.*)')
mark_timestamp_group = 1
mark_program_group = 2
mark_log_group = 3
success_result = "0"
+skip_lines = 0
+max_lines = 500
+filter_regex = re.compile ('')
+skip_regex = re.compile('')
+
class BaseMark:
colors = 0, 0, 0
def __init__(self, timestamp, log):
class SyscallParser:
def __init__ (self):
- self.pending_execs = []
self.syscalls = []
- def search_pending_execs (self, search_pid):
- n = len (self.pending_execs)
- for i in range (n):
- (pid, timestamp, command) = self.pending_execs[i]
- if pid == search_pid:
- return (i, timestamp, command)
-
- return (None, None, None)
-
def add_line (self, str):
m = mark_regex.search (str)
if m:
- timestr = m.group (mark_timestamp_group)
- timestamp = float (timestr[5:]) + (float (timestr[2:3]) * 60.0) + (float (timestr[0]) * 60.0*60.0)
+ timestr = m.group (mark_timestamp_group).split(':')
+ timestamp = float (timestr[2]) + (float (timestr[1]) * 60.0) + (float (timestr[0]) * 3600.0)
program = m.group (mark_program_group)
text = program + m.group (mark_log_group)
if text == 'last':
program_hash = program.__hash__ ()
s.colors = palette[program_hash % len (palette)]
self.syscalls.append (s)
-
+ else:
+ print 'No log in %s' % str
return
def parse_strace(filename):
parser = SyscallParser ()
+ global skip_lines
+ global max_lines
+ global skip_regex
+
+ skip_found = False
+
for line in file(filename, "r").readlines():
if line == "":
break
- parser.add_line (line)
+ if not skip_found:
+ if skip_regex.search(line):
+ skip_found = True
+ else:
+ continue
+
+ if skip_lines > 0:
+ skip_lines -= 1
+ continue
+
+ if len(parser.syscalls) >= max_lines:
+ break
+
+ if filter_regex.search(line):
+ parser.add_line (line)
return parser.syscalls
syscall.timestamp -= first_timestamp
def compute_syscall_metrics(syscalls):
+ global PIXELS_PER_SECOND
+ global PIXELS_PER_LINE
+
num_syscalls = len(syscalls)
metrics = Metrics()
metrics.width = PLOT_WIDTH
last_timestamp = syscalls[num_syscalls - 1].timestamp
- num_seconds = int(math.ceil(last_timestamp))
- metrics.height = max(num_seconds * PIXELS_PER_SECOND,
- num_syscalls * PIXELS_PER_LINE)
+
+ time_height = int(math.ceil(last_timestamp * PIXELS_PER_SECOND))
+ line_height = num_syscalls * PIXELS_PER_LINE
+
+ if time_height > line_height:
+ metrics.height = time_height
+ print "Adjusting PIXELS_PER_LINE = %d" % PIXELS_PER_LINE
+ PIXELS_PER_LINE = metrics.height / num_syscalls
+ print " PIXELS_PER_LINE = %d" % PIXELS_PER_LINE
+ else:
+ metrics.height = line_height
+ print "Adjusting PIXELS_PER_SECOND %d" % PIXELS_PER_SECOND
+ PIXELS_PER_SECOND = int(math.ceil(metrics.height / last_timestamp))
+ print " PIXELS_PER_SECOND %d" % PIXELS_PER_SECOND
text_ypos = 0
def plot_syscalls_to_surface(syscalls, metrics):
num_syscalls = len(syscalls)
+ print 'picture size: %d x %d' % (metrics.width, metrics.height);
+
surface = cairo.ImageSurface(cairo.FORMAT_RGB24,
metrics.width, metrics.height)
return surface
def main(args):
+
+ global skip_lines
+ global max_lines
+ global filter_regex
+ global skip_regex
+
option_parser = optparse.OptionParser(
usage="usage: %prog -o output.png <debug.log>")
option_parser.add_option("-o",
"--output", dest="output",
metavar="FILE",
help="Name of output file (output is a PNG file)")
+ option_parser.add_option("-s",
+ "--skip", dest="skip",
+ metavar="LINES",
+ help="Skip a number of loglines at the beginning of the file or wait till a regular expression happens")
+ option_parser.add_option("-m",
+ "--max-lines", dest="max",
+ help="max lines that need to be plotted")
+ option_parser.add_option("-f",
+ "--filter", dest="filter",
+ help="filter the log lines on a regular expression")
options, args = option_parser.parse_args()
in_filename = args[0]
out_filename = options.output
+ if options.skip:
+ try:
+ skip_lines = int(options.skip)
+ except:
+ skip_regex = re.compile(options.skip)
+ skip_lines = 0
+
+ if options.max:
+ max_lines = int(options.max)
+
+ if options.filter:
+ filter_regex = re.compile(options.filter)
+
syscalls = []
for syscall in parse_strace(in_filename):
syscalls.append(syscall)