Reputation: 28659
I am trying to enable logging in a module using a logger configured in an executable.
According to the documentation,
A good convention to use when naming loggers is to use a module-level logger, in each module which uses logging, named as follows:
logger = logging.getLogger(__name__)
I have followed that, creating a module-level logger in my foo
module:
module foo
:
import logging
logger = logging.getLogger(__name__)
class Foo():
def __init__(self):
logger.info("hello world")
Again, according to the documentation
Creating loggers, handlers, and formatters explicitly using Python code that calls the configuration methods listed above.
In my executable I import foo
and set up the logger, basically a copy-paste of the example int he documentation link above:
executable:
import logging
from foo import foo
if __name__ == '__main__':
# create logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# create console handler and set level to debug
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
# add ch to logger
logger.addHandler(ch)
logger.info('start')
f = foo.Foo()
I see the log statement from my executable, but my module based logger doesn't work:
start No handlers could be found for logger "foo.foo"
What am I doing wrong?
Edit:
I tried using basicConfig
in my executable, which, according to the documentation does the following:
Does basic configuration for the logging system by creating a
StreamHandler
with a defaultFormatter
and adding it to the root logger
executable:
import logging
from foo import foo
if __name__ == '__main__':
# create logger
logger = logging.getLogger(__name__)
... (same as above) ...
logging.basicConfig(level=logging.DEBUG)
logger.info('start')
f = foo.Foo()
And now logging in my module works!
What confuses me is that in my previous example is I am creating a StreamHandler
and adding it to the root logger.
So I guess my question should be:
What is basicConfig
doing which explicit calls to the logging configuration api isn't?
Upvotes: 1
Views: 6214
Reputation: 5107
You need to configure the root logger before you import other modules which will use it as a factory to make their local logger instances.
Change your executable to configure the root logger before getting child loggers
import logging
# root logger must be configured before loading child modules which use it
#logging.basicConfig(level=logging.DEBUG)
root_logger = logging.getLogger()
# create console handler and set level to debug
console = logging.StreamHandler()
console.setLevel(logging.DEBUG)
console_format = '%(asctime)15s %(levelname)-8s [%(filename)s:%(lineno)s %(funcName)s] %(message)s'
console_formatter = logging.Formatter(console_format)
console.setFormatter(console_formatter)
root_logger.addHandler(console)
from foo import foo
# create module specific logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
if __name__ == '__main__':
logger.info('start')
f = foo.Foo()
Then your child module can be like this:
import logging
# create module specific logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
class Foo():
def __init__(self):
logger.info("hello world")
Upvotes: 0
Reputation: 11280
You need to assign handlers to the Foo
module logger as well, since they use different logger objects:
import logging
logger = logging.getLogger(__name__)
sh = logging.StreamHandler()
logger.setLevel(logging.DEBUG)
logger.addHandler(sh)
class Foo():
def __init__(self):
logger.info("hello world")
==================== RESTART: C:\Python27\tests\test2.py ====================
start
hello world
Or you can use basicConfig
function from the logging module to change the defaults of the root logger and new ones:
if __name__ == '__main__':
sh = logging.StreamHandler()
logging.basicConfig(level=logging.DEBUG)
root = logging.getLogger(__name__)
root.info('start')
f = Foo()
A great resource for logging - Python Logging Cookbook
Update according to the new question:
Does basic configuration for the logging system by creating a StreamHandler with a default Formatter and adding it to the root logger. The functions debug(), info(), warning(), error() and critical() will call basicConfig() automatically if no handlers are defined for the root logger.
In your code, each module has it's own logger object. You need to specify handlers and configurations for each. The basic config basically sets some defaults for you - in case you don't explicity state them. All logger objects are derived from the root logger, so you change the defaults for the root logger and then new loggers derives it.
Upvotes: 1