I am trying to understand the python logging, and I have this:
Main.py:
import logging
from Foo import Foo
logging.basicConfig(level=logging.DEBUG)
fh_formatter = logging.Formatter('[%(asctime)s : %(levelname)s : %(name)s] : %(message)s')
file_handler = logging.FileHandler('logger.log', mode='w')
file_handler.setFormatter(fh_formatter)
file_handler.setLevel(logging.DEBUG)
sh_formatter = logging.Formatter('%(message)s')
stream_handler = logging.StreamHandler()
stream_handler.setFormatter(sh_formatter)
stream_handler.setLevel(logging.DEBUG)
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
logger.addHandler(file_handler)
logger.addHandler(stream_handler)
logger.info('Running main')
Foo().print_foo()
Foo.py
import logging
from Bar import Bar
logger = logging.getLogger(__name__)
class Foo():
def print_foo(self):
Bar().print_bar()
logger.info('Inside Foo.foo')
Bar.py:
import logging
logger = logging.getLogger(__name__)
class Bar():
def print_bar(self):
logger.info('Inside Bar.bar')
When I run the code, on the console I see this output:
Running main
INFO:__main__:Running main
INFO:Bar:Inside Bar.bar
INFO:Foo:Inside Foo.foo
But when I check the logger.log
, I see only one line
[2019-03-23 18:46:01,276 : INFO : __main__] : Running main
How can I make it so that I see all the lines in both the places? Do I need to set a file handler and stream handler for each logger in each file? If I have a python project, and I want to have a single log file along with console output, what is the right way to do this?
The problem is on this line in Foo and Bar:
logger = logging.getLogger(__name__)
Note that you only reset the logging handler in Main.py
, with the logger name of __name__
, which resolved to "__main__"
as you can see in the output. When you get the logger from Foo.py
, your logger name is "Foo"
and hence everything you set to "__main__"
is not applied.
What you want to do: Change the __name__
part. For example, your app is called fubar
then you do this in Main.py
:
logger = logging.getLogger("fubar")
and in Foo.py
, as a submodule in the app, do this:
logger = logging.getLogger("fubar.Foo")
Or you can even use the same name if you wish. This way, the handler assigned at higher level will pass on to sub-levels.