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 fh
Rowan Thorpe <[email protected]>
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