Logging
Levels
  1. UNSET
  2. DEBUG, logging.debug()
  3. INFO, logging.info()
  4. WARNING, default level, only events of this level and above will be tracked
    • warnings.warn(), in library code if the issue is avoidable and the client application should be modified to eliminate the warning
    • logging.warning(), if there is nothing the client application can do about the situation, but the event should still be noted
  5. ERROR
    • Report suppression of an error without raising an exception
    • logging.error(), logging.exception()
  6. CRITICAL, logging.critical()
#WARNING is defalut level
import logging

logging.warning('Watch out!')  # will print a message to the console
logging.info('I told you so')  # will not print anything
			
import logging
logging.basicConfig(level=logging.DEBUG) # adjust level

logging.warning('Watch out!') # will print
logging.info('I told you so') # will print
			
Logging into file
import logging

logging.basicConfig(filename='log.txt', level=logging.DEBUG)

logging.warning('Watch out!')
logging.info('I told you so')
			
Multiple modules
# l2.py
import logging

def do_something():
    logging.info('Logging in lib ...');
			
# l1.py
import logging
import l2

def main():
    logging.basicConfig(filename='log.txt', level=logging.INFO)

    logging.warning('Watch out!')
    logging.info('I told you so')

    l2.do_something()

if __name__ == '__main__':
    main()
			
Logging format
import logging

logging.basicConfig(format='[%(levelname)s] (%(threadName)-10s) %(name)s %(asctime)s : %(message)s', filename='log.txt', level=logging.INFO)

logging.warning('Watch out!')
logging.info('I told you so')
			
[WARNING] (MainThread) root 2023-07-06 06:21:26,437 : Watch out!
[INFO] (MainThread) root 2023-07-06 06:21:26,437 : I told you so
            
Logging Objects
  • Logger, Expose the interface that application code directly uses
  • Handler, Send the log records (created by loggers) to the appropriate destination
  • Filter, Determining which log records to output
  • Formatter, Specify the layout of log records in the final output
  • LogRecord, instances are created automatically by the Logger every time something is logged
  • #WARNING is defalut level
    import logging
    
    class UserRunningProgramFilter(logging.Filter):
        def filter(self, record):
            print(record.module, record.name, record.pathname, record.getMessage())
            if record.name != 'root': # returns True to log it or False to discard it
                return True
    
    def get_logger():
        # create a logger
        logger = logging.getLogger()
        logger.setLevel(logging.DEBUG) # set up logging level
    
        # create handler
        handler = logging.FileHandler('log.txt', mode='a', encoding=None, delay=False)
    
        # create formater
        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    
        handler.addFilter(UserRunningProgramFilter())
        handler.setFormatter(formatter) # set up format for handler
        logger.addHandler(handler) # add handler for logger
    
        return logger
    
    logger = get_logger()
    
    def main():
    
        logger.warning('Watch out!')
        logger.info('I told you so')
    
        logger.info('End ...')
    
    if __name__ == '__main__':
        main()
                
    Rotating Log Files
  • Create rotating log files
  • Output logging into a new log file each time logging some messages
  • import logging
    import logging.handlers
    
    logger = logging.getLogger()
    logger.setLevel(logging.DEBUG)
    
    handler = logging.handlers.RotatingFileHandler(
        'log.txt',
        maxBytes=2,
        backupCount=3, # create 4 log rotating log files
    )
    logger.addHandler(handler)
    
    # Log some messages
    for i in range(10):
        logger.debug('i = %d' % i)
                
    The Logging Tree
  • Logger instances are configured in a tree structure, based on their names
  • root has no name
  • If a logger does not have any handlers, the message is handed to its parent for processing
  • l1.py
    #WARNING is defalut level
    import logging
    import l2
    from package.l3 import do_something
    
    def get_logger():
        # create a logger
        logger = logging.getLogger()
        logger.setLevel(logging.DEBUG) # set up logging level
    
        # create handler
        handler = logging.FileHandler('log.txt', mode='a', encoding=None, delay=False)
    
        # create formater
        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        handler.setFormatter(formatter) # set up format for handler
        logger.addHandler(handler) # add handler for logger
    
        return logger
    
    logger = get_logger()
    
    def main():
    
        logger.warning('Watch out!')
        logger.info('I told you so')
    
        l2.do_something()
        do_something()
    
        logger.info('End ...')
    
    if __name__ == '__main__':
        main()
    			
    l2.py
    import logging
    
    logger = logging.getLogger('l2')
    
    def do_something():
        logger.info('Do Something ...')
    			
    __init__.py
    # empty
    			
    l3.py
    import logging
    
    logger = logging.getLogger('package.l3')
    
    def do_something():
        logger.info('Do Something ...')
    			
    log.txt
    2023-07-06 06:36:24,954 - root - WARNING - Watch out!
    2023-07-06 06:36:24,954 - root - INFO - I told you so
    2023-07-06 06:36:24,954 - l2 - INFO - Do Something ...
    2023-07-06 06:36:24,955 - package.l3 - INFO - Do Something ...
    2023-07-06 06:36:24,955 - root - INFO - End ...
    			
    Integration with the warnings Module
  • Integrates warning into logging using the WARNING level
  • import logging
    import warnings
    
    logging.basicConfig(
        filename='log.txt',
        level=logging.INFO,
    )
    
    # output warning on screen
    warnings.warn('This warning is not sent to the logs')
    
    # send warning information to logging
    logging.captureWarnings(True)
    
    # output warning to logging file
    warnings.warn('This warning is sent to the logs')
    warnings.warn('End ...')
                
    Reference