A Python Logging Pattern

Posted by mwguy on Fri 06 March 2020
When writing command line utilities in python for almost any purpose. I almost
always want to control the level of verbosity in my project. To that end, I've
regularly found myself utilizing a combination of argparse and logging to create a command line flag to let me control verbosity
at runtime.

I thought it might be useful to some so I'm documenting it here:

import argparse
import logging

# This makes this work in a manner so that it only runs if
# It's been called on a command line. This allows me to have
# a quick CLI way to use an object or other thing I've defined
# in this file without having it run when I've imported the thing
# elsewhere

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    # Other Parser Bits here
    parser.add_argument("-v", "--verbose",
                        action='append_const',
                        help="Turn on Verbosity",
                        const=1, default=[])

    args = parser.parse_args()

    VERBOSE = len(args.verbose)

    if VERBOSE == 0:
        logging.basicConfig(level=logging.ERROR)

    elif VERBOSE == 1:
        logging.basicConfig(level=logging.WARNING)

    elif VERBOSE == 2:
        logging.basicConfig(level=logging.INFO)

    else:
        logging.basicConfig(level=logging.DEBUG)

    logger = logging.getLogger("my_program_name")
What this does is it allows you to specify additional -v's (eg -vv get's INFO level
logs and -vvv gets DEBUG level logs). This allows you to write your messages out in a
verbose fashion like so:
try:
   result = dangerousthing()
except Exception as wtf:
   logger.error("Shit fucked up : {}".format(wtf))
else:
   logger.debug("Did my dangerous thing and got : {}".format(result))
   logger.info("Danger Count : {}".format(len(result))
   if len(result) == 0:
       logger.warning("Dangerous thing had empty result, that's odd.")
By default you'd only see a message if dangerousthing() failed and threw an error. A use case
that fits the Unix style "Only say something if shit's fucked" workflow. But with the additional
levels of verbosity you can specify you can get a clearer and clearer picture. -v for example
would let you know if Dangerous thing had no results, which might be important later, while -vvv
very verbosely tell you all the data that dangerousthing() gave you.
I hope this helps you! I've found this to be a reasonably simple cookie cutter to get logging "handled"
for most simple cases. Best of luck!