1.Logging levels, handlers, and formatters
The stdlib `logging` module replaces `print("HERE")` with a system that has a severity level, can route output to multiple destinations (handlers), and can format each destination differently — all without touching the calling code.
Key features
- Level order, low to high: DEBUG (10) < INFO (20) < WARNING (30) < ERROR (40) < CRITICAL (50)
- A logger AND each of its handlers has its own level — a record must clear both to be emitted
- logging.getLogger(__name__) gives each module its own named logger in one shared hierarchy
- A formatter controls the TEXT shape of a record (timestamp, level, message) — it does not filter anything
- logging.config.dictConfig() configures loggers/handlers/formatters from one data structure, not scattered setup calls
The five standard levels
- logger.debug(...) — gate 1: logger.setLevel(DEBUG) — passes
- handler.setLevel(WARNING) — gate 2: DEBUG < WARNING — dropped here
- Formatter — only shapes text — never filters what reaches it
- Output — only WARNING and ERROR records actually appear
Command
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler()
handler.setLevel(logging.WARNING) # handler filters independently
handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s'))
logger.addHandler(handler)A record needs to clear the logger's level AND the handler's level — a formatter only changes how it looks, never whether it appears.