Log only the slow calls
A service makes thousands of calls, so logging every one drowns the log. Time each call and write a WARNING only when it passes a limit. The fast call is logged at DEBUG, hidden at INFO level. isEnabledFor lets you skip costly work when a level is off. (The limit is printed instead of the measured time, so the output is the same on every run.)
The logging module records what your program is doing with a severity level, a source name and a format, and can send the records anywhere. It replaces scattered print calls with output you can filter, store and search.
Change the code and press Run (Ctrl+Enter). Predict what will happen first, then break it on purpose and read what changes. Your edits are saved and match the lesson page.
Ready for more? This phase has 7 hands-on exercises with automatic checks.
Practice questions
Write the code in the editor, run it, then open the model answer to compare.
Call logging.basicConfig so that INFO and above appear in the form LEVEL: message (the format string is "%(levelname)s: %(message)s"). Then log one info line and one error line from a logger called pipeline.
Write safe_divide(a, b) that returns a / b. When b is zero it must call logger.exception(...) with a short message and return None. Call it with (6, 3) and with (1, 0).
Make a logger jobs that writes DEBUG and above to a file jobs.log (use a FileHandler and setLevel(logging.DEBUG) on the logger). Log three messages, then read the file and print how many lines it has (it should print 3).
Explain it without notes
Name the five standard log levels in order and explain the default threshold.
Why use logging.getLogger(__name__) in every module rather than the root logger?
Why should you write logger.info("x=%s", x) instead of an f-string?
How do you record a caught exception with its traceback?
Expected output
ok
WARNING llm.client: generate was slow (limit 0.05 s)
ok
debug enabled: True
debug enabled: False