Autologging — easier logging and tracing for classes¶
Release: | 0.3.0 |
---|
The autologging module defines two decorators and a metaclass factory that make logging easier to use with classes.
Python 2.7 and Python 3.2+ are supported using the same codebase. All examples given on this site use Python 3 syntax.
Table of Contents¶
Download and Install¶
- Use “pip install Autologging”.
- Download a source or built distribution from Autologging on SourceForge and run either setup.py or the binary installer.
- Clone the Autologging Mercurial repository from BitBucket and run setup.py.
If you download or clone the source, the test suite can be run from the project root directory in either of the following ways:
python -m unittest test.suite
python setup.py test
Introduction¶
When using the Python logging module to log classes, there are a couple of challenges that usually must be addressed by the developer:
- The standard logging module is not inherently “aware” of classes in the context of logging statements made within class methods.
- The standard logging module has no concept of tracing (i.e. there are neither log methods for tracing nor any log level lower than logging.DEBUG to use for tracing). (See logging vs. tracing.)
Challenge #1 is not a failing of the logging module, but rather a side-effect of using Python stack frames to determine caller information (see logging.Logger.findCaller()).
A reasonable workaround for #1 is to simply create a class-level logger that uses the class’s qualified name as the logger name. This approach is consistent with respect to the logging module’s recommended usage for logger naming (as well as being analogous to java.util.logging usage, upon which Python’s logging module is based).
Challenge #2 can also be worked around, though it requires a bit more effort. Defining a new log level/name for tracing (via logging.addLevelName()) is a start, but writing (and maintaining) the tracing log statements becomes tedious and error prone. In a language as dynamic as Python, it should not be (and isn’t) necessary to do this “by hand.”
Class logging boilerplate code belongs in a module¶
As it turns out, the code necessary to create appropriately-named loggers for classes and to trace functions or class methods is boilerplate.
The autologging module encapsulates this boilerplate code for you, allowing you to use simple decorators and a metaclass to get consistent class logging and tracing.
A module that employs the use of autologging resembles the following:
import logging
from autologging import logged, traced, TracedMethods
_logger = logging.getLogger(__name__)
@traced
def my_helper():
_logger.debug("I am doing something helpful.")
@logged(_logger)
def another_helper():
another_helper.__logger.info("some useful information here")
@logged
class MyClass(metaclass=TracedMethods("my_staticmethod", "my_classmethod",
"my_instancemethod")):
@staticmethod
def my_staticmethod():
MyClass.__logger.debug("I am a static method.")
@classmethod
def my_classmethod(cls):
cls.__logger.debug("I am a class method.")
def my_instancemethod(self):
self.__logger.debug("I am an instance method.")
New in version 0.2.2: Module-level (and inner) functions may now be decorated with @logged. Use <function-name>.__logger to access the logger.
Changed in version 0.2: Inner classes and “internal” classes (i.e. classes named with leading underscore) are now handled correctly.
A module that uses autologging for inner classes resembles the following:
class Outer:
@logged
class _Inner:
"""Logger name will be '<modulename>.Outer._Inner'."""
Please see The autologging API for details, then check out Examples of using autologging.