Debugging & Profiling
Logging
The logging module for structured event tracking — log levels, handlers, formatters, filters, and production-ready logging configuration.
Interview: Production debugging — proper logging is essential for diagnosing issues in deployed applications.
Python's logging module provides a flexible, configurable system for tracking events in applications. Unlike print(), logging supports severity levels, multiple output destinations, structured formatting, and can be configured without changing code. It's the standard for production application observability.
Log Levels
DEBUG(10) — detailed information for development/diagnosisINFO(20) — confirmation that things are working as expectedWARNING(30) — something unexpected happened, but the app still worksERROR(40) — a serious problem, some functionality failedCRITICAL(50) — the application may not be able to continue- Set the logger level to control the minimum severity that gets recorded
Core Components
- Logger: Entry point —
logging.getLogger("name")creates named loggers - Handler: Where logs go — StreamHandler (console), FileHandler, RotatingFileHandler
- Formatter: Log message format — timestamps, levels, module names
- Filter: Fine-grained control over which records pass through
Best Practices
- Use
logger = logging.getLogger(__name__)— module-level named loggers - Use
%sformatting in log calls —logger.info("User %s logged in", name) - Use
logger.exception()in except blocks — automatically includes the traceback - Configure logging once at application startup — don't configure in library code
- Use
RotatingFileHandlerorTimedRotatingFileHandlerto prevent log files from growing forever
Interview Insight
Logging replaces print() in production code. Use named loggers (__name__), appropriate log levels (DEBUG for development, INFO+ for production), and structured formatting. logger.exception() in except blocks automatically captures the full traceback — invaluable for debugging production issues.
Common Pitfall
Using f-strings in log calls: logger.info(f"User {name}"). This evaluates the f-string even if the log level would suppress it, wasting CPU. Use logger.info("User %s", name) instead — the string is only formatted if the log is actually emitted.
Use Cases
Application monitoring — tracking user actions, system events, errors
Production debugging — diagnosing issues from log files
Audit trails — recording security-relevant events (logins, data changes)
Performance monitoring — logging request durations and resource usage
Distributed systems — structured logging for centralized log aggregation
Common Mistakes
Using print() instead of logging — no levels, formatting, or output control
Using f-strings in log calls — always use % formatting for lazy evaluation
Not using logger.exception() in except blocks — loses the traceback
Configuring logging in library code — only configure in the application entry point
Not rotating log files — unbounded log files fill up disk space