Logging exceptions

logging · Practical · 9 min

An error log without a traceback is the hardest kind of bug report to act on.

Inside an except block, log.exception("message") logs at ERROR and appends the current exception's traceback. It's equivalent to log.error("message", exc_info=True).

Use exc_info=True with other levels when the failure isn't really an error, for example a retried call: log.warning("retrying", exc_info=True). You can also pass an exception instance: exc_info=err.

Guidelines:

  • Call log.exception only inside an except block; elsewhere there is no current exception and you get NoneType: None as the "traceback".
  • Log or re-raise, not both at every layer, or a single failure appears five times. Log where you handle the error (for example the top-level request handler).
  • Include identifiers in the message: log.exception("charge failed for order %s", order_id).

stack_info=True adds the current call stack (not an exception) to a record, useful for "who called this deprecated function?". stacklevel=2 attributes the record's funcName and lineno to the caller, which is what you want inside logging helper functions.

Exception chains (raise ... from err) are rendered in full, the same as an uncaught exception.

Example

import logging, sys
logging.basicConfig(stream=sys.stdout, format="%(levelname)s %(message)s")
log = logging.getLogger("billing")

def charge(order_id, amount):
    try:
        return 100 / amount
    except ZeroDivisionError:
        log.exception("charge failed for order %s", order_id)
        return None

charge("A-17", 0)
# ERROR charge failed for order A-17
# Traceback (most recent call last):
#   File "...", line 7, in charge
#     return 100 / amount
# ZeroDivisionError: division by zero

Remember

  • log.exception() = log.error() plus the current traceback
  • exc_info=True attaches a traceback at any level
  • Log an error once, where it is handled

Watch out for

  • Logging and re-raising at every layer, so one failure produces many identical tracebacks.

Check yourself

  1. What is the difference between log.exception('x') and log.error('x')?

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

Official docs: docs.python.org/3/library/logging.html#logging.Logger.exception

Builds on

Unlocks

Nothing builds on this yet.