Logs can be filtered, redirected and timestamped without touching the code that emits them; prints can't.
The logging module gives each message a level saying how important it is: DEBUG, INFO, WARNING, ERROR and CRITICAL, in increasing severity.
The quickest start is logging.basicConfig(...), called once at program start. It attaches a handler that writes to standard error, with the threshold and format you choose:
logging.basicConfig(level=logging.INFO,
format="%(asctime)s %(levelname)s %(message)s")Messages below the threshold are dropped. With no configuration at all, only WARNING and above appear: that's why logging.info("hi") seems to do nothing at first. Note that the module-level functions (logging.info, logging.warning...) call basicConfig() for you if the root logger has no handlers yet.
Why bother instead of print?
- You can turn detail up or down with one setting instead of deleting prints.
- Output goes to stderr, a file or a log service without code changes.
- Each line can carry a timestamp, level, module and line number for free.
basicConfig does nothing if the root logger already has handlers, which surprises people in notebooks, test runners, and after an early logging.warning(...) call; pass force=True to replace the existing setup. Other handy arguments are filename= to log to a file and datefmt= for the timestamp format.
Example
import logging, sys
logging.warning("before config") # WARNING:root:before config (auto basicConfig)
logging.basicConfig(
level=logging.INFO,
format="%(levelname)-8s %(message)s",
stream=sys.stdout,
force=True, # replace any earlier configuration
)
logging.debug("hidden: below INFO")
logging.info("server started on port %d", 8000)
logging.error("disk almost full")
# INFO server started on port 8000
# ERROR disk almost fullRemember
- Five levels: DEBUG < INFO < WARNING < ERROR < CRITICAL
- Call logging.basicConfig once at startup to set level and format
- Unconfigured logging shows only WARNING and above
Watch out for
- Calling basicConfig after something else configured logging; it silently does nothing unless force=True.