Zobrazují se příspěvky se štítkemPython. Zobrazit všechny příspěvky
Zobrazují se příspěvky se štítkemPython. Zobrazit všechny příspěvky

čtvrtek 5. října 2017

Python logger by class

Common Python logging practice is to have one logger per module (e.s. see the Fang's blog):
import logging
logger = logging.getLogger(__name__)
However, the general habit in other OOP programming languages (Java, C#, ...) is to have one (private static) logger per class:
public class MyObject {
    private final static Logger LOG = Logger.getLogger(MyObject.class.getName());
}
In Python, a logger per class may be created, too:
import logging
class Foo(object):
    __log = logging.getLogger(__name__ + '.Foo')

    def foo(self):
        self.__log.info('foo called')


class Bar(Foo):
    __log = logging.getLogger(__name__ + '.Bar')

    def bar(self):
        self.__log.info('bar called')


bar = Bar()
bar.foo()
bar.bar()

>>> INFO:__main__.Foo:foo called
>>> INFO:__main__.Bar:bar called

Note the double leading underscore __log to exploit the Python name mangling to simulate a private attribute. However, it is not very convenient to write the name of the class as a string. One way to avoid that is to init the logger after the class has been created:
class Bar(Foo):
    def bar(self):
        self.__log.info('bar called')


Bar._Bar__log = logging.getLogger(__name__ + Bar.__name__) # manual name mangling
Still not very nice. We had to type the name of the class manually again. So let's exploit a decorator black magic to do it automatically:
def addlogger(cls: type):
    aname = '_{}__log'.format(cls.__name__)
    setattr(cls, aname, logging.getLogger(cls.__module__ + '.' + cls.__name__))
    return cls


@addlogger
class Foo(object):
    def foo(self):
        self.__log.info('foo called')


@addlogger
class Bar(Foo):
    def bar(self):
        self.__log.info('bar called')


bar = Bar()
bar.foo()
bar.bar()

>>> INFO:__main__.Foo:foo called
>>> INFO:__main__.Bar:bar called
And voilà, we have a private static logger for each class with just one simple line or code.