Skip to content

Instantly share code, notes, and snippets.

@techtonik
Created October 19, 2011 20:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save techtonik/1299647 to your computer and use it in GitHub Desktop.
Save techtonik/1299647 to your computer and use it in GitHub Desktop.
Python - Get function trace in Xdebug format - https://bitbucket.org/techtonik/xtrace
import datetime
import inspect
import os
import sys
oldfunc = None #: save old trace function if any
def start():
global oldfunc
oldfunc = sys.gettrace()
print datetime.datetime.now().strftime('TRACE START [%Y-%m-%d %H:%M:%S]')
sys.settrace(function_trace_xdebug)
def stop():
global oldfunc
print datetime.datetime.now().strftime('TRACE END [%Y-%m-%d %H:%M:%S]')
sys.settrace(oldfunc)
trace_cwd = os.getcwd() #: current directory is stripped from filenames
trace_depth = 0
trace_filter = ['/usr/lib/python']
# [ ] check what will happen with depth when trace started deep inside and
# moved out (also check for Xdebug)
def function_trace_xdebug(frame, event, arg):
'''print function trace in default xdebug human-readable format
http://xdebug.org/docs/execution_trace'''
global trace_depth
if event == 'call': # generated before any function call
def strip_cwd(filename):
global trace_cwd
if trace_cwd and filename.startswith(trace_cwd):
return os.path.normpath(filename.replace(trace_cwd, '.', 1))
return filename
trace_depth += 1
funcname = frame.f_code.co_name
filename = strip_cwd(frame.f_code.co_filename)
lineno = frame.f_lineno
param = ''
if funcname == '<module>':
funcname = '<%s>' % inspect.getmodule(frame.f_code).__name__
# by analogy with PHP require() trace in Xdebug, the format is
# <mod.name>(module_location) file_imported_from:line
param = filename
filename = strip_cwd(frame.f_back.f_code.co_filename)
# skip paths mentioned in trace_filter
if (funcname[0] is not '<' # not module import
and any( [filename.startswith(x) for x in trace_filter] )):
pass
else:
print '%*s-> %s(%s) %s:%s' % (trace_depth*2, '', funcname, param,
filename, lineno)
return function_trace_xdebug
elif event == 'return':
trace_depth -= 1
else:
pass #print 'TRACE: UNKNOWN %s EVENT WITH ARG %s' % (event, arg)
return
@techtonik
Copy link
Author

f30994 - add filename and lineno info, add module name for entries

TRACE START [2011-10-20 11:27:06]
-> {main}()
  -> abspath() /usr/lib/python2.7/posixpath.py:341
    -> isabs() /usr/lib/python2.7/posixpath.py:51
    -> join() /usr/lib/python2.7/posixpath.py:60
...
      -> <module>(StringIO) /usr/lib/python2.7/StringIO.py:30
        -> StringIO() /usr/lib/python2.7/StringIO.py:42
      -> <module>(xml) /usr/lib/python2.7/xml/__init__.py:17
      -> <module>(xml.parsers) /usr/lib/python2.7/xml/parsers/__init__.py:8
      -> <module>(xml.parsers.expat) /usr/lib/python2.7/xml/parsers/expat.py:1
      -> ParseError() /home/user07/trac/0.12dev/.pylibs/genshi/input.py:53
      -> XMLParser() /home/user07/trac/0.12dev/.pylibs/genshi/input.py:75
      -> HTMLParser() /home/user07/trac/0.12dev/.pylibs/genshi/input.py:274
  -> exists() /usr/lib/python2.7/genericpath.py:15
  -> trace_stop() bootstrap.py:21
TRACE END   [2011-10-20 11:27:27]

c598d4 - strip current working directory from filenames
7590f2 - wrap actual module name in <>, provide path to module as a param, and mention the line module is imported from in final argument
36b94b - convert to a module

import xtrace
xtrace.start()
# ...
xtrace.stop()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment