15

I'm trying to use Python's logging module, and have questions on the best way to use it.

I define several classes, want to write logs and be able to set the level of all of them at the same time. I tried :

  • to use the same logger everywhere. But my classes are used by a framework, I don't have a single entrypoint where I could define a main logger. If so, how should I create it and add handlers ?
  • to use one logger per file. Should I create it as a class attribute, and adding handlers only the first time the class is instantiated ? Or put it with the imports before the class definition ? This tutorial told me not to, but I don't really get why.

Thanks for any hints. I've found lots of docs on the basic way to use a logger, but not much on how to use it in classes.

EDIT: I don't think it's a duplicate of the link below. The accepted answer explains how to load the config in a main program, and then use it in all the modules. But what if I don't have a main program ? Where do I define it ?

MeanStreet
  • 1,217
  • 1
  • 15
  • 33
  • Can't you create it where your classes are defined? And like you proposed in question #2, as a singleton? – HelloWorld May 17 '18 at 12:28
  • Have you read e.g. https://docs.python.org/3/howto/logging.html#configuring-logging-for-a-library? – jonrsharpe May 17 '18 at 12:30
  • @seb-mtl Yeah I could, but it seems heavy because I have to put that same code to get the same logger in every class. Is it really the good practice ? – MeanStreet May 17 '18 at 12:32
  • @jonrsharpe yes, but this explains how to let the user configure the logger. Here, the user is the framework and won't configure it, but I still want it – MeanStreet May 17 '18 at 12:35
  • @akshat I don't think it's a duplicate. The accepted answer explains how to load the config in a main program, and then use it in all the modules. But what if I don't have a main program ? Where do I define it ? – MeanStreet May 17 '18 at 12:48
  • @Mean-Street, check other answers, which are not main program based. – akshat May 17 '18 at 12:50

1 Answers1

48

If you create logger objects in separate files, but with the same name. They will share all the attributes. In fact, they are the same logger. The logging module also allow the creation of logger objects in a hierarchical order. For example, a logger with name spam.mod2 is a sub logger of spam in which it takes on all of spam's attributes, but can also be customized.

To put it into concrete example. I am going to create a simple project which has 2 modules: mod1 and mod2. A common module setup_logger is used to create a single logger. Finally, I have a main module, which drives the whole system.

The setup_logger module will create a new logger object and name it spam. The code can be simple as listed, or as complex as you want.

# setup_logger.py
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger('spam')

Next, mod1 being lazy, just reuse that logger object:

# mod1.py
from setup_logger import logger

class Class1(object):
    def do_something(self):
        logger.info('Class1: doing something')

mod2 creates its own logger object, but still need to import setup_logger so that the spam logger is created. mod2 creates a sub logger by naming it spam.mod2:

# mod2.py
import logging
import setup_logger

# mod2 creates its own logger, as a sub logger to 'spam'
logger = logging.getLogger('spam.mod2')

class Class2:
    def do_something(self):
        logger.info('Class2: doing something')

Finally, main will put all of them together:

# main.py
import mod1
import mod2


if __name__ == '__main__':
    object1 = mod1.Class1()
    object1.do_something()

    object2 = mod2.Class2()
    object2.do_something()

Output:

INFO:spam:Class1: doing something
INFO:spam.mod2:Class2: doing something
Hai Vu
  • 37,849
  • 11
  • 66
  • 93
  • Thanks. But if I define handlers to my logger in your `setup_logger.py`, and then import this several times (in each module), the handlers will be created each time the file is imported, right ? Isn't it a problem ? – MeanStreet May 17 '18 at 13:54
  • The way Python works is the imported code only get executed once, no mater how many imports. Try it out and see for yourself. – Hai Vu May 17 '18 at 15:17
  • 1
    The problem here is when `main.py` is invoked `mod1` gets imported which causes `setup_logger` to eventually be invoked before an instance of the class is ever instantiated. This is quite unflexible. One potential issue is how do you specify where log files go through a config file? In this setup before a config file can even be read the logger gets created. – alex Aug 28 '20 at 17:31
  • 1
    @HaiVu thank you very much for this answer, it has helped me immensefully! – deppep Sep 29 '20 at 17:56