Python Logging · Exercises
Practical Python

Python Logging Exercises

4 exercises that build on the Python Logging lesson, from easy to hard. Each one is checked in your browser when you press Check. Stuck? Use the hint before peeking at the solution.

What this lesson covers: The logging module records messages from your program with a severity level, a source name and a destination you configure once, so you can turn detail up or down without editing your code. By the end you can configure logging with basicConfig, choose the right level, create named loggers, route messages to the screen or a file with handlers and formatters, log tracebacks with logger.exception, and avoid the default-level and duplicate-handler traps. You will practise: Configure the root logger; Predict which messages appear; Fix the silent, duplicating logger; Log while cleaning prices.

0 / 4 completed

Python Logging practice exercises

1. Configure the root logger

Write code Easy

Write configure(stream, level=logging.INFO) that configures the root logger with logging.basicConfig so it writes to stream, uses the level given, and formats lines as %(levelname)s:%(name)s:%(message)s. Use force=True so calling it twice works.

Your code
import io
import logging

def configure(stream, level=logging.INFO):
    # call logging.basicConfig with level, format, stream and force=True
    pass

out = io.StringIO()
configure(out)
logging.getLogger("demo").info("hello")
print(out.getvalue().strip())

2. Predict which messages appear

Predict the output Easy

Type exactly what this program prints. The logger threshold is WARNING (30) and the handler threshold is ERROR (40). Remember that both must allow a message.

Read this code
import logging
import sys

log = logging.getLogger("store")
log.handlers.clear()
log.propagate = False
log.setLevel(logging.WARNING)

handler = logging.StreamHandler(sys.stdout)
handler.setLevel(logging.ERROR)
handler.setFormatter(logging.Formatter("%(levelname)s %(message)s"))
log.addHandler(handler)

log.info("opened")
log.warning("low stock")
log.error("out of stock")
log.critical("database lost")
print(log.isEnabledFor(logging.INFO), log.isEnabledFor(logging.WARNING))

3. Fix the silent, duplicating logger

Fix the bug Medium

make_logger(stream) should return the logger named orders that writes LEVEL:message lines to stream and shows INFO messages. Right now info() messages are lost, and calling the function twice writes every message twice. Fix both problems so that each call gives a logger with exactly one handler.

Your code
import io
import logging

def make_logger(stream):
    log = logging.getLogger("orders")
    handler = logging.StreamHandler(stream)
    handler.setFormatter(logging.Formatter("%(levelname)s:%(message)s"))
    log.addHandler(handler)
    return log

out = io.StringIO()
make_logger(out).info("order 1 paid")
print(repr(out.getvalue()))

4. Log while cleaning prices

Write code Hard

Write load_prices(lines, log) that turns a list of strings into a list of floats. For each line: if it is not a number, call log.warning with the message template "skipping bad price %r" and the line as a separate argument; if the number is negative, call log.error with "negative price %s" and the number as an argument, and skip it. After the loop, call log.info with "loaded %d of %d prices" and the two counts as arguments. Return the list of valid prices. Pass values as logging arguments (no f-strings).

Your code
import logging

def load_prices(lines, log):
    prices = []
    # try float(line); warn about bad text, error on negatives, keep the rest
    # finally log how many of the lines were loaded
    return prices

log = logging.getLogger("prices")
print(load_prices(["4.5", "abc", "-2", "10"], log))

Next lessonPython Testing

More Python Logging examples · All Python exercises