The autologging API — Autologging 0.1 documentation

# Autologging 0.1 documentation

## The autologging API

# The `autologging` API

`autologging.` `TRACE` = 1

  A custom tracing log level, lower in severity than `logging.DEBUG`. Autologging `traced()` and `TracedMethods()` create log records with this custom level.

`autologging.` `logged`(obj)

  Add a named logger member to a decorated class.

  The logger member always has a dot-separated name consisting of the parent logger’s name, followed by a dot (‘.’), followed by the class name.

  If obj is a `class`, then `obj.__logger` will have the logger name “module-name.class-name”:

      >>> @logged
      ... class Test:
      ...     pass
      ...
      >>> Test._Test__logger.name
      'autologging.Test'

  If obj is a `logging.Logger` object, then that logger is treated as the parent logger and the decorated class’s `__logger` member will have the logger name “parent-logger-name.class-name”:

      >>> _logger = logging.getLogger("test.parent")
      >>> @logged(_logger)
      ... class Test:
      ...     pass
      ...
      >>> Test._Test__logger.name
      'test.parent.Test'

  Note

  The logger member is made “private” (i.e. `__logger` with double underscore) to ensure that log messages that include the %(name)s format placeholder are written with the correct name.

  Consider a subclass of a `@logged`-decorated parent class. If the subclass were not decorated with `@logged` and could access the parent’s logger member directly to make logging calls, those log messages would display the name of the parent class, not the subclass.

  Therefore, subclasses of a `@logged`-decorated parent class that wish to use a provided `self.__logger` object must themselves be decorated with `@logged`.

`autologging.` `traced`(obj)

  Add call/return tracing to an unbound function.

  Warning

  This decorator will not quite work as expected (or may fail entirely) for class methods. To automatically trace class method call/return, please see the `TracedMethods` metaclass factory.

  In the following example, tracing log messages are written to a log whose channel defaults to the function’s module name:

      >>> import sys
      >>> logging.basicConfig(level=TRACE, stream=sys.stdout)
      >>> @traced
      ... def my_function(arg, keyword=None):
      ...     return "%s and %s" % (arg, keyword)
      ...
      >>> my_function("spam", keyword="eggs")
      TRACE:autologging:CALL my_function *('spam',) **{'keyword': 'eggs'}
      TRACE:autologging:RETURN my_function 'spam and eggs'
      'spam and eggs'

  In the following example, tracing log messages are written to a user-named log:

      >>> import sys
      >>> logging.basicConfig(level=TRACE, stream=sys.stdout)
      >>> _logger = logging.getLogger("test.ing")
      >>> @traced(_logger)
      ... def my_function(arg, keyword=None):
      ...     return "%s and %s" % (arg, keyword)
      ...
      >>> my_function("spam", keyword="eggs")
      TRACE:test.ing:CALL my_function *('spam',) **{'keyword': 'eggs'}
      TRACE:test.ing:RETURN my_function 'spam and eggs'
      'spam and eggs'

`autologging.` `TracedMethods`(*args)

  Return a metaclass that enables call/return tracing for methods.

  Only methods named explicitly in args will be traced.

  If the first item in args is a `logging.Logger`, then that logger is treated as the parent logger, and method tracers will use a logger with the name “parent-logger-name.class-name”. Otherwise, method tracers will use a logger with the name “module-name.class-name”.

  Note

  Regardless of whether a logger was explicitly passed in or not, the logger used by the tracers is not made available to the class or its instances.

  This allows for logging configurations where tracing is sent to a separate file/target than logging. For such a configuration, simply configure a logger specifically for tracing and pass that logger as the first argument to `TracedMethods`.

  Also note that a class may be decorated by `logged()` and use `TracedMethods` as a metaclass without conflict.

  In the following example, tracing log messages are written to a log whose channel defaults to “module-name.class-name”:

      >>> import sys
      >>> logging.basicConfig(level=TRACE, stream=sys.stdout)
      >>> class MyClass(object,
      ...               metaclass=TracedMethods("my_staticmethod",
      ...                                       "my_classmethod",
      ...                                       "my_instancemethod")):
      ...     @staticmethod
      ...     def my_staticmethod(arg, keyword=None):
      ...         return "%s and %s" % (arg, keyword)
      ...     @classmethod
      ...     def my_classmethod(cls, arg, keyword=None):
      ...         return "%s and %s" % (arg, keyword)
      ...     def my_instancemethod(self, arg, keyword=None):
      ...         return "%s and %s" % (arg, keyword)
      ...
      >>> MyClass.my_staticmethod("spam", keyword="eggs")
      TRACE:autologging.MyClass:CALL MyClass.my_staticmethod *('spam',) **{'keyword': 'eggs'}
      TRACE:autologging.MyClass:RETURN MyClass.my_staticmethod 'spam and eggs'
      'spam and eggs'
      >>> MyClass.my_classmethod("green eggs", keyword="ham")
      TRACE:autologging.MyClass:CALL MyClass.my_classmethod *('green eggs',) **{'keyword': 'ham'}
      TRACE:autologging.MyClass:RETURN MyClass.my_classmethod 'green eggs and ham'
      'green eggs and ham'
      >>> instance = MyClass()
      >>> instance.my_instancemethod("Batman", keyword="Robin")
      TRACE:autologging.MyClass:CALL MyClass.my_instancemethod *('Batman',) **{'keyword': 'Robin'}
      TRACE:autologging.MyClass:RETURN MyClass.my_instancemethod 'Batman and Robin'
      'Batman and Robin'

  In the following example, tracing log messages are written to a user-named log:

      >>> import sys
      >>> logging.basicConfig(level=TRACE, stream=sys.stdout)
      >>> _logger = logging.getLogger("test.ing")
      >>> class MyClass(object,
      ...               metaclass=TracedMethods(_logger, "my_staticmethod",
      ...                                       "my_classmethod",
      ...                                       "my_instancemethod")):
      ...     @staticmethod
      ...     def my_staticmethod(arg, keyword=None):
      ...         return "%s and %s" % (arg, keyword)
      ...     @classmethod
      ...     def my_classmethod(cls, arg, keyword=None):
      ...         return "%s and %s" % (arg, keyword)
      ...     def my_instancemethod(self, arg, keyword=None):
      ...         return "%s and %s" % (arg, keyword)
      ...
      >>> MyClass.my_staticmethod("spam", keyword="eggs")
      TRACE:test.ing.MyClass:CALL MyClass.my_staticmethod *('spam',) **{'keyword': 'eggs'}
      TRACE:test.ing.MyClass:RETURN MyClass.my_staticmethod 'spam and eggs'
      'spam and eggs'
      >>> MyClass.my_classmethod("green eggs", keyword="ham")
      TRACE:test.ing.MyClass:CALL MyClass.my_classmethod *('green eggs',) **{'keyword': 'ham'}
      TRACE:test.ing.MyClass:RETURN MyClass.my_classmethod 'green eggs and ham'
      'green eggs and ham'
      >>> instance = MyClass()
      >>> instance.my_instancemethod("Batman", keyword="Robin")
      TRACE:test.ing.MyClass:CALL MyClass.my_instancemethod *('Batman',) **{'keyword': 'Robin'}
      TRACE:test.ing.MyClass:RETURN MyClass.my_instancemethod 'Batman and Robin'
      'Batman and Robin'