Skip to main content

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

LevelNumeric ValueWhen to Use
DEBUG10Detailed diagnostic info
INFO20General informational messages
WARNING30Warning about potential problems
ERROR40Error occurred but app continues
CRITICAL50Serious 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 line
  • s (step): Step into function
  • c (continue): Continue execution
  • l (list): Show current code
  • p variable: Print variable value
  • q (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

  1. Add comprehensive logging to an existing project
  2. Create a custom logger with rotation
  3. Debug a complex function using pdb
  4. Implement error tracking with email notifications
  5. Build a logging decorator for timing functions :::