Explain Codes LogoExplain Codes Logo

Log exception with traceback in Python

python
logging
exception-handling
best-practices
Anton ShumikhinbyAnton Shumikhin·Dec 21, 2024
TLDR

Efficiently log exceptions in Python using the built-in logging module. In the except segment of a try/except block, call logging.exception() to log the exception and its traceback automatically.

import logging logging.basicConfig(level=logging.ERROR) # Defining the logging level as ERROR try: problematic_operation() # Here be dragons...replace with your code except Exception: logging.exception("Exception occurred") # Logs the exception

This succinct piece of code captures and logs any thrown exception and its traceback, then stores the log to your specified logging handler.

Setting up the logger

The logging module is pretty awesome, but you can make it even cooler by configuring it to your requirements. Use logging.basicConfig to specify a log file and logging level. And if you're Sherlock Holmes level of detective, set the level to DEBUG.

logging.basicConfig(filename='app.log', filemode='w', level=logging.DEBUG) # Now even ants can't hide

This config will set up a log file named app.log, overwrite the previous logs (filemode='w'), and capture all the DEBUG and above level messages.

Catch & log the Uncaught

You might encounter some sneaky uncaught exceptions, especially when multithreading. That's when sys.excepthook comes in, as the superhero to catch all those uncaught exceptions.

import sys def handle_exception(exc_type, exc_value, exc_traceback): logging.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback)) # No exception can hide now sys.excepthook = handle_exception

Use a try-except at your thread's entry point to trap exceptions, or learn some magic tricks like InstallThreadExcepthook if your standard excepthook isn't playing nice with threads.

Threading and custom handlers

Custom logging handlers

If the default logging feels too mainstream for you, try custom handlers for a tailor-made logging experience.

class CustomHandler(logging.Handler): # Here be dragons, i.e., code for custom handler logger.addHandler(CustomHandler()) # Custom handler in action

Threading issues and solutions

Multithreading can be like a house party - things can get messy. Overriding the run method within a Thread allows you to do some cleanup:

class MyThread(threading.Thread): def run(self): try: super().run() # Let's get the party started! except Exception: logger.exception("It's clean-up time in thread '%s'", self.name) raise

Full traceback logging

Use exc_info with logging.error for extra details, like when you need to capture full traceback outside an exception block.

logging.error("I didn't see this coming!", exc_info=True) # Provides the full traceback

Tracebacks with context

Keep your traceback logs readable by including a message with logging.exception. This message acts as a context clue that will help in debugging.

except Exception as e: logging.exception("Needle in the haystack found: %s", e) # Provides the exception

Formatting for Future Analysis

Structure your logs to include date, time, and severity level. Future you will thank present you when analyzing the logs later.

logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', # This is like your log's ID datefmt='%m/%d/%Y %I:%M:%S %p', # Because we like to know "when" level=logging.DEBUG # For the love of details )

Best Practices for Ultimate Logging

Following the best practices in logging like proper exception propagation with raise can improve your Python applications' error handling. Be sure your logging strategies adapt to the Python version you're using, ensuring compatibility with Python 3.6 and above.