Skip to content

Logging

To debug the code, you need to collect information and analyze it after execution. This section briefly introduces the logging module. The logging module is a standard Python module used to record diagnostic messages in a log file.

Simple configurarion

The following is a simple code example that shows how to use the logging module.

import logging
logging.basicConfig(
    filename  = 'debug.log',      # Log output file
    level     = logging.INFO,   # Output level
)

list_n = ['a',0, 1, 2, 'b']
for entry in list_n:
        print("The entry is", entry)
        logging.info(f' computation for {entry} started')
        r = 1/int(entry)
        logging.debug(f' computation is done for {entry}')
logger.info(f'Process id Done')

logging.basicConfig is a one-time configuration at the beginning. Later, we'll show how you can change the configuration. There are different logging levels: DEBUG, ERROR, WARNING, INFO, and CRITICAL. By choosing a level, you can filter messages, such as sending INFO and WARNING to sys.stdout, INFO, WARNING, and ERROR (and above) to sys.stderr, and the rest to a file named app.log.

Logging Configuration

Let use try-except statement

import sys
import logging
# create a logger with 'test_application'
logger = logging.getLogger('test_application')
logger.setLevel(logging.DEBUG)
# create file handler which logs even debug messages
fh = logging.FileHandler('file.log')
fh.setLevel(logging.DEBUG)
# create console handler with a higher log level
ch = logging.StreamHandler()
ch.setLevel(logging.ERROR)
fh.setLevel(logging.DEBUG)
# create formatter and add it to the handlers
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
ch.setFormatter(formatter)
# add the handlers to the logger
logger.addHandler(fh)
logger.addHandler(ch)

list_n = ['a',0, 1, 2, 'b']
for entry in list_n:
    try:
        print("The entry is", entry)
        r = 1/int(entry)
        logger.info(f' computation is done for {entry}')
    except Exception as e:
        print(f'Reason: Oops!, {e.__class__} occurred.')
        logger.warning(f' Could not compute for {entry}')
        logger.debug(f'Reason: Oops!, {e.__class__} occurred.')
    finally: 
        logger.info(f'Next entry')
logger.info(f'Process id Done')

Most programs use logging.getLogger(__name__) instead of specifying a name directly. We can rewrite the function as follows:

# main.py
import sys
import logging

list_n = ['a',0, 1, 2, 'b']

def reciptocal(list_n):
    for entry in list_n:
        try:
            print("The entry is", entry)
            r = 1/int(entry)
            logger.info(f' computation is done for {entry}')
        except Exception as e:
            print(f'Reason: Oops!, {e.__class__} occurred.')
            logger.warning(f' Could not compute for {entry}')
            logger.debug(f'Reason: Oops!, {e.__class__} occurred.')
        finally: 
            logger.info(f'Next entry')
    logger.info(f'Process id Done')


if __name__ == '__main__':
    # create a logger with 'test_application'
    logger = logging.getLogger(__name__)
    logger.setLevel(logging.DEBUG)
    # create file handler which logs even debug messages
    fh = logging.FileHandler('file.log')
    fh.setLevel(logging.DEBUG)
    # create console handler with a higher log level
    ch = logging.StreamHandler()
    ch.setLevel(logging.ERROR)
    fh.setLevel(logging.DEBUG)
    # create formatter and add it to the handlers
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    fh.setFormatter(formatter)
    ch.setFormatter(formatter)
    # add the handlers to the logger
    logger.addHandler(fh)
    logger.addHandler(ch)
    reciptocal(list_n)