Applications often require structured logging to track events, errors, and operational details. Python’s built-in logging module provides a flexible framework for emitting log mesages from applications. It supports multiple severity levels: CRITICAL, ERROR, WARNING, INFO, and DEBUG, in descending order of severity.
By default, the root logger only outputs messages at WARNING level or higher:
import logging
logging.debug("Debugging detail")
logging.info("General information")
logging.warning("Potential issue detected")
logging.error("An error occurred")
logging.critical("Critical system failure")
This produces:
WARNING:root:Potential issue detected
ERROR:root:An error occurred
CRITICAL:root:Critical system failure
Customizing Log Behavior
The basicConfig() method allows quick setup of logging parameters such as output destination, format, and minimum severity level:
import logging
logging.basicConfig(
filename='app.log',
level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(message)s',
datefmt='%Y-%m-%d'
)
logging.info("Application started")
logging.debug("Internal state check")
logging.warning("Deprecated API usage")
logging.error("Failed to connect to service")
logging.critical("Database unavailable")
This writes all messages (including DEBUG) to app.log with timestamps and source location.
Key parameters for basicConfig():
filename: directs logs to a file.filemode: specifies file opening mode ('a'for appeend,'w'for overwrite).format: defines message structure using placeholders.datefmt: customizes timestamp appearance.level: sets the threshold for the root logger.stream: sends output to a stream likesys.stdout; ignored iffilenameis set.
Common format specifiers include:
%(levelname)s: log level name (e.g.,ERROR)%(asctime)s: human-readable timestamp%(filename)sand%(lineno)d: source file and line number%(message)s: the actual log content
Advanced Configuration with Logger, Handler, and Formatter
For fine-grained control, use explicit components:
- Logger: entry point for logging calls.
- Handler: determines where logs are sent (console, file, network, etc.).
- Formatter: specifies the layout of log records.
- Filter: optionally restricts which records get emitted.
Example: simultaneous output to console (for warnings+) and file (for info+):
import logging
# Create logger
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
# Console handler (shows WARNING and above)
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.WARNING)
# File handler (records INFO and above)
file_handler = logging.FileHandler('access.log')
file_handler.setLevel(logging.INFO)
# Shared formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
console_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)
# Attach handlers
logger.addHandler(console_handler)
logger.addHandler(file_handler)
# Log messages
logger.debug("This won't appear on console")
logger.info("User logged in") # appears only in file
logger.warning("Disk space low") # appears in both
logger.error("Connection timeout")
logger.critical("System shutdown initiated")
Console output:
2019-12-30 23:25:24,047 - root - WARNING - Disk space low
2019-12-30 23:25:24,047 - root - ERROR - Connection timeout
2019-12-30 23:25:24,047 - root - CRITICAL - System shutdown initiated
File access.log contains all messages from INFO upward, including the "User logged in" entry.