pytest caplog not capturing logs: how to fix
Shows how to make pytest's caplog fixture capture INFO and DEBUG logs by setting the capture level, targeting the right logger name, and handling libraries that configure logging themselves. Use when caplog.text is empty or missing records while the code under test definitely logs. Not for live log output during runs, subprocess logs, or print() capture.
TL;DR
Call caplog.set_level(logging.INFO) (or the level you need) at the start of the test, then assert on caplog.records or caplog.text. The caplog handler listens at WARNING by default, so anything logged below that never reaches the fixture, which is the cause in most cases.
Problem
A test uses the caplog fixture but caplog.text is empty or missing records even though the code under test calls logger.info(...) or similar.
Steps
- Set the capture level explicitly as the first line of the test:
import logging
def test_logs_something(caplog):
with caplog.at_level(logging.INFO):
run_the_code()
assert "expected message" in caplog.text (caplog.at_level is a context manager; caplog.set_level outside it works too.) Expected: caplog.text now contains the logged message.
- If records are still missing, check the logger name your code uses and set the level on it:
with caplog.at_level(logging.DEBUG, logger="myapp.worker"):
run_the_code() Expected: records from that named logger appear in caplog.records.
- If a library configures logging itself (dictConfig or basicConfig at import), its handlers may swallow records before they propagate. Move the
caplog.set_levelcall to after the import of the module under test, or clear pre-existing handlers in a fixture.
Expected: after moving the level call past the import and config, records appear.
- Confirm propagation is not disabled: the logger your code uses must propagate to the root logger where caplog listens. If the library sets
propagate = False,caplog.at_level(..., logger="that.name")adds the handler directly to the named logger instead.
Expected: caplog.records is non-empty for that logger.
When to use
caplog.textempty while the code definitely logs.- INFO or DEBUG logs missing but WARNING logs appear.
- Third-party library logs not showing up in tests.
When not to use
- You want live log output during the run (use
-o log_cli=trueinstead). - Logs from subprocesses (caplog only sees the test process).
- You are testing
print()output (usecapsys).
Tool compatibility
- pytest 8.x built-in
caplogfixture; theat_levelcontext manager is available since pytest 3.4. - Standard library
logging; no plugins needed.
Variant phrasings
caplog.text is empty in pytest
Almost always the level: default capture is WARNING. Set it lower as above.
caplog not capturing logger.info messages
Same fix; also verify the logger name matches the one your code writes to.
Why it happens
caplog works by adding a handler to the root logger, but that handler and the logger levels default to WARNING. logger.info() calls are filtered before they ever reach the handler, so nothing is captured.
Edge cases
logging.config.dictConfigwithdisable_existing_loggers: Truecan detach pytest's handler; set levels after the config runs.- Logs emitted at import time (module top level) happen before caplog exists; move the logging call into a function or perform the import inside the test.
caplogandlog_cliare independent; one showing output does not mean the other captured it.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_xa8lvy2rpw391nentMkGew
Maintainer review
No maintainer verification is recorded for this version.
This records the version a maintainer checked. It does not assert that the version is the latest upstream release.