Install & Compatibility
Where this runs
tested against v1.2 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.920 runs
installs and imports cleanly · install 0.0s · import 0.654s · 31.3MB
glibcpy 3.10–3.920 runs
installs and imports cleanly · install 2.8s · import 0.569s · 32MB
30MB installed
● package 30MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
StructuredLogCapture
✓ from pytest_structlog import StructuredLogCapture
Used for type hinting the 'log' fixture in tests. The fixture itself is automatically available.
get_logger
✓ import structlog; logger = structlog.get_logger()
This is how you obtain a logger in `structlog` for the code under test.
This quickstart demonstrates how to use the `log` fixture provided by pytest-structlog. It shows how to capture structlog events from a function under test and then assert their presence and content using `log.events`, `log.has()`, and `log.count()`.
import structlog
from pytest_structlog import StructuredLogCapture
# your_lib.py (or code under test)
logger = structlog.get_logger()
def do_something():
logger.info("Starting process", task_id="abc-123")
for i in range(2):
logger.debug("Step complete", step=i)
logger.warning("Process finished with warnings", result="partial", count=2)
# test_your_lib.py
def test_do_something(log: StructuredLogCapture):
assert len(log.events) == 0 # No logs captured initially
do_something()
# Assert on specific event counts
assert log.count("Starting process", level="info") == 1
assert log.count("Step complete", level="debug") == 2
# Assert on individual events with context
assert log.has("Starting process", task_id="abc-123")
assert log.has("Step complete", step=0)
assert log.has("Step complete", step=1)
assert log.has("Process finished with warnings", result="partial", count=2, level="warning")
# You can also inspect all captured events directly
expected_events = [
log.info("Starting process", task_id="abc-123"),
log.debug("Step complete", step=0),
log.debug("Step complete", step=1),
log.warning("Process finished with warnings", result="partial", count=2)
]
assert log.events == expected_events
Debug
Known issues
breakingSupport for Python 3.7 was dropped in version 1.1. Projects running on Python 3.7 will need to use an older version of `pytest-structlog`.fixUpgrade to Python >=3.8 or pin `pytest-structlog<1.1` in your project's dependencies.
affects: >=1.1
gotchaPrior to v0.4, `pytest-structlog` would reset structlog's defaults, which could interfere with custom `structlog.configure()` setups. While this behavior was reverted, complex structlog configurations (e.g., custom processors) might still require explicit management to avoid conflicts with the plugin's default behavior.fixFor complete control, add a `structlog.configure()` call directly in your `conftest.py` and use `--structlog-explicit` (or set `structlog_explicit = true` in `pytest.ini`) to disable automatic processor selection by the plugin.
affects: All versions, but particularly relevant for custom configurations.
gotchaThe command-line options `--structlog-keep` and `--structlog-evict` are mutually exclusive. Specifying both will result in an error.fixChoose either `--structlog-keep` to retain specific processors or `--structlog-evict` to remove them, but do not use both in the same pytest invocation or configuration.
affects: All versions supporting these options (>=1.0).
gotchaBy default, pytest captures standard output and error, which can hide `structlog` messages printed to the console during test runs, making it seem like no logs are being generated.fixTo see `structlog` output during tests, run `pytest` with the `-s` flag (e.g., `pytest -s`) or configure `capture = no` in your `pytest.ini` file.
affects: All versions.
Errors
Common errors & fixes
ValueError: I/O operation on closed file (when running pytest)
This error can occur when `structlog`'s configuration conflicts with pytest's default capture mechanisms, especially if you are manually configuring `logging.config.dictConfig` with specific handlers or formatters that interfere with `_pytest.capture`.
fixReview your `structlog` and standard library logging configurations in `conftest.py` or `pytest.ini`. Try simplifying the logging setup during tests or investigate specific handlers/processors that might be closing I/O streams prematurely. Sometimes, disabling complex logging configuration in tests or using `pytest -s` can help diagnose the root cause.
pytest does not find tests / No logs captured by 'log' fixture
`structlog` configuration might be too aggressive or incorrectly set up to capture logs within the pytest environment, preventing `pytest-structlog` from hooking into the logging pipeline correctly.
fixEnsure that `pytest-structlog` is correctly installed and that your `structlog.configure()` call in your application does not prematurely finalize the processor chain in a way that bypasses the plugin's hooks. Verify that the `log` fixture is correctly injected into your test function signature (e.g., `def test_something(log: StructuredLogCapture):`). If using advanced `structlog` configuration, consider using `--structlog-explicit` with your own `structlog.configure()` in `conftest.py`.
Upgrade
Version history
1.2latest on PyPI · released Sep 10, 2025
Audit
Dependencies
pytestrequiredRequired as a pytest plugin for test execution and fixture management.
structlogrequiredThe core library for structured logging that this plugin asserts against.