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 :::