I am trying to figure out the best practice for using logging in python across multiple modules. I see here: http://docs.python.org/2/howto/logging#logging-from-multiple-modules on how to use the root logger to log across multiple modules. As the link points out though, you can't tell where in your application your messages come from as they all show name "root."
It seems to me there are two options (this assumes my modules are NOT in a package structure, but are just a bunch of modules in the same folder):
1) Use the root logger as in the example, but change the log formatting to include the filename:
# myapp.py
import logging
import mylib
def main():
logging.basicConfig(format='%(asctime)s %(filename)s %(levelname)s: %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p', level=logging.INFO) #filename='myapp.log',
logging.info('Started')
mylib.do_something()
logging.info('Finished')
if __name__ == '__main__':
main()
#mylib.py
import logging
def do_something():
logging.info('Do something')
In [4]: import myapp
In [5]: myapp.main()
03/06/2014 12:22:07 PM myapp.py INFO: Started
03/06/2014 12:22:07 PM mylib.py INFO: Do something
03/06/2014 12:22:07 PM myapp.py INFO: Finished
2) Use a root logger in the main app but a named logger in the submodules, and use 'name' instead of 'filename' in the log format:
# myapp.py
import logging
import mylib
def main():
#logging.basicConfig(format='%(asctime)s %(filename)s %(levelname)s: %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p', level=logging.INFO) #filename='myapp.log',
logging.basicConfig(format='%(asctime)s %(name)s %(levelname)s: %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p', level=logging.INFO) #filename='myapp.log',
logging.info('Started')
mylib.do_something()
logging.info('Finished')
if __name__ == '__main__':
main()
#mylib.py
import logging
def do_something():
#logging.info('Do something')
logger = logging.getLogger(__name__)
logger.info('Do something')
In [3]: import myapp
In [4]: myapp.main()
03/06/2014 12:27:29 PM root INFO: Started
03/06/2014 12:27:29 PM mylib INFO: Do something
03/06/2014 12:27:29 PM root INFO: Finished
On top of the hierarchy is the root logger, which can be accessed via logging. root. This logger is called when methods like logging. debug() is used. By default, the root log level is WARN, so every log with lower level (for example via logging.info("info") ) will be ignored.
Logging is a means of tracking events that happen when some software runs. Logging is important for software developing, debugging, and running. If you don't have any logging record and your program crashes, there are very few chances that you detect the cause of the problem.
To start logging using the Python logging module, the factory function logging. getLogger(name) is typically executed. The getLogger() function accepts a single argument - the logger's name. It returns a reference to a logger instance with the specified name if provided, or root if not.
Vinay Sajip (maintainer of the logging module) makes a recommendation here which is similar to your option #2, except that you could use a named logger everywhere, even in myapp:
import logging
import mylib
logger = logging.getLogger(__name__)
def main():
logging.basicConfig(format='%(asctime)s %(module)s %(levelname)s: %(message)s',
datefmt='%m/%d/%Y %I:%M:%S %p', level=logging.INFO)
logger.info('Started')
mylib.do_something()
logger.info('Finished')
if __name__ == '__main__':
main()
which yields
03/06/2014 12:59:25 PM myapp INFO: Started
03/06/2014 12:59:25 PM mylib INFO: Do something
03/06/2014 12:59:25 PM myapp INFO: Finished
Note that if you use %(module)s
instead of %(name)s
, then you get myapp
where before you got root
or myapp.py
, or __main__
.
This symmetry -- of always using logger
-- may be especially useful if myapp
is sometimes called as a script and sometimes imported as a module.
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