I am trying to setup generic logging in my Python library modules so that they use the logger configured in the calling module without having to hard code a logger name. I've seen plenty of examples using logging.basicConfig()
in the calling module and calling logging.debug()
in the library module, but it doesn't work when I configure my own StreamHandler. What am I doing wrong?
This is my calling module:
import logging, logging.handlers
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
consolehandler = logging.StreamHandler()
consoleformatter = logging.Formatter('[%(name)s] %(levelname)s %(message)s')
consolehandler.setFormatter(consoleformatter)
logger.addHandler(consolehandler)
import libmodule
def run():
logger.info("message from calling module")
libmodule.say("message from library module")
I've tried this in libmodule.py:
import logging
def say(msg):
logging.info(msg)
and this:
import logging
logger = logging.getLogger()
def say(msg):
logger.info(msg)
But in both cases when I call run(), I get this output:
[callingmodule] INFO message from calling module
but was expecting this:
[callingmodule] INFO message from calling module
[callingmodule] INFO message from library module
Python comes with a logging module in the standard library that provides a flexible framework for emitting log messages from Python programs. This module is widely used by libraries and is the first go-to point for most developers when it comes to logging.
Python provides a logging system as a part of its standard library, so you can quickly add logging to your application.
logger = logging.getLogger(__name__) This means that logger names track the package/module hierarchy, and it's intuitively obvious where events are logged just from the logger name. Sounds like good advice.
That's because in the first instance, you get a logger by name, and in the second, you just use getLogger()
, which returns the root logger. Which is not the same one, and doesn't have your custom stream handler installed.
The easier way to do this is to follow the guidance in the docs here:
'Multiple calls to getLogger() with the same name will always return a reference to the same Logger object.'
In other words, if you just use getLogger('my_common_name')
in both places, then both of them will automatically point to the same logger, even if you've customized it in one place.
Added: If you want to capture the logger from a parent, then you would do something like this in your library:
# In libmodule
_log = None
def initLogger(logger=None):
global _log
if logger != None:
_log = logger
else:
import logging
_log = logging.getLogger()
# Later in the module
def say(message):
_log.info(message)
then in your parent module:
# In the parent module
mylog = a logger i set up
import libmodule
libmodule.initLogger(mylog)
That should make them both point to the same logger.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With