def METHOD_NAME(func):
    @functools.wraps(func)
    def trace(*args, **kw):
        # default to logger that was passed by module, but
        # can override by passing logger=foo as function parameter.
        # make sure this doesn't conflict with one of the parameters
        # you are expecting
        filename = os.path.normcase(inspect.getsourcefile(func))
        func_name = func.__name__
        if hasattr(func, 'func_code'):
            lineno = func.func_code.co_firstlineno
        else:
            lineno = func.__code__.co_firstlineno
        l2 = kw.get('logger', logger)
        if l2 is None:
            l2 = logging.getLogger("trace.%s" % func.__module__)
        if isinstance(l2, str):
            l2 = logging.getLogger(l2)
        message = "ENTER %s("
        message = message + ', '.join([safe_repr(arg) for arg in args])
        if args and kw:
            message += ', '
        for k, v in list(kw.items()):
            message = message + "%s=%s" % (k, safe_repr(v))
        message = message + ")"
        frame = inspect.getouterframes(inspect.currentframe())[1][0]
        doLog(l2, logging.INFO, os.path.normcase(frame.f_code.co_filename),
              frame.f_lineno, message, args=[func_name], exc_info=None,
              func=frame.f_code.co_name)
        try:
            result = "Bad exception raised: Exception was not a derived "\
                     "class of 'Exception'"
            try:
                result = func(*args, **kw)
            except (KeyboardInterrupt, Exception) as e:
                result = "EXCEPTION RAISED"
                doLog(l2, logging.INFO, filename, lineno,
                      "EXCEPTION: %s\n", args=[e],
                      exc_info=sys.exc_info(), func=func_name)
                raise
        finally:
            doLog(l2, logging.INFO, filename, lineno,
                  "LEAVE %s --> %s\n", args=[func_name, result],
                  exc_info=None, func=func_name)
        return result
    return trace
    #end of trace()