Skip to content

Commit

Permalink
Apply capture_logs to initialized bound loggers (#412)
Browse files Browse the repository at this point in the history
Fixes #408
  • Loading branch information
fabianbuechler authored Apr 23, 2022
1 parent dcccf49 commit 881d841
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 5 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ So please make sure to **always** properly configure your applications.
[#401](https://github.com/hynek/structlog/pull/401)
- `structlog.PrintLogger` -- that is used by default -- now uses `print()` for printing, making it a better citizen for interactive terminal applications.
[#399](https://github.com/hynek/structlog/pull/399)
- `structlog.testing.capture_logs` now works for already initialized bound loggers.
[#408](https://github.com/hynek/structlog/pull/412)


### Fixed
Expand Down
16 changes: 13 additions & 3 deletions src/structlog/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,22 @@ def capture_logs() -> Generator[List[EventDict], None, None]:
.. versionadded:: 20.1.0
"""
cap = LogCapture()
old_processors = get_config()["processors"]
# Modify `_Configuration.default_processors` set via `configure` but always
# keep the list instance intact to not break references held by bound
# loggers.
processors = get_config()["processors"]
old_processors = processors.copy()
try:
configure(processors=[cap])
# clear processors list and use LogCapture for testing
processors.clear()
processors.append(cap)
configure(processors=processors)
yield cap.entries
finally:
configure(processors=old_processors)
# remove LogCapture and restore original processors
processors.clear()
processors.extend(old_processors)
configure(processors=processors)


class ReturnLogger:
Expand Down
30 changes: 28 additions & 2 deletions tests/test_testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
CapturedCall,
CapturingLogger,
CapturingLoggerFactory,
LogCapture,
ReturnLogger,
ReturnLoggerFactory,
)
Expand Down Expand Up @@ -46,11 +47,16 @@ def test_restores_processors_on_success(self):
exit.
"""
orig_procs = self.get_active_procs()
assert len(orig_procs) > 1

with testing.capture_logs():
assert orig_procs is not self.get_active_procs()
modified_procs = self.get_active_procs()
assert len(modified_procs) == 1
assert isinstance(modified_procs[0], LogCapture)

assert orig_procs is self.get_active_procs()
restored_procs = self.get_active_procs()
assert orig_procs is restored_procs
assert len(restored_procs) > 1

def test_restores_processors_on_error(self):
"""
Expand All @@ -64,6 +70,26 @@ def test_restores_processors_on_error(self):

assert orig_procs is self.get_active_procs()

def test_captures_bound_logers(self):
"""
Even logs from already bound loggers are captured and their processors
restored on exit.
"""
logger = get_logger("bound").bind(foo="bar")
logger.info("ensure logger is bound")

with testing.capture_logs() as logs:
logger.info("hello", answer=42)

assert logs == [
{
"event": "hello",
"answer": 42,
"foo": "bar",
"log_level": "info",
}
]


class TestReturnLogger:
# @pytest.mark.parametrize("method", stdlib_log_methods)
Expand Down

0 comments on commit 881d841

Please sign in to comment.