Logging Capture and Formatting

Purpose

This subtopic addresses the need to **capture, control, and format logging output** generated during test execution. While the broader parent topic covers capturing all output streams (stdout, stderr, and logs), this subtopic specifically focuses on managing log messages emitted by Python’s `logging` module. It provides features to:

This allows tests to assert on log content, helps developers debug by viewing logs live or in reports, and integrates logging output seamlessly with pytest’s test lifecycle.

Functionality

Core Components

Log Formatting

Dynamic Log Level Control

Through the `caplog` fixture, tests can dynamically adjust logger levels to capture or suppress messages:

caplog.set_level("INFO", logger="my.module")
with caplog.at_level("DEBUG"):
    # code producing debug logs here

This facility restores original logger levels after test completion, ensuring no side effects leak between tests.

Live Logging to Terminal

The plugin supports "live logging," streaming logs to the terminal in real-time during test execution. This is handled by `_LiveLoggingStreamHandler`, which writes log messages with appropriate section headers and spacing, while temporarily disabling stdout/stderr capturing to avoid interference.

Log File Output

When configured, logs can be written to a file with separate format and level settings, enabling persistent log storage for test runs.

Relationship

This subtopic tightly integrates with its parent topic, **Output and Log Capture**, by specializing in the logging portion of output capturing. It complements the stdout/stderr capture subtopic by focusing on the structured log records and their formatting rather than raw byte streams.

The logging capture and formatting subtopic introduces advanced formatting features (color, timestamp precision, multi-line indentation) and dynamic logger level control, which are not covered by the more general output capturing mechanisms.


Code Snippets Illustrating Key Interactions

Accessing Captured Logs in Tests

def test_logging_example(caplog):
    logger = logging.getLogger("myapp")
    logger.info("Starting")
    logger.error("An error occurred")

    assert ("myapp", logging.INFO, "Starting") in caplog.record_tuples
    assert "An error occurred" in caplog.text

Setting Logger Level Temporarily

with caplog.at_level("DEBUG"):
    logging.getLogger("myapp").debug("Debug message")
    assert "Debug message" in caplog.text

LoggingPlugin Setup of Handlers and Formatters

self.caplog_handler = LogCaptureHandler()
self.caplog_handler.setFormatter(self.formatter)

self.log_file_handler = _FileHandler(log_file, mode=self.log_file_mode, encoding="UTF-8")
self.log_file_handler.setFormatter(file_formatter)

if self._log_cli_enabled():
    self.log_cli_handler = _LiveLoggingStreamHandler(terminal_reporter, capture_manager)
else:
    self.log_cli_handler = _LiveLoggingNullHandler()

Diagram: Log Capturing and Reporting Flow

sequenceDiagram
    participant Test as Test Code
    participant Logger as Python Logger
    participant LogHandler as LogCaptureHandler
    participant Caplog as caplog Fixture
    participant Plugin as LoggingPlugin
    participant Report as Test Report

    Test->>Logger: Emit log record
    Logger->>LogHandler: Handle log record (store & format)
    LogHandler->>Caplog: Store record & formatted text
    Note right of Caplog: Provides access via attributes and methods
    Plugin->>LogHandler: Add/Remove handler during test phases
    Test->>Plugin: pytest hooks trigger capturing setup/teardown
    Plugin->>Report: Add log sections (setup, call, teardown)
    Report->>User: Display logs in test report

This flowchart visualizes how log messages emitted during tests are intercepted by handlers registered by the plugin, stored and formatted, accessed via the `caplog` fixture, and attached to test reports for user inspection.


This logging capture and formatting feature ensures pytest users can flexibly control and inspect logging output in their tests with rich formatting and integration into the test lifecycle, enhancing test diagnostics and developer productivity.