Skip to content

LoggingPlugin

LoggingPlugin

LoggingPlugin(verifier)

Bases: BasePlugin

Logging interception plugin.

Patches logging.Logger._log globally. Uses reference counting so nested sandboxes work correctly, following the SubprocessPlugin pattern.

Source code in src/bigfoot/plugins/logging_plugin.py
def __init__(self, verifier: "StrictVerifier") -> None:
    super().__init__(verifier)
    # FIFO queue for log mocks (per-plugin instance, per-verifier)
    self._mock_queue: deque[LogMockConfig] = deque()
    self._mock_consumed: list[LogMockConfig] = []
    self._sentinel = LogSentinel(self)

log property

log

Sentinel used as source argument in assert_interaction() for logging.

install

install()

No-op. Called to ensure plugin is registered before sandbox entry.

Access to any attribute of log_mock triggers plugin creation via _LoggingProxy.getattr. This method exists as a named no-op so tests that want the interceptor active without any mocks have an explicit API to call.

Source code in src/bigfoot/plugins/logging_plugin.py
def install(self) -> None:
    """No-op. Called to ensure plugin is registered before sandbox entry.

    Access to any attribute of log_mock triggers plugin creation via
    _LoggingProxy.__getattr__. This method exists as a named no-op so
    tests that want the interceptor active without any mocks have an
    explicit API to call.
    """

mock_log

mock_log(level, message, logger_name=None, *, required=True)

Register a FIFO log mock.

Calls are matched in registration order. Unlike subprocess.run, unmocked log calls are swallowed (fire-and-forget) and recorded on the timeline, requiring assertion at teardown.

Source code in src/bigfoot/plugins/logging_plugin.py
def mock_log(
    self,
    level: str,
    message: str,
    logger_name: str | None = None,
    *,
    required: bool = True,
) -> None:
    """Register a FIFO log mock.

    Calls are matched in registration order. Unlike subprocess.run,
    unmocked log calls are swallowed (fire-and-forget) and recorded
    on the timeline, requiring assertion at teardown.
    """
    self._mock_queue.append(
        LogMockConfig(
            level=level.upper(),
            message=message,
            logger_name=logger_name,
            required=required,
        )
    )

assert_log

assert_log(level, message, logger_name)

Assert the next log interaction with all 3 fields.

Source code in src/bigfoot/plugins/logging_plugin.py
def assert_log(
    self,
    level: str,
    message: str,
    logger_name: str,
) -> None:
    """Assert the next log interaction with all 3 fields."""
    self.verifier.assert_interaction(
        self._sentinel,
        level=level.upper(),
        message=message,
        logger_name=logger_name,
    )

assert_debug

assert_debug(message, logger_name)

Assert the next log interaction is a DEBUG message.

Source code in src/bigfoot/plugins/logging_plugin.py
def assert_debug(self, message: str, logger_name: str) -> None:
    """Assert the next log interaction is a DEBUG message."""
    self.assert_log("DEBUG", message, logger_name)

assert_info

assert_info(message, logger_name)

Assert the next log interaction is an INFO message.

Source code in src/bigfoot/plugins/logging_plugin.py
def assert_info(self, message: str, logger_name: str) -> None:
    """Assert the next log interaction is an INFO message."""
    self.assert_log("INFO", message, logger_name)

assert_warning

assert_warning(message, logger_name)

Assert the next log interaction is a WARNING message.

Source code in src/bigfoot/plugins/logging_plugin.py
def assert_warning(self, message: str, logger_name: str) -> None:
    """Assert the next log interaction is a WARNING message."""
    self.assert_log("WARNING", message, logger_name)

assert_error

assert_error(message, logger_name)

Assert the next log interaction is an ERROR message.

Source code in src/bigfoot/plugins/logging_plugin.py
def assert_error(self, message: str, logger_name: str) -> None:
    """Assert the next log interaction is an ERROR message."""
    self.assert_log("ERROR", message, logger_name)

assert_critical

assert_critical(message, logger_name)

Assert the next log interaction is a CRITICAL message.

Source code in src/bigfoot/plugins/logging_plugin.py
def assert_critical(self, message: str, logger_name: str) -> None:
    """Assert the next log interaction is a CRITICAL message."""
    self.assert_log("CRITICAL", message, logger_name)

activate

activate()

Reference-counted class-level patch installation.

Source code in src/bigfoot/plugins/logging_plugin.py
def activate(self) -> None:
    """Reference-counted class-level patch installation."""
    with LoggingPlugin._install_lock:
        if LoggingPlugin._install_count == 0:
            self._check_conflicts()
            self._install_patches()
        LoggingPlugin._install_count += 1