def trace_logging_on(refdir=default_refdir,    # reference-point directory path
                     negprefix=('..', '<'),  # negative filtering path prefixes
                     filterfunc=(lambda s: True),   # custom filtering function
                     filterarg='',     # .format()-able filter argument pattern
                                       # e.g. '{event}&{path}&{frame.f_lineno}'
                     events2log = { # mapping events to .format()-able log patt
                         'call': '[C  ] {path}: {name}{callargs}',
                         'return': '[  R] {path}: {name}  ->  {argrepr}',
                         'exception': '[ E ] {path}, in {name}:\n{traceback}',
                     },  # [.format()-able patterns refer to tracer()'s locals]
                     logger='',                       # logger name or instance
                     loggermethod='debug',                 # logger method name
                     reprfunc=default_reprfunc):  # repr()-replacement function

    """
    Enable logging of Python call/return/exception events (handily filtered).

    Usage variants:
    * simply-turn-on call:        trace_logging_on(...)
    * context manager syntax:     with trace_logging_on(...): ...
    * context manager with 'as':  with trace_logging_on(...) as tracefunc: ...
    """

    from inspect import getargvalues, formatargvalues
    from traceback import format_exception
    if isinstance(logger, basestring):
        from logging import getLogger
        logger = getLogger(logger)
    log = getattr(logger, loggermethod)
    relpath = os.path.relpath
    formatvalue = (lambda s: '=' + reprfunc(s))
    filterarg_format = filterarg.format

    def tracer(frame, event, arg):
        if event not in events2log:  # initial event filtering
            return tracer
        path = relpath(frame.f_code.co_filename, refdir)  # relative to refdir
        # path-prefix-based scope filtering (negative, i.e. False lets by)
        if path.startswith(negprefix):
            return None  # (<- None to discontinue tracing in sub-scopes)
        # adding some locals (to be used to format filtering/logging arguments)
        name = frame.f_code.co_name
        argrepr = reprfunc(arg)
        if event == 'call':
            argvalues = (getargvalues(frame) if name != '<genexpr>'
                         else ([],) + getargvalues(frame)[1:])
            callargs = formatargvalues(*argvalues, formatvalue=formatvalue)
        elif event == 'exception':
            traceback = ''.join(format_exception(*arg))
        pattern_fields = locals()
        # callback-based individual filtering (positive, i.e. True lets by)
        if not filterfunc(filterarg_format(**pattern_fields)):
            return tracer
        # event-specific logging
        log(events2log[event].format(**pattern_fields))
        return tracer

    with_support = [_with_statement_support(tracer, previous=sys.gettrace())]
    sys.settrace(tracer)
    return with_support.pop()   # (we don't like circular references...)

    Enable logging of Python call/return/exception events (handily filtered).

    Usage variants:
    * simply-turn-on call:        trace_logging_on(...)
    * context manager syntax:     with trace_logging_on(...): ...
    * context manager with 'as':  with trace_logging_on(...) as tracefunc: ...
    
recipes/Python/577429_Tiny_tracedebuglogging_tool_smart_event/recipe-577429.py