I am trying to start using logging in python and have read several blogs. One issue that is causing confusion for me is whether to create the logger per function or per module. In this Blog: Good logging practice in Python it is recommended to get a logger per function. For example:
import logging
def foo():
logger = logging.getLogger(__name__)
logger.info('Hi, foo')
class Bar(object):
def __init__(self, logger=None):
self.logger = logger or logging.getLogger(__name__)
def bar(self):
self.logger.info('Hi, bar')
The reasoning given is that
The logging.fileConfig and logging.dictConfig disables existing loggers by default. So, those setting in file will not be applied to your logger. It’s better to get the logger when you need it. It’s cheap to create or get a logger.
The recommended way I read everywhere else is like as shown below. The blog states that this approach "looks harmless, but actually, there is a pitfall"
.
import logging
logger = logging.getLogger(__name__)
def foo():
logger.info('Hi, foo')
class Bar(object):
def bar(self):
logger.info('Hi, bar')
I find the former approach to be tedious as I would have to remember to get the logger in each function. Additionally getting the logger in each function is surely more expensive than once per module. Is the author of the blog advocating a non-issue? Would following logging best practices avoid this issue?
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 has a built-in module logging which allows writing status messages to a file or any other output streams. The file can contain the information on which part of the code is executed and what problems have been arisen.
I would agree with you; getting logger in each and every function you use creates too much unnecessary cognitive overhead, to say the least.
The author of the blog is right about the fact that you should be careful to properly initialize (configure) your logger(s) before using them.
But the approach he suggests makes sense only in the case you have no control over your application loading and the application entry point (which usually you do).
To avoid premature (implicit) creation of loggers that happens with a first call to any of the message logging functions (like logging.info()
, logging.error()
, etc.) if a root logger hasn't been configured beforehand, simply make sure you configure your logger before logging.
Initializing the logger from the main thread before starting other threads is also recommended in Python docs.
Python's logging tutorial (basic and advanced) can serve you as a reference, but for a more concise overview, have a look at the logging section of The Hitchhiker's Guide to Python.
Have a look at this modified example from Python's logging tutorial:
# myapp.py
import logging
import mylib
# get the fully-qualified logger (here: `root.__main__`)
logger = logging.getLogger(__name__)
def main():
logging.basicConfig(format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s',
level=logging.DEBUG)
# note the `logger` from above is now properly configured
logger.debug("started")
mylib.something()
if __name__ == "__main__":
main()
And
# mylib.py
import logging
# get the fully-qualified logger (here: `root.mylib`)
logger = logging.getLogger(__name__)
def something():
logger.info("something")
Producing this on stdout
(note the correct name
):
$ python myapp.py
2017-07-12 21:15:53,334 __main__ DEBUG started
2017-07-12 21:15:53,334 mylib INFO something
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