Guest User

Untitled

a guest
Apr 22nd, 2018
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.77 KB | None | 0 0
  1. #!/usr/bin/python
  2. """ tracer.py: Quick and dirty python 'strace'
  3. """
  4.  
  5. import os
  6. import os.path
  7. import sys
  8. import linecache
  9. from functools import wraps
  10.  
  11. class tracer(object):
  12. """
  13. Let's say you want to trace a function/method ``foo``::
  14.  
  15. ...
  16. ...
  17. def foo(args):
  18. <stuff you are interested in>
  19. ...
  20. ...
  21.  
  22. You simply add the following::
  23.  
  24. from tracer import tracer
  25. ...
  26. ...
  27. @tracer
  28. def foo(args):
  29. <stuff you are interested in>
  30. ...
  31. ...
  32.  
  33. Now, your function is setup for tracing. Note however, by default nothing
  34. will be traced and the tracer() function will effectively be a noop until
  35. there is a DEBUG variable set in the processes environment at runtime.
  36.  
  37. So, assuming that the function/method ``foo`` is called when the command
  38. ``fancyapp`` is run::
  39.  
  40. $ fancyapp # will *not* enable tracing
  41. $ DEBUG=1 fancyapp # will enable tracing
  42.  
  43. caveats:
  44.  
  45. * this tool skips over system modules (ie: anything under
  46. <sys.prefix>/lib/ ) and builtins. This behavior can be changed by
  47. overriding the is_ignored() method.
  48. * this tool currently spits its output to stderr, it might be better to
  49. send output to a log file instead.
  50. """
  51.  
  52. def __init__(self, fn):
  53. self.indent = ''
  54. self.fn = fn
  55.  
  56. def is_ignored(self, filename):
  57. """ is_ignored(filename) -> True or False
  58.  
  59. Are calls within this filename skipped during a trace ?
  60. """
  61. system_path = os.path.dirname( sys.modules['os'].__file__ )
  62.  
  63. return True if ( # skip over
  64. filename.startswith(system_path) or # - system modules
  65. filename.startswith('<') or # - builtins like <string>
  66. __file__.find(filename) != -1 # - /this/ module
  67. ) else False
  68.  
  69. def trace_fn(self, frame, event, arg):
  70. """ trace_fn(frame, event, arg) -> trace_fn
  71.  
  72. The tracing function that'll be set using the ``sys.settrace()`` call.
  73. """
  74. filename = frame.f_code.co_filename
  75. if self.is_ignored(filename):
  76. return self.trace_fn
  77.  
  78. lineno = frame.f_lineno
  79. src = linecache.getline(filename, lineno).strip()
  80. filename = filename if len(filename) < 30 else '...' + filename[-27:]
  81. if event in ('call', 'return'):
  82. fn = frame.f_code.co_name
  83. if event == 'call':
  84. args = ''
  85. if frame.f_code.co_argcount > 0:
  86. args = ', '.join('%s = %s' % (k, repr(v)) for k, v in frame.f_locals.items())
  87. sys.stderr.write("%30s +%-5s |%s%s(%s)\n" % (filename, lineno, self.indent, fn, args))
  88. self.indent += ' '
  89. else:
  90. self.indent = self.indent[:-2]
  91. if src.find('return') != -1:
  92. sys.stderr.write("%30s +%-5s |%s%s <= %s\n" % (filename, lineno, self.indent, fn, src.replace('return', '')))
  93. else:
  94. sys.stderr.write("%30s +%-5s |%s%s() <= None\n" % (filename, lineno, self.indent, fn))
  95. else:
  96. sys.stderr.write("%30s +%-5s |%s%s\n" % (filename, lineno, self.indent, src))
  97.  
  98. return self.trace_fn
  99.  
  100. def __call__(self, *args, **kwargs):
  101. if os.environ.get('DEBUG', None):
  102. @wraps(self.fn)
  103. def traceit(*args, **kwargs):
  104. tracer = sys.gettrace()
  105. try:
  106. sys.settrace(self.trace_fn)
  107. return self.fn(*args, **kwargs)
  108. finally:
  109. sys.settrace(tracer)
  110.  
  111. return traceit(*args, **kwargs)
  112. else:
  113. return self.fn(*args, **kwargs)
Add Comment
Please, Sign In to add comment