Logging from static methods
Asked Answered
D

3

16

In a class with few no static functions, I typically do logging like this:

class ClassA:

    def __init__(self):
        self._logger = logging.getLogger(self.__class__.__name__)

    def do_something(self):
        self._logger.info("Doing something")

    def do_something_else(self):
        self._logger.info("Doing something else.")

In a class with static methods I've been doing this:

class ClassB:

    _logger = logging.getLogger("ClassB")

    @staticmethod
    def do_something():
        ClassB._logger.info("Doing something")

    @staticmethod
    def do_something_else():
        ClassB._logger.info("Doing something else")

You could do this but it seems lame:

class ClassB:

    @staticmethod
    def do_something():
        logger = logging.getLogger("ClassB")
        logger.info("Doing something")

    @staticmethod
    def do_something_else():
        logger = logging.getLogger("ClassB")
        logger.info("Doing something else")

Is there a better pattern for logging from static methods?

Deciare answered 8/12, 2011 at 22:44 Comment(0)
R
11

You could turn them into class methods instead.

class ClassB(object):
    _logger = logging.getLogger("ClassB")

    @classmethod
    def do_something(cls):
         cls._logger.info("Doing something")

But note that when you derive from ClassB and call do_something, it will get a different logger since cls denotes the derived class rather than ClassB.

Roethke answered 8/12, 2011 at 22:49 Comment(1)
I actually like the idea that the logger name would show the name of the derived class. So I think I'll do it just like your example.Deciare
H
4

That pretty much does exhaust your options. After all, there are only three scopes accessible to a static method: the method scope, the class scope, and the module scope. And if you want to have the logger name match the class name, you will need at minimum one logger per class, so there's no point in storing them at the module scope when you might as well store them at the class scope (as your second example does).

Personally, I usually use a logger per module. But if I were doing individual class loggers, I would probably use your pattern #2, having a _logger variable in each class. It just seems the cleanest to me.

Hauptmann answered 8/12, 2011 at 22:49 Comment(3)
Thanks for confirming that there aren't really any other options. Wish I could mark two answers (yours and larsmans) but I upvoted your helpful response.Deciare
And +1 from me for the per-module logger; that's actually what I tend to do.Roethke
This article suggests if creating logging instances at module level and loading a configuration from file, that you set diable_existing_loggers to False, as without this only loggers specifically listed in the config will remain active (unless you import your module after the config is loaded).Anastatius
L
1

late to the answer party but would like to add one more point.

If you have a more complicated logger initialization (init file paths to log to, etc) then do you can do it by creating logger_init outside of the class.

def init_logger():
    logger = logging.getLogger('general_logger')
    # do other logger setup like
    # setup logger handlers,
    # set formatters,
    # set logging levels, etc
    return logger

then, init your logger from static class

 class MyClass(object):
     _logger = init_logger()

     @classmethod
     def do_something(cls):
         cls._logger.info("doing something")

happy logging!

Legacy answered 4/6, 2013 at 22:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.