blob: e18d02cf734e730107f226ccac8753a8d2f14060 [file] [log] [blame]
# Copyright 1999-2009 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
import os, sys, threading
import portage.const
from portage.util import writemsg
def set_trace(on=True):
if on:
t = trace_handler()
threading.settrace(t.event_handler)
sys.settrace(t.event_handler)
else:
sys.settrace(None)
threading.settrace(None)
class trace_handler(object):
def __init__(self):
python_system_paths = []
for x in sys.path:
if os.path.basename(x).startswith("python2."):
python_system_paths.append(x)
self.ignore_prefixes = []
for x in python_system_paths:
self.ignore_prefixes.append(x + os.sep)
self.trim_filename = prefix_trimmer(os.path.join(portage.const.PORTAGE_BASE_PATH, "pym") + os.sep).trim
self.show_local_lines = False
self.max_repr_length = 200
def event_handler(self, *args):
frame, event, arg = args
if "line" == event:
if self.show_local_lines:
self.trace_line(*args)
else:
if not self.ignore_filename(frame.f_code.co_filename):
self.trace_event(*args)
return self.event_handler
def trace_event(self, frame, event, arg):
writemsg("%s line=%d name=%s event=%s %slocals=%s\n" % \
(self.trim_filename(frame.f_code.co_filename),
frame.f_lineno,
frame.f_code.co_name,
event,
self.arg_repr(frame, event, arg),
self.locals_repr(frame, event, arg)))
def arg_repr(self, frame, event, arg):
my_repr = None
if "return" == event:
my_repr = repr(arg)
if len(my_repr) > self.max_repr_length:
my_repr = "'omitted'"
return "value=%s " % my_repr
elif "exception" == event:
my_repr = repr(arg[1])
if len(my_repr) > self.max_repr_length:
my_repr = "'omitted'"
return "type=%s value=%s " % (arg[0], my_repr)
return ""
def trace_line(self, frame, event, arg):
writemsg("%s line=%d\n" % (self.trim_filename(frame.f_code.co_filename), frame.f_lineno))
def ignore_filename(self, filename):
if filename:
for x in self.ignore_prefixes:
if filename.startswith(x):
return True
return False
def locals_repr(self, frame, event, arg):
"""Create a representation of the locals dict that is suitable for
tracing output."""
my_locals = frame.f_locals.copy()
# prevent unsafe __repr__ call on self when __init__ is called
# (method calls aren't safe until after __init__ has completed).
if frame.f_code.co_name == "__init__" and "self" in my_locals:
my_locals["self"] = "omitted"
# We omit items that will lead to unreasonable bloat of the trace
# output (and resulting log file).
for k, v in my_locals.items():
my_repr = repr(v)
if len(my_repr) > self.max_repr_length:
my_locals[k] = "omitted"
return my_locals
class prefix_trimmer(object):
def __init__(self, prefix):
self.prefix = prefix
self.cut_index = len(prefix)
self.previous = None
self.previous_trimmed = None
def trim(self, s):
"""Remove a prefix from the string and return the result.
The previous result is automatically cached."""
if s == self.previous:
return self.previous_trimmed
else:
if s.startswith(self.prefix):
self.previous_trimmed = s[self.cut_index:]
else:
self.previous_trimmed = s
return self.previous_trimmed