Logging module instead of print in Python (a concise guide to logging)

  • 2020-04-02 13:51:38
  • OfStack

Replace the print? What's wrong with print?

Print is probably the first thing anyone learning Python will touch. Its main function is to print a message to the console like this:


print 'Hello, logging!'

Print is also the most common thing most people use to debug their own programs, just like writing js using console.log. Many new and even experienced Python learners use print to debug their code.

For example, this is a small program that I wrote to output the Fibonacci sequence. Let's take a look at its code:


# -*- coding: utf-8 -*-
"""
A simple fibonacci program
"""
import argparse parser = argparse.ArgumentParser(description='I print fibonacci sequence')
parser.add_argument('-s', '--start', type=int, dest='start',
                    help='Start of the sequence', required=True)
parser.add_argument('-e', '--end', type=int, dest='end',
                    help='End of the sequence', required=True) def infinite_fib():
    a, b = 0, 1
    yield a
    yield b
    while True:
        #print 'Before caculation: a, b = %s, %s' % (a, b)
        a, b = b, a + b
        #print 'After caculation: a, b = %s, %s' % (a, b)
        yield b
def fib(start, end):
    for cur in infinite_fib():
        #print 'cur: %s, start: %s, end: %s' % (cur, start, end)
        if cur > end:
            return
        if cur >= start:
            #print 'Returning result %s' % cur
            yield cur def main():
    args = parser.parse_args()
    for n in fib(args.start, args.end):
        print n, if __name__ == '__main__':
    main()


Here's how it works:


$ python fib.py  -s 1 -e 100
1 1 2 3 5 8 13 21 34 55 89
$ python fib.py  -s 100 -e 1000
144 233 377 610 987

There is no problem, the program correctly completed its function. But wait, what happened to that bunch of commented out print statements in the program?

It turns out that this is the output that I used to DEBUG when I wrote this little program. After I finished the program, I naturally commented out these prints. So let's see what happens if I turn this print statement on?


$ python fib.py  -s 1 -e 100
cur: 0, start: 1, end: 100
cur: 1, start: 1, end: 100
Returning result 1
1 Before caculation: a, b = 0, 1
After caculation: a, b = 1, 1
cur: 1, start: 1, end: 100
... ...
... ...
( Countless output messages )

As you can see, all the calculations are printed out.

Add print when you write, and delete/comment out print when you submit your code, so why do we have to put up with this hassle? Let's introduce our main character logging, which is almost designed for this use.

Better yet, use logging modules

Logging is a built-in logging module in Python that makes it easy to process and manage log output. The simplest use of logging module is to use basicConfig method to configure logging directly:


import logging # Set default level for DEBUG
# Set up the log The format of the
logging.basicConfig(
    level=logging.DEBUG,
    format="[%(asctime)s] %(name)s:%(levelname)s: %(message)s"
) # record log
logging.debug(...)
logging.info(...)
logging.warn(...)
logging.error(...)
logging.critical(...)


Once logging is configured, ' 'logging.debug' 'is used to replace all print statements. We'll see the output:


[2014-03-18 15:17:45,216] root:cur: 0, start: 1, end: 100
[2014-03-18 15:17:45,216] root:DEBUG: cur: 1, start: 1, end: 100
[2014-03-18 15:17:45,216] root:DEBUG: Returning result 1
[2014-03-18 15:17:45,216] root:DEBUG: Before caculation: a, b = 0, 1
... ...

Use a real logger

The basicConfig method described above will work for you in most scenarios, but basicConfig has one big drawback.

Calling basicConfig adds a handler to the root logger so that when your program works with other logging third-party modules, the logger behavior of the third-party module will be affected. This is determined by the inheritance nature of the logger.

So we need to use a real logger:


import logging # Use a name for fib the logger
logger = logging.getLogger('fib') # Set up the logger the level for DEBUG
logger.setLevel(logging.DEBUG) # Create an output log to the console StreamHandler
hdr = logging.StreamHandler()
formatter = logging.Formatter('[%(asctime)s] %(name)s:%(levelname)s: %(message)s')
hdr.setFormatter(formatter) # to logger add handler
logger.addHandler(hdr)

This lets you use logger for log output. The downside is that the amount of code is much larger than basicConfig. So I suggest that if it is a very simple script, you can directly use basicConfig, if it is a slightly larger project, I recommend that you carefully configure logger.

Dynamically control all the output of the script

After using the logging module, we can easily control the output of the program by modifying the log level of the logger. For example, we can add a -v parameter to our Fibonacci sequence to control the printing of all debugging information.


# Add receive a verbose parameter
parser.add_argument('-v', '--verbose', action='store_true', dest='verbose',
                    help='Enable debug info') # judge verbose
if args.verbose:
    logger.setLevel(logging.DEBUG)
else:
    logger.setLevel(logging.ERROR)

This way, by default, our applet doesn't print debug information, and only prints extra debug information when '-v/--verbose' is passed in, like this:


$ python fib.py  -s 1 -e 100
1 1 2 3 5 8 13 21 34 55 89 $ python fib.py  -s 1 -e 100 -v
[2014-03-18 15:17:45,216] fib:DEBUG: cur: 0, start: 1, end: 100
[2014-03-18 15:17:45,216] fib:DEBUG: cur: 1, start: 1, end: 100
[2014-03-18 15:17:45,216] fib:DEBUG: Returning result 1
[2014-03-18 15:17:45,216] fib:DEBUG: Before caculation: a, b = 0, 1
... ...

As you can see, when you need to print DEBUG information and when you need to turn it off after logging, it's incredibly easy.

So replace the print in your script with logging!

read

These are just some of the simplest functions of logging module. As an alternative to print, logging module also has many powerful and useful functions, such as reading configuration from file, various Handlers, and so on. It is recommended that you read the official logging documentation:

1. (link: http://docs.python.org/2/library/logging.html)
2. (link: http://docs.python.org/2/howto/logging.html)

Finally, the complete code of Fibonacci sequence program using logging module is attached:


# -*- coding: utf-8 -*-
"""
A simple fibonacci program
"""
import argparse parser = argparse.ArgumentParser(description='I print fibonacci sequence')
parser.add_argument('-s', '--start', type=int, dest='start',
                    help='Start of the sequence', required=True)
parser.add_argument('-e', '--end', type=int, dest='end',
                    help='End of the sequence', required=True)
parser.add_argument('-v', '--verbose', action='store_true', dest='verbose',
                    help='Enable debug info') import logging logger = logging.getLogger('fib')
logger.setLevel(logging.DEBUG) hdr = logging.StreamHandler()
formatter = logging.Formatter('[%(asctime)s] %(name)s:%(levelname)s: %(message)s')
hdr.setFormatter(formatter) logger.addHandler(hdr)
def infinite_fib():
    a, b = 0, 1
    yield a
    yield b
    while True:
        logger.debug('Before caculation: a, b = %s, %s' % (a, b))
        a, b = b, a + b
        logger.debug('After caculation: a, b = %s, %s' % (a, b))
        yield b
def fib(start, end):
    for cur in infinite_fib():
        logger.debug('cur: %s, start: %s, end: %s' % (cur, start, end))
        if cur > end:
            return
        if cur >= start:
            logger.debug('Returning result %s' % cur)
            yield cur def main():
    args = parser.parse_args()
    if args.verbose:
        logger.setLevel(logging.DEBUG)
    else:
        logger.setLevel(logging.ERROR)     for n in fib(args.start, args.end):
        print n, if __name__ == '__main__':
    main()


Related articles: