Can Python be made to generate tracing similar to bash's set -x?
Perhaps use sys.settrace:
Use traceit()
to turn on tracing, use traceit(False)
to turn off tracing.
import sysimport linecachedef _traceit(frame, event, arg): ''' http://www.dalkescientific.com/writings/diary/archive/2005/04/20/tracing_python_code.html ''' if event == "line": lineno = frame.f_lineno filename = frame.f_globals["__file__"] if (filename.endswith(".pyc") or filename.endswith(".pyo")): filename = filename[:-1] name = frame.f_globals["__name__"] line = linecache.getline(filename, lineno) print "%s # %s:%s" % (line.rstrip(), name, lineno,) return _traceitdef _passit(frame, event, arg): return _passitdef traceit(on=True): if on: sys.settrace(_traceit) else: sys.settrace(_passit)def mktemp(src): passdef my_mktemp(src): mktemp(src) p=srctraceit()for src in ('cpfs.c','log.c',): my_mktemp(src)traceit(False)
yields
mktemp(src) # __main__:33pass # __main__:30p=src # __main__:34mktemp(src) # __main__:33pass # __main__:30p=src # __main__:34if on: sys.settrace(_traceit) # __main__:26else: sys.settrace(_passit) # __main__:27
To trace specific calls, you can wrap each interesting function with your own logger. This does lead to arguments expanded to their values rather than just argument names in the output.
Functions have to be passed in as strings to prevent issues where modules redirect to other modules, like os.path / posixpath. I don't think you can extract the right module name to patch from just the function object.
Wrapping code:
import importlibdef wrapper(ffull, f): def logger(*args, **kwargs): print "TRACE: %s (%s, %s)" % (ffull, args, kwargs) return f(*args, **kwargs) return loggerdef log_execution(ffull): parts = ffull.split('.') mname = '.'.join(parts[:-1]) fname = parts[-1] m = importlib.import_module(mname) f = getattr(m, fname) setattr(m, fname, wrapper(ffull, f))
Usage:
for f in ['os.path.join', 'os.listdir', 'sys.exit']: log_execution(f)p = os.path.join('/usr', 'bin')os.listdir(p)sys.exit(0)....% ./a.py TRACE: os.path.join (('/usr', 'bin'), {})TRACE: os.listdir (('/usr/bin',), {})TRACE: sys.exit ((0,), {})