#Setup Your Log import logging logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG) log = logging #paste this somewhere accessible in your code def LogTrace(func=None, redact=[]): import threading import traceback def wrapper(func): def decorator(*args, **kwargs): if not hasattr(LogTrace, 'local'): LogTrace.local = threading.local() tl = LogTrace.local if not hasattr(tl, 'log_indent'): tl.log_indent=0 funcname = func.__module__ + "." + func.__name__ margs = [str("'%s'"%arg if isinstance(arg, str) else arg) for arg in [("********" if i in redact else arg) for i, arg in enumerate(args)]] #list all positional arguments margs.extend(["%s=%s"%(key, str("'%s'"%val if isinstance(val, str) else val)) for key, val in [(key, ("********" if key in redact else val)) for key, val in kwargs.items()]]) #list all keyword arguments try: log.debug("\t"*tl.log_indent + "Entering %s(%s)" % (funcname, ", ".join(margs))) tl.log_indent+=1 retval = func(*args, **kwargs) tl.log_indent-=1 log.debug("\t"*tl.log_indent + "Leaving %s = %s" % (funcname, retval)) return retval except Exception as e: tl.log_indent-=1 file = traceback.extract_tb()[-1][0] line = traceback.extract_tb()[-1][1] clsfunc = e.__class__.__name__ log.error("\t"*tl.log_indent + "Encountered error in %s: %s(%s) [%s:%i]" % (funcname, clsfunc, e.message, file, line)) raise e return decorator if func: return wrapper(func) else: return wrapper #decorate your functions to be traced @LogTrace def WhatDoesThisFunctionDo(): pass #if some information should be redacted from the log, add it's position and name to the list @LogTrace(redact=[2,'password',3,'secret') def MySensitiveFunction(param1, param2, password, secret): pass