Reputation: 2955
I am trying to beef up the logging in my Python scripts and I am grateful if could share best practices with me. For now I have created this little script (I should say that I run Python 3.4)
import logging
import io
import sys
def Streamhandler(stream, level, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"):
ch = logging.StreamHandler(stream)
ch.setLevel(level)
formatter = logging.Formatter(format)
ch.setFormatter(formatter)
return ch
# get the root logger
logger = logging.getLogger()
stream = io.StringIO()
logger.addHandler(Streamhandler(stream, logging.WARN))
stream_error = io.StringIO()
logger.addHandler(Streamhandler(stream_error, logging.ERROR))
logger.addHandler(Streamhandler(stream=sys.stdout, level=logging.DEBUG))
print(logger)
for h in logger.handlers:
print(h)
print(h.level)
# 'application' code # goes to the root logger!
logging.debug('debug message')
logging.info('info message')
logging.warning('warn message')
logging.error('error message')
logging.critical('critical message')
print(stream.getvalue())
print(stream_error.getvalue())
I have three handlers, 2 of them write into a io.StringIO (this seems to work). I need this to simplify testing but also to send logs via a HTTP email service. And then there is a Streamhandler for the console. However, logging.debug and logging.info messages are ignored on the console here despite setting the level explicitly low enough?!
Upvotes: 1
Views: 2057
Reputation: 77892
First, you didn't set the level on the logger itself:
logger.setLevel(logging.DEBUG)
Also, you define a logger
but do your calls on logging
- which will call on the root logger. Not that it will make any difference in your case since you didn't specify a name for your logger, so logging.getLogger()
returns the root logger.
wrt/ "best practices", it really depends on how "complex" your scripts are and of course on your logging needs.
For self-contained simple scripts with simple use cases (single known environment, no concurrent execution, simple logging to a file or stderr etc), a simple call to logging.basicConfig()
and direct calls to logging.whatever()
are usually good enough.
For anything more complex, it's better to use a distinct config file - either in ini
format or as Python dict (using logging.dictConfig
), split your script into distinct module(s) or package(s) each defining it's own named logger (with logger = logging.getLogger(__name__)
) and only keep your script itself as the "runner" for your code, ie: configure logging, import modules, parse command line args and call the main function - preferably in a try/except block as to properly log any unhandled exception before crashing.
Upvotes: 2
Reputation: 3981
A logger
has a threshold level too, you need to set it to DEBUG
first:
logger.setLevel(logging.DEBUG)
Upvotes: 1