1import sys 2import inspect 3from collections import OrderedDict 4 5class TracebackFancy: 6 def __init__(self,traceback): 7 self.t = traceback 8 9 def getFrame(self): 10 return FrameFancy(self.t.tb_frame) 11 12 def getLineNumber(self): 13 return self.t.tb_lineno 14 15 def getNext(self): 16 return TracebackFancy(self.t.tb_next) 17 18 def __str__(self): 19 if self.t == None: 20 return "" 21 str_self = "%s @ %s" % (self.getFrame().getName(), self.getLineNumber()) 22 return str_self + "\n" + self.getNext().__str__() 23 24class ExceptionFancy: 25 def __init__(self,frame): 26 self.etraceback = frame.f_exc_traceback 27 self.etype = frame.exc_type 28 self.evalue = frame.f_exc_value 29 30 def __init__(self,tb,ty,va): 31 self.etraceback = tb 32 self.etype = ty 33 self.evalue = va 34 35 def getTraceback(self): 36 return TracebackFancy(self.etraceback) 37 38 def __nonzero__(self): 39 return self.etraceback != None or self.etype != None or self.evalue != None 40 41 def getType(self): 42 return str(self.etype) 43 44 def getValue(self): 45 return self.evalue 46 47class CodeFancy: 48 def __init__(self,code): 49 self.c = code 50 51 def getArgCount(self): 52 return self.c.co_argcount 53 54 def getFilename(self): 55 return self.c.co_filename 56 57 def getVariables(self): 58 return self.c.co_varnames 59 60 def getName(self): 61 return self.c.co_name 62 63class ArgsFancy: 64 def __init__(self,frame,arginfo): 65 self.f = frame 66 self.a = arginfo 67 68 def __str__(self): 69 args, varargs, kwargs = self.getArgs(), self.getVarArgs(), self.getKWArgs() 70 ret = "" 71 count = 0 72 size = len(args) 73 for arg in args: 74 ret = ret + ("%s = %s" % (arg, args[arg])) 75 count = count + 1 76 if count < size: 77 ret = ret + ", " 78 if varargs: 79 if size > 0: 80 ret = ret + " " 81 ret = ret + "varargs are " + str(varargs) 82 if kwargs: 83 if size > 0: 84 ret = ret + " " 85 ret = ret + "kwargs are " + str(kwargs) 86 return ret 87 88 def getNumArgs(wantVarargs = False, wantKWArgs=False): 89 args, varargs, keywords, values = self.a 90 size = len(args) 91 if varargs and wantVarargs: 92 size = size+len(self.getVarArgs()) 93 if keywords and wantKWArgs: 94 size = size+len(self.getKWArgs()) 95 return size 96 97 def getArgs(self): 98 args, _, _, values = self.a 99 argWValues = OrderedDict() 100 for arg in args: 101 argWValues[arg] = values[arg] 102 return argWValues 103 104 def getVarArgs(self): 105 _, vargs, _, _ = self.a 106 if vargs: 107 return self.f.f_locals[vargs] 108 return () 109 110 def getKWArgs(self): 111 _, _, kwargs, _ = self.a 112 if kwargs: 113 return self.f.f_locals[kwargs] 114 return {} 115 116class FrameFancy: 117 def __init__(self,frame): 118 self.f = frame 119 120 def getCaller(self): 121 return FrameFancy(self.f.f_back) 122 123 def getLineNumber(self): 124 return self.f.f_lineno 125 126 def getCodeInformation(self): 127 return CodeFancy(self.f.f_code) 128 129 def getExceptionInfo(self): 130 return ExceptionFancy(self.f) 131 132 def getName(self): 133 return self.f.f_code.co_name 134 135 def getLocals(self): 136 return self.f.f_locals 137 138 def getArgumentInfo(self): 139 return ArgsFancy(self.f,inspect.getargvalues(self.f)) 140 141class TracerClass: 142 def callEvent(self,frame): 143 pass 144 145 def lineEvent(self,frame): 146 pass 147 148 def returnEvent(self,frame,retval): 149 pass 150 151 def exceptionEvent(self,frame,exception,value,traceback): 152 pass 153 154 def cCallEvent(self,frame,cfunct): 155 pass 156 157 def cReturnEvent(self,frame,cfunct): 158 pass 159 160 def cExceptionEvent(self,frame,cfunct): 161 pass 162 163tracer_impl = TracerClass() 164 165 166def the_tracer_entrypoint(frame,event,args): 167 if tracer_impl == None: 168 return None 169 if event == "call": 170 call_retval = tracer_impl.callEvent(FrameFancy(frame)) 171 if call_retval == False: 172 return None 173 return the_tracer_entrypoint 174 elif event == "line": 175 line_retval = tracer_impl.lineEvent(FrameFancy(frame)) 176 if line_retval == False: 177 return None 178 return the_tracer_entrypoint 179 elif event == "return": 180 tracer_impl.returnEvent(FrameFancy(frame),args) 181 elif event == "exception": 182 exty,exva,extb = args 183 exception_retval = tracer_impl.exceptionEvent(FrameFancy(frame),ExceptionFancy(extb,exty,exva)) 184 if exception_retval == False: 185 return None 186 return the_tracer_entrypoint 187 elif event == "c_call": 188 tracer_impl.cCallEvent(FrameFancy(frame),args) 189 elif event == "c_return": 190 tracer_impl.cReturnEvent(FrameFancy(frame),args) 191 elif event == "c_exception": 192 tracer_impl.cExceptionEvent(FrameFancy(frame),args) 193 return None 194 195def enable(t=None): 196 global tracer_impl 197 if t: 198 tracer_impl = t 199 sys.settrace(the_tracer_entrypoint) 200 201def disable(): 202 sys.settrace(None) 203 204class LoggingTracer: 205 def callEvent(self,frame): 206 print "call " + frame.getName() + " from " + frame.getCaller().getName() + " @ " + str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo()) 207 208 def lineEvent(self,frame): 209 print "running " + frame.getName() + " @ " + str(frame.getLineNumber()) + " locals are " + str(frame.getLocals()) 210 211 def returnEvent(self,frame,retval): 212 print "return from " + frame.getName() + " value is " + str(retval) + " locals are " + str(frame.getLocals()) 213 214 def exceptionEvent(self,frame,exception): 215 print "exception %s %s raised from %s @ %s" % (exception.getType(), str(exception.getValue()), frame.getName(), frame.getLineNumber()) 216 print "tb: " + str(exception.getTraceback()) 217 218def f(x,y=None): 219 if x > 0: 220 return 2 + f(x-2) 221 return 35 222 223def g(x): 224 return 1.134 / x 225 226def print_keyword_args(**kwargs): 227 # kwargs is a dict of the keyword args passed to the function 228 for key, value in kwargs.iteritems(): 229 print "%s = %s" % (key, value) 230 231def total(initial=5, *numbers, **keywords): 232 count = initial 233 for number in numbers: 234 count += number 235 for key in keywords: 236 count += keywords[key] 237 return count 238 239if __name__ == "__main__": 240 enable(LoggingTracer()) 241 f(5) 242 f(5,1) 243 print_keyword_args(first_name="John", last_name="Doe") 244 total(10, 1, 2, 3, vegetables=50, fruits=100) 245 try: 246 g(0) 247 except: 248 pass 249 disable() 250