
Chapter Outline
Chapter 6: Debugging and Logging
Debugging is an essential part of software development. Almost every piece of software that is written has errors or various kinds. It is the programmer's job to identify and fix pieces of code that make some software malfunction. This process is called debugging.
Most programming languages offer a debugger that allow the programmer to set breakpoints, to halt program execution at certain points within the program, and inspect the current state of the program variables. This allows the programmer to identify whether some variables may have incorrect values at certain point of the execution.
The debugger also allows the programmer to step though the code line by line, or step over, or out of certain sections of the code to ensure that the code execution order is correct. The Python Debugger is the pdb.
6.1 Debugging with pdb and IDE Tools
The Python Debugger, or pdb lets you pause program execution and step through code interactively.
pythonimport pdbdef debug_demo():a = 10b = 0pdb.set_trace()return a / bdebug_demo()
The program pauses after the set_trace() function is executed:
bash> /.../pdb_demo.py(7)debug_demo()-> return a / b(Pdb)
Code stepping using PDB
n– next lines– step into functionp var– print variableq– quit debugger
IDE Debugging
Most modern IDEs (e.g., PyCharm, VS Code) natively support:
- Breakpoints
- Step over/into
- Variable watching
- Call stack inspection
Instead of running the python program you need to debug the program.
6.2 Logging in Python
Python’s built-in logging module provides a flexible framework for emitting log messages from your code. It's far superior to using print() statements for:
- Debugging
- Tracking errors
- Auditing system events
- Application monitoring in production
Basic Logging Example
pythonimport logginglogging.basicConfig(level=logging.INFO)logging.info("App started")
Output:
INFO:root:App started
Log Levels and Usage
| Level | Use Case Example |
|---|---|
DEBUG | Internal state for developers |
INFO | Successful operations |
WARNING | Recoverable problems or deprecations |
ERROR | Serious problems that need attention |
CRITICAL | Application is unusable |
Changing Output Format
pythonlogging.basicConfig(level=logging.INFO,format='%(asctime)s - %(levelname)s - %(message)s')
Output:
bash2023-07-17 16:21:10,200 - INFO - App started
Writing Logs to a File
pythonlogging.basicConfig(filename='app.log',level=logging.DEBUG,format='%(asctime)s - %(levelname)s - %(message)s')
Logging in Functions
pythondef divide(a, b):if b == 0:logging.error("Attempted to divide by zero")return Nonereturn a / bdivide(10, 0)
Logging Exceptions
pythontry:1 / 0except ZeroDivisionError:logging.exception("Something went wrong!")
Output:
bash2023-07-17 01:26:40,389 - ERROR - Something went wrong!Traceback (most recent call last):File "/.../basic_logging.py", line 11, in <module>1 / 0~~^~~ZeroDivisionError: division by zero
6.3 Refactoring the Calculator: Fault-Tolerant Version
Here’s a refactored CLI calculator with logging and error handling.
calculator.py1import logging23logging.basicConfig(4 filename='calculator.log',5 level=logging.INFO,6 format='%(asctime)s - %(levelname)s - %(message)s'7)89def add(a, b): return a + b10def subtract(a, b): return a - b11def multiply(a, b): return a * b1213def divide(a, b):14 if b == 0:15 logging.error("Division by zero attempted.")16 raise ValueError("Cannot divide by zero.")17 return a / b1819def main():20 print("CLI Calculator (With Logging and Exception Handling)")21 try:22 operation = input("Choose operation (add/subtract/multiply/divide): ").strip().lower()23 num1 = float(input("Enter first number: "))24 num2 = float(input("Enter second number: "))2526 if operation == "add":27 result = add(num1, num2)28 elif operation == "subtract":29 result = subtract(num1, num2)30 elif operation == "multiply":31 result = multiply(num1, num2)32 elif operation == "divide":33 result = divide(num1, num2)34 else:35 logging.warning(f"Invalid operation: {operation}")36 return3738 logging.info(f"{operation}({num1}, {num2}) = {result}")39 print(f"Result: {result}")4041 except ValueError as ve:42 logging.error(f"Value error: {ve}")43 print(f"Value error: {ve}")44 except Exception as e:45 logging.critical(f"Unexpected error: {e}", exc_info=True)46 print("An unexpected error occurred.")4748if __name__ == "__main__":49 main()
Check your understanding
Test your knowledge of Debugging and Logging in Python