Your first log messages

logging · Essentials · 8 min

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 full

Remember

  • 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.

Check yourself

  1. With no logging configuration, what does logging.info('x') print?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.python.org/3/howto/logging.html#a-simple-example