python - Decorator to log function execution line by line -
i'm working on script takes few minutes run, , provide output user progress. unfortunately i'm exceedingly lazy. i'd write function without logging, , apply decorator steps through function , prints each line before executing line. i'm looking loggingdecorator
such that:
>>> @loggingdecorator ... def myfunction(): ... foo() ... bar() ... baz() >>> myfunction() starting myfunction foo() ... [ok] bar() ... [ok] baz() ... [ok] myfunction done!
here's i've tried far:
import sys def logging_tracer(frame, event, arg): def local_tracer(local_frame, event, arg): if frame local_frame: print frame.f_code.co_name, event, arg print frame.f_code.co_name, event, arg return local_tracer def loggingdecorator(func): def _wrapper(): old_trace_function = sys.gettrace() sys.settrace(logging_tracer) try: result = func() except: raise else: return result finally: sys.settrace(old_trace_function) return _wrapper
unfortunately, prints bit much; follows function calls , prints them out, line line (well, doesn't print source line, existing answers using inspect, combined stuff on frame object in trace function it), i'm bit stumped how logging_tracer
unless function in question decorated.
so here's came with. @corley brigman's comment got me started in right direction. bit hackey, sys.gettrace/settrace
rather promenently documented "cpython implementation details", , solution should not expected work in other implementations. said, seems work out pretty well. tracing functionality in cpython not provide notification of "line finished executing", [ok]
question doesn't make sense.
fixing recursive tracing issue simple matter of keeping cache of functions decorated, , produce output if frame being traced function decorated.
import inspect import sys def logging_tracer(frame, event, arg): lines, firstline = inspect.getsourcelines(frame) def local_tracer(local_frame, event, arg): if event == 'line' , frame local_frame: print event, frame.f_lineno,'\t', lines[frame.f_lineno - firstline] #print event, lines[frame.f_lineno - firstline] #print frame.f_code.co_name, frame.f_lineno, event, arg if frame.f_code in log_these_functions: print event, frame.f_lineno,'\t', lines[frame.f_lineno - firstline + (event == 'call')] #print frame.f_code.co_name, event, arg return local_tracer else: return none log_these_functions = set() def loggingdecorator(func): log_these_functions.add(func.func_code) def _wrapper(): old_trace_function = sys.gettrace() sys.settrace(logging_tracer) try: result = func() except: raise else: return result finally: sys.settrace(old_trace_function) return _wrapper
Comments
Post a Comment