Logging Instead of print
About 18 minutes
Why this matters
print is fine for a learner’s first program. Real programs use logging: messages come with a severity level, can be switched on or off without editing code, and can go to the screen, a file or a service.
The idea
import logging
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")
log = logging.getLogger("shop")
log.debug("cart contents: [...]") # hidden: below INFO
log.info("order 7 accepted") # INFO: order 7 accepted
log.warning("stock is low") # WARNING: stock is low
log.error("payment failed") # ERROR: payment failed
Levels, from quiet to loud: DEBUG, INFO, WARNING, ERROR, CRITICAL. A logger shows messages at or above its level.
Under the hood a logger creates messages, a handler decides where they go (StreamHandler(stream) writes to a stream) and a formatter decides how they look. Inside an except block, log.exception("...") also records the traceback.
Try it
Change level=logging.INFO to logging.DEBUG, then to logging.ERROR. Which messages appear each time?
Your turn
Write three functions:
make_logger(name, stream): return the logger calledname, at levelINFO, with one handler that writes tostreamin the formatLEVEL: message("%(levelname)s: %(message)s"). Setlogger.propagate = Falseso the root logger does not print it a second time. Calling the function again with the same name must replace the old handler, not add a second one.process_orders(orders, logger): each order is a dictionary like{"id": 3, "qty": 2}. A quantity of 0 or less logs a warningorder 3: bad quantity 0; otherwise log an info messageorder 3: ok. Return how many orders were fine.safe_parse(text, logger): returnint(text); if the text is not a whole number, log an errorcould not parse 'abc'(with!r) and returnNone.
Recap
- Use logging levels instead of
printso output can be filtered and redirected. - A logger makes messages, a handler picks the destination, a formatter picks the look.
log.exception(...)insideexceptrecords the traceback too.
Common mistakes
- Doing nothing and expecting INFO to appear. The default level is
WARNING; set a level. - Adding a handler every time a function runs, so each message prints several times.
- Logging secrets such as passwords or tokens.