tracehook does pretty-printed/ascii-art logging of Python function calls, args,
return-values and pre-return locals() snapshots in realtime. It is small,
non-intrusive, hyper-configurable, and has minimal dependencies. It has been
syntax-tested OK for python >= 2.6 and >= 3.1
The primary focus is on easy-on-the-eye (portable!) colourised output for quick visual in-terminal tracing of the lifecycle of data passing through the running program, in contrast to the verbose line-granularity source-debug output and heavy exported images which most other tracers are designed for.
It requires no auxiliary processes and only requires import tracehook and a
small decorator above each function you want traced. For maximum
implementation-portability it uses function-wrapping for all but one piece of
functionality (optionally dumping variable-snapshots from within the function
before return, for which it uses sys.settrace), so avoiding sys.settrace
entirely just requires that the decorators be of the form
@wrap(around=no_around), which means only the pre- and post- blocks will be
run.
Presently @wrap accepts the following arguments (unquoted - "compact" is
boolean and the others are function references):
pre = pre | no_pre around = around | no_around post = post | no_post compact = True | False
The {,no_}pre/around/post references are to ready-provided functions, but if
you want to experiment there is nothing stopping you creating your own custom
functions based on those and doing e.g. @wrap(pre=my_pre)
$ git clone https://github.com/rowanthorpe/tracehook.git $ git clone https://github.com/tartley/colorama.git
$ wget -O tracehook-0.3.3.tar.gz https://github.com/rowanthorpe/tracehook/tarball/v0.3.3 $ wget -O colorama-0.3.3.tar.gz https://github.com/tartley/colorama/tarball/v0.3.3
There are enough indicative uses in the test.py file that for now the easiest and quickest explanation is to just look in that file for inspiration.
- The standard approach is to install into a system directory and import from there:
import tracehook as th- To just import from a subdir "tracehook" within your project instead (which may sometimes be more appropriate for a small tracing hook like this), do the following:
if __package__:
from . import tracehook as th
else:
import os, sys, inspect
trc_exec = inspect.getfile(inspect.currentframe())
try:
trc_exec = os.readlink(trc_exec)
except OSError:
pass
trc_folder = os.path.realpath(os.path.join(os.path.dirname(os.path.realpath(trc_exec)), "tracehook"))
if trc_folder not in sys.path:
sys.path.insert(0, trc_folder)
del trc_exec, trc_folder
import tracehook as th- And if the importing subsystem is inexplicably broken for you, use an
inlining exec (and update global var assignments and callers to e.g.
pre()instead ofth.pre()) as shown below. Add dir to the system path as above, then replace the import line with:
with open(os.path.join(trc_folder, "__init__.py"), 'r') as fh:
exec(fh.read())
del fhRowan Thorpe <rowan@rowanthorpe.com>
tracehook uses the GPLv3 license, check COPYING file.
- Add case-handling for using sys.settrace (or equivalents) portably across different Python implementations (presently I've only tested it on cpython)
- (nitpick) Use something like argparse to colourise each commandline argv exactly, rather than the present heuristic way
