Module 31 - Logging & Debugging
Logging helps track events during program execution, while debugging helps identify and fix errors.
1. Logging Basics
import logging
# Configure logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
# Log messages
logging.debug('Debug message')
logging.info('Info message')
logging.warning('Warning message')
logging.error('Error message')
logging.critical('Critical message')
2. Logging Levels
| Level | Numeric Value | When to Use |
|---|---|---|
| DEBUG | 10 | Detailed diagnostic info |
| INFO | 20 | General informational messages |
| WARNING | 30 | Warning about potential problems |
| ERROR | 40 | Error occurred but app continues |
| CRITICAL | 50 | Serious error, app may crash |
3. Logging to File
import logging
logging.basicConfig(
filename='app.log',
filemode='a', # append mode
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logging.info('Application started')
logging.error('An error occurred')
4. Logger Objects
import logging
# Create logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# File handler
file_handler = logging.FileHandler('app.log')
file_handler.setLevel(logging.ERROR)
# Console handler
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)
# Formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)
# Add handlers
logger.addHandler(file_handler)
logger.addHandler(console_handler)
# Use logger
logger.debug('Debug message')
logger.info('Info message')
logger.error('Error message')
5. Debugging with pdb
Basic Usage
import pdb
def calculate(a, b):
pdb.set_trace() # Debugger stops here
result = a + b
return result
calculate(5, 3)
pdb Commands
n(next): Execute next lines(step): Step into functionc(continue): Continue executionl(list): Show current codep variable: Print variable valueq(quit): Exit debugger
6. Using breakpoint()
def process_data(data):
breakpoint() # Python 3.7+
result = [x * 2 for x in data]
return result
process_data([1, 2, 3])
7. Exception Logging
import logging
logging.basicConfig(level=logging.ERROR)
try:
result = 10 / 0
except ZeroDivisionError:
logging.exception("Division by zero occurred")
8. Practical Example
import logging
from datetime import datetime
class Application:
def __init__(self):
self.logger = logging.getLogger(__name__)
self.logger.setLevel(logging.DEBUG)
# File handler
fh = logging.FileHandler(f'app_{datetime.now():%Y%m%d}.log')
fh.setLevel(logging.INFO)
# Console handler
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
# Formatter
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
fh.setFormatter(formatter)
ch.setFormatter(formatter)
self.logger.addHandler(fh)
self.logger.addHandler(ch)
def run(self):
self.logger.info('Application started')
try:
# Application logic
self.logger.debug('Processing data...')
result = self.process()
self.logger.info(f'Result: {result}')
except Exception as e:
self.logger.exception(f'Error occurred: {e}')
finally:
self.logger.info('Application ended')
def process(self):
return 42
if __name__ == '__main__':
app = Application()
app.run()
Summary
✅ Use logging instead of print statements
✅ Different levels for different severity
✅ Log to files for production
✅ pdb for interactive debugging
✅ Log exceptions with context
Next Steps
In Module 32, you'll learn:
- Performance optimization
- Profiling code
- Memory management
- Speed optimization techniques
Practice Exercises
- Add comprehensive logging to an existing project
- Create a custom logger with rotation
- Debug a complex function using pdb
- Implement error tracking with email notifications
- Build a logging decorator for timing functions :::