# Copyright The IETF Trust 2012-2019, All Rights Reserved import os import sys import time as timeutils import inspect import six if six.PY3: from typing import Callable try: import syslog logger = syslog.syslog # type: Callable except ImportError: # import syslog will fail on Windows boxes import logging logging.basicConfig(filename='tracker.log',level=logging.INFO) logger = logging.info try: from pprint import pformat except ImportError: pformat = lambda x: x # type: ignore import cProfile import traceback as tb # A debug decorator, written by Paul Butler, taken from # http://paulbutler.org/archives/python-debugging-with-decorators/ # Additional functions and decorator functionality added by # Henrik Levkowetz __version__ = "0.16" increment = 2 debug = False # Number of times to indent output # A list is used to force access by reference _report_indent = [4] _mark = [ timeutils.time() ] def set_indent(i): _report_indent[0] = i def trace(fn): # renamed from 'report' by henrik 16 Jun 2011 """Decorator to print information about a function call for use while debugging. Prints function name, arguments, and call number when the function is called. Prints this information again along with the return value when the function returns. """ def fix(s,n=64): import re s = re.sub(r'\\t', ' ', s) s = re.sub(r'\s+', ' ', s) if len(s) > n+3: s = s[:n]+"..." return s def wrap(fn, *params,**kwargs): call = wrap.callcount = wrap.callcount + 1 indent = ' ' * _report_indent[0] fr = tb.format_stack()[-3].strip()[4:] # call from fi, co = [ l.strip() for l in fr.splitlines()[:2] ] # file info, code fu = "%s.%s()" % (fn.__module__, fn.__name__) # function name fc = "%s(%s)" % (fn.__name__, ', '.join( # function call [fix(repr(a)) for a in params] + ["%s = %s" % (a, fix(repr(b))) for a,b in kwargs.items()] )) if debug: sys.stderr.write("\n%s From %s:\n%s | %s\n%s %s\n%s* %s [#%s]\n" % (indent, fi, indent, co, indent, fu, indent, fc, call)) _report_indent[0] += increment mark = timeutils.time() ret = fn(*params,**kwargs) tau = timeutils.time() - mark _report_indent[0] -= increment if debug: sys.stderr.write("%s %s | %.3fs [#%s] ==> %s\n" % (indent, fc, tau, call, fix(repr(ret)))) return ret wrap.callcount = 0 if debug: from decorator import decorator return decorator(wrap, fn) else: return fn def filepos(): file, line, func, text = tb.extract_stack(None, 2)[0] parts = file.split(os.sep) name = os.sep.join(parts[-2:]) indent = ' ' * (_report_indent[0]) return "%s%s:%s: %s()" % (indent, name, line, func) def mark(): def show_entry(e): sys.stderr.write(" at %s:L%s %s() %s\n" % e) if debug: indent = ' ' * (_report_indent[0]) file, line, func, text = tb.extract_stack(None, 2)[0] parts = file.split(os.sep) name = os.sep.join(parts[-2:]) sys.stderr.write("%sMark %s:%s\n" % (indent, name, line)) _mark[0] = timeutils.time() def lap(s): if debug: clk = timeutils.time() tau = clk - _mark[0] ts = timeutils.strftime("%H:%M:%S", timeutils.localtime(clk)) say("%s: %.3fs since mark: %s" % (ts, tau, s)) def clock(s): if debug: lap(s) _mark[0] = timeutils.time() def time(fn): """Decorator to print timing information about a function call. """ def wrap(fn, *params,**kwargs): indent = ' ' * _report_indent[0] fc = "%s.%s()" % (fn.__module__, fn.__name__,) mark = timeutils.time() ret = fn(*params,**kwargs) tau = timeutils.time() - mark sys.stderr.write("%s| %s | %.3fs\n" % (indent, fc, tau)) return ret wrap.callcount = 0 if debug: from decorator import decorator return decorator(wrap, fn) else: return fn def show(name): if debug: frame = inspect.stack()[1][0] value = eval(name, frame.f_globals, frame.f_locals) indent = ' ' * (_report_indent[0]) sys.stderr.write("%s%s: '%s'\n" % (indent, name, value)) def showpos(name): if debug: file, line, func, text = tb.extract_stack(None, 2)[0] parts = file.split(os.sep) fn = os.sep.join(parts[-2:]) # frame = inspect.stack()[1][0] value = eval(name, frame.f_globals, frame.f_locals) indent = ' ' * (_report_indent[0]) sys.stderr.write("%s%s:%s: %s: '%s'\n" % (indent, fn, line, name, value)) def log(name): if debug: frame = inspect.stack()[1][0] value = eval(name, frame.f_globals, frame.f_locals) indent = ' ' * (_report_indent[0]) logger("%s%s: %s" % (indent, name, value)) def pprint(name): if debug: frame = inspect.stack()[1][0] value = eval(name, frame.f_globals, frame.f_locals) indent = ' ' * (_report_indent[0]) sys.stderr.write("%s%s:\n" % (indent, name)) lines = pformat(value).split('\n') for line in lines: sys.stderr.write("%s %s\n"%(indent, line)) def dir(name): if debug: name = "dir(%s)" % name frame = inspect.stack()[1][0] value = eval(name, frame.f_globals, frame.f_locals) indent = ' ' * (_report_indent[0]) sys.stderr.write("%s%s:\n" % (indent, name)) lines = pformat(value).split('\n') for line in lines: sys.stderr.write("%s %s\n"%(indent, line)) def type(name): if debug: name = "type(%s)" % name frame = inspect.stack()[1][0] value = eval(name, frame.f_globals, frame.f_locals) indent = ' ' * (_report_indent[0]) sys.stderr.write("%s%s: %s\n" % (indent, name, value)) def say(s): if debug: indent = ' ' * (_report_indent[0]) sys.stderr.write("%s%s\n" % (indent, s)) sys.stderr.flush() def profile(fn): def wrapper(*args, **kwargs): datafn = fn.__name__ + ".profile" # Name the data file sensibly prof = cProfile.Profile() retval = prof.runcall(fn, *args, **kwargs) prof.dump_stats(datafn) return retval if debug: from decorator import decorator return decorator(wrapper, fn) else: return fn def traceback(levels=None): if debug: indent = ' ' * (_report_indent[0]) sys.stderr.write("\n%s---- Stack ----\n" % indent) if levels: start = -2-levels else: start = None for s in tb.format_stack()[start:-1]: sys.stderr.write("%s%s" % (indent, s)) sys.stderr.write("%s---------------\n" % indent) def show_caller(level=None): if debug: indent = ' ' * (_report_indent[0]) if level is None: level = -3 sys.stderr.write("%sCalled from %s\n" % (indent, tb.format_stack()[level].strip()[4:])) def info(name): if debug: frame = inspect.stack()[1][0] value = eval(name, frame.f_globals, frame.f_locals) vtype = eval("type(%s)"%name, frame.f_globals, frame.f_locals) indent = ' ' * (_report_indent[0]) sys.stderr.write("%s%s: '%s' (%s)\n" % (indent, name, value, vtype))