import sys import signal from twisted.application import service from twisted.python import reflect, log class CannotFindFunction(ValueError): pass class Tracer(object): skip = object() installed = False def install(self): self.installed = True sys.settrace(self.trace) def uninstall(self): self.installed = False sys.settrace(None) def toggle(self): if self.installed: self.uninstall() else: self.install() def trace(self, frame, event, arg): r = getattr(self, 'trace_' + event.upper())(frame, arg) if r is self.skip: return None elif r is None: return self.trace else: return r def trace_CALL(self, frame, arg): pass def trace_LINE(self, frame, arg): pass def trace_RETURN(self, frame, arg): pass def trace_EXCEPTION(self, frame, arg): pass def extractArgs(frame): co = frame.f_code dict = frame.f_locals n = co.co_argcount if co.co_flags & 4: n = n+1 if co.co_flags & 8: n = n+1 result = {} for i in range(n): name = co.co_varnames[i] result[name] = dict.get(name, "*** undefined ***") return result def formatArgs(args): return ', '.join(['='.join((k, reflect.safe_repr(v))) for (k, v) in args.iteritems()]) class Spewer(Tracer): callDepth = 0 def trace_CALL(self, frame, arg): self.callDepth += 1 frameSelf = frame.f_locals.get('self') if frameSelf is not None: if hasattr(frameSelf, '__class__'): k = reflect.qual(frameSelf.__class__) else: k = reflect.qual(type(frameSelf)) k = k + '.' else: k = '' log.msg("%s%s%s(%s)" % ( self.callDepth * ' ', k, frame.f_code.co_name, formatArgs(extractArgs(frame)))) def trace_RETURN(self, frame, arg): if arg is not None: log.msg("%s<= %s" % ( self.callDepth * ' ', reflect.safe_repr(arg),)) self.callDepth = max(0, self.callDepth - 1) def trace_EXCEPTION(self, frame, arg): log.msg("%s^- %s" % ( self.callDepth * ' ', reflect.safe_repr(arg),)) self.callDepth = max(0, self.callDepth - 1) class SignalService(service.Service): def __init__(self, sigmap): self.sigmap = sigmap def startService(self): service.Service.startService(self) self.oldsigmap = {} for sig, handler in self.sigmap.items(): self.oldsigmap[sig] = signal.signal(sig, handler) def stopService(self): for sig, handler in self.oldsigmap.items(): signal.signal(sig, handler) del self.oldsigmap service.Service.stopService(self)