Naming Python loggers
Asked Answered
F

3

49

In Django, I've got loggers all over the place, currently with hard-coded names.

For module-level logging (i.e., in a module of view functions) I have the urge to do this.

log = logging.getLogger(__name__)

For class-level logging (i.e., in a class __init__ method) I have the urge to do this.

self.log = logging.getLogger("%s.%s" % (
    self.__module__, self.__class__.__name__))

I'm looking for second opinions before I tackle several dozen occurrences of getLogger("hard.coded.name").

Will this work? Anyone else naming their loggers with the same unimaginative ways?

Further, should I break down and write a class decorator for this log definition?

Footpoundsecond answered 30/12, 2008 at 19:47 Comment(1)
I'm curious: why would you want class-level loggin?Abbevillian
O
69

I typically don't use or find a need for class-level loggers, but I keep my modules at a few classes at most. A simple:

import logging
LOG = logging.getLogger(__name__)

At the top of the module and subsequent:

LOG.info('Spam and eggs are tasty!')

from anywhere in the file typically gets me to where I want to be. This avoids the need for self.log all over the place, which tends to bother me from both a put-it-in-every-class perspective and makes me 5 characters closer to 79 character lines that fit.

You could always use a pseudo-class-decorator:

>>> import logging
>>> class Foo(object):
...     def __init__(self):
...             self.log.info('Meh')
... 
>>> def logged_class(cls):
...     cls.log = logging.getLogger('{0}.{1}'.format(__name__, cls.__name__))
... 
>>> logged_class(Foo)
>>> logging.basicConfig(level=logging.DEBUG)
>>> f = Foo()
INFO:__main__.Foo:Meh
Overripe answered 31/12, 2008 at 7:31 Comment(2)
Interesting approach... I think I spent too long with Java. Module-level logging may be just what the doctor ordered.Footpoundsecond
There is one problem with the usage of __name__: When the module is imported somewhere using a relative import, its messages will go to the log using that shorter __name__. This is not a problem as long as you avoid these relative imports, which are bad style anyway (as stated in the python FAQ)Amateurish
P
3

For class level logging, as an alternative to a pseudo-class decorator, you could use a metaclass to make the logger for you at class creation time...

import logging

class Foo(object):
    class __metaclass__(type):
        def __init__(cls, name, bases, attrs):
            type.__init__(name, bases, attrs)
            cls.log = logging.getLogger('%s.%s' % (attrs['__module__'], name))
    def __init__(self):
        self.log.info('here I am, a %s!' % type(self).__name__)

if __name__ == '__main__':
    logging.basicConfig(level=logging.DEBUG)
    foo = Foo()
Palladio answered 27/10, 2009 at 3:36 Comment(2)
I had to change type.__init__(...) to object.__init__(...), or there will be an error under python 2.7: descriptor '__init__' requires a 'type' object but received a 'str'. But I cannot get this method to work under python 3.x.Ceiba
I figured it out. To get this method also working for python 3.x, I need to write the metaclass separately, and use hack like logging_metaclass_hack = logging_metaclass("logging_metaclass_hack", (object, ), {}) and inherit to Foo.Ceiba
P
2

That looks like it will work, except that self won't have a __module__ attribute; its class will. The class-level logger call should look like:

self.log = logging.getLogger( "%s.%s" % ( self.__class__.__module__, self.__class__.__name__ ) )
Panlogism answered 30/12, 2008 at 20:12 Comment(5)
Are you sure self won't have a module attribute? I tried it and it seemed to have one.Elliott
self does have a module attribute.Footpoundsecond
Strange... >>> from datetime import date >>> d = date.today() >>> d.__module__ Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'datetime.date' object has no attribute 'module' >>> d.__class__.__module__ 'datetime' >>>Panlogism
Well, that got butchered; apparently you can't put code into a comment on a comment. Anyway, I looked at datetime to see if an instance had a module attribute and it doesn't look like it does. Maybe other classes do.Panlogism
@Steve: module is probably undefined for C-API instances. Not 100% on that one, but instances of user defined types appear to have it.Overripe

© 2022 - 2024 — McMap. All rights reserved.