Author: reinhard Date: 2007-07-16 16:48:40 -0500 (Mon, 16 Jul 2007) New Revision: 9760
Modified: trunk/gnue-common/src/base/log.py Log: Added function logging decorator. issue123 in-progress Modified: trunk/gnue-common/src/base/log.py =================================================================== --- trunk/gnue-common/src/base/log.py 2007-07-13 22:22:52 UTC (rev 9759) +++ trunk/gnue-common/src/base/log.py 2007-07-16 21:48:40 UTC (rev 9760) @@ -35,12 +35,11 @@ from gnue.common.base import utils -__all__ = ['debug', 'info', 'warning', 'deprecated', 'error', 'critical', - 'exception', 'debug_n', 'info_n', 'warning_n', 'deprecated_n', - 'error_n', 'critical_n', 'exception_n'] +__all__ = ['logged_f', 'debug', 'info', 'warning', 'deprecated', 'error', + 'critical', 'exception', 'debug_n', 'info_n', 'warning_n', + 'deprecated_n', 'error_n', 'critical_n', 'exception_n'] # TODO: -# - function for enter() and leave(), maybe as decorator? # - function to declare function as deprecated, maybe as decorator? # - Exception hook # - allow for __gnue_logger__ module global variable to use as a logger name @@ -49,6 +48,105 @@ # ----------------------------------------------------------------------------- +# Log function entry and exit +# ----------------------------------------------------------------------------- + +def logged_f(func): + """ + Decorator to activate logging for a function. + + If this decorator is applied to a function, every call to that function is + logged on C{DEBUG} level. + + Usage with Python 2.4 or later:: + @logged_f + myfunction(self, foo, bar): + : + + Usage with Python 2.3:: + myfunction(self, foo, bar): + : + myfunction=logged_f(myfunction) + """ + def new_f(*args, **kwargs): + name = func.func_globals['__name__'] + __enter(name, func) + result = func(*args, **kwargs) + __leave(name, func, result) + return result + return new_f + +# ----------------------------------------------------------------------------- + +def __enter(name, func): + + # Get the caller's frame + frame = inspect.currentframe().f_back + while not frame.f_code.co_name == 'new_f': + frame = frame.f_back + + try: + fname = __func_name(func, frame) + + args = frame.f_locals['args'] + kwargs = frame.f_locals['kwargs'] + + params = [] + # Arguments + params.extend([repr(item) for item in args]) + # Keyword arguments + params.extend(["%s=%r" % (k, v) for (k, v) in kwargs.items()]) + + msg = "Calling function %s(%s)" % (fname, ", ".join(params)) + + finally: + # Frame object has to be deleted manually. + del frame + + debug_n(name, msg) + return True + +# ----------------------------------------------------------------------------- + +def __leave(name, func, result): + + # Get the caller's frame + frame = inspect.currentframe().f_back + while not frame.f_code.co_name == 'new_f': + frame = frame.f_back + + try: + msg = "Returning from function " + __func_name(func, frame) + "() -> " \ + + repr(result) + finally: + # Frame object has to be deleted manually. + del frame + + debug_n(name, msg) + return True + +# ----------------------------------------------------------------------------- + +def __func_name(func, frame): + # It seems like there is no way to find out the name of the class that + # defined a method. To print out the class name in the log, we need to + # inspect the 'self' parameter. + fname = func.__name__ + code = func.func_code + if code.co_argcount > 0 and code.co_names[0] == 'self': + klass = frame.f_locals['args'][0].__class__ + if isinstance(klass, str): + # Old stle class + fname = klass + '.' + fname + else: + # New style class + fname = klass.__module__ + '.' + klass.__name__ + '.' + fname + else: + fname = func.func_globals['__name__'] + '.' + fname + return fname + + +# ----------------------------------------------------------------------------- # Log to the logger named after the calling module # ----------------------------------------------------------------------------- _______________________________________________ commit-gnue mailing list commit-gnue@gnu.org http://lists.gnu.org/mailman/listinfo/commit-gnue