-1

I am trying to build a logger logger_script.py for my python scripts that:

  • outputs a log file with customizable log level.
  • outputs a console output with customizable log level (not necessarily equal to the log file's one)
  • logs unhandled exceptions both to the log file and to the console

I achieved the first two points by following the answer to "https://stackoverflow.com/questions/29087297/is-there-a-way-to-change-the-filemode-for-a-logger-object-that-is-not-configured/29087645 ". I adapted it a to my needs and it now looks like:

import sys
import logging

def create_logger(log_filename, logfile_level, console_level):

    # create logger and file handler
    logger = logging.getLogger(__name__)
    logger.setLevel(logging.DEBUG)

    fh = logging.FileHandler(log_filename, mode='w')
    fh.setLevel(logfile_level)

    # create console handler with independent log level
    ch = logging.StreamHandler(stream=sys.stdout)
    ch.setLevel(console_level)

    formatter = logging.Formatter('[%(asctime)s] %(levelname)8s: %(message)s' +
                                  ' (%(filename)s:%(lineno)s)',
                                  datefmt='%m-%d, %H:%M:%S')
    fh.setFormatter(formatter)
    ch.setFormatter(formatter)

    if (logger.hasHandlers()): #clear pre-existing logs (?)
        logger.handlers.clear() 
        
    logger.addHandler(ch)
    logger.addHandler(fh)
    
    return logger

#create the logger: file log + console output
logger = create_logger("LogFile.log", logging.INFO, logging.WARNING)

#####  piece of code with handled exceptions:  #####
beta = 3

while beta > -3:
    try:
        2/beta
        logger.info("division successful".rjust(20))
    except ZeroDivisionError:
        logger.exception("ZeroDivisionError".rjust(20))    
    beta -= 1

##### piece of code with unhandled exception  ##### 
gamma = 1/0
    

However, when running a code with an unhandled exception (see last line), these do not get passed to the log file, only to the console.

I followed advices from Logging uncaught exceptions in Python and added the following snippet;

def handle_exception(exc_type, exc_value, exc_traceback):
    if issubclass(exc_type, KeyboardInterrupt):
        sys.__excepthook__(exc_type, exc_value, exc_traceback)
        return

    logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))

sys.excepthook = handle_exception

either before or after the logger creation lines, but it does not work in my case.

How can I make unhandled exception appear, together with their traceback message?

I would like to avoid encapsulating the whole code into a try: except statement.

  • "unhandled exception" needs to be handled to be logged - `except` it, log it, but just re-raise is afterwards – h4z3 Apr 29 '21 at 12:37

1 Answers1

0

I would like to avoid encapsulating the whole code into a try: except statement.

I'd recommend doing the whole code in def main() then - it would be already useful if you decide to reuse parts of your code so that no code gets executed when importing the file. :)

Then you can do a catch-all thing in if __name__== "__main__"::

if __name__ == "__main__":
    try:
        main()
    except Exception as e: 
        logger.exception("Program stopped because of a critical error.")
        raise

[That's literally how I do it in my own code. It doesn't need any tricks, I literally added it for unexpected exceptions happened so that I could debug later.]

raise re-raises the same error that was caught - so it's uncaught to the outside world. And .exception does the same thing as .error but includes the exception info on its own.

h4z3
  • 5,265
  • 1
  • 15
  • 29