Skip to content

Testing Guide

LogXide provides testing utilities to capture and assert on log output, similar to pytest's caplog fixture.

Quick Start (pytest)

LogXide includes a built-in pytest plugin that provides a caplog fixture automatically:

from logxide import logging

def test_logging(caplog):
    logger = logging.getLogger("test")
    logger.addHandler(caplog.handler)
    logger.info("Hello!")

    assert "Hello!" in caplog.text
    assert ("test", 20, "Hello!") in caplog.record_tuples

Auto-registration

The caplog fixture is auto-registered via pyproject.toml entry point when logxide is installed. No conftest.py setup required.

LogCaptureFixture

For more control, use LogCaptureFixture directly:

import pytest
from logxide import logging
from logxide.testing import LogCaptureFixture

@pytest.fixture
def caplog_logxide():
    fixture = LogCaptureFixture()
    fixture.set_level(logging.DEBUG)
    yield fixture
    fixture.clear()

def test_example(caplog_logxide):
    logger = logging.getLogger("test")
    logger.addHandler(caplog_logxide.handler)
    logger.info("Hello!")

    assert "Hello!" in caplog_logxide.text
    assert ("test", 20, "Hello!") in caplog_logxide.record_tuples
    assert caplog_logxide.messages == ["Hello!"]

Properties

Property Type Description
.handler MemoryHandler The underlying Rust-backed memory handler
.records list[LogRecord] All captured log records
.text str All messages as newline-separated string
.record_tuples list[tuple[str, int, str]] (logger_name, level, message) tuples
.messages list[str] Message strings only

Methods

Method Description
set_level(level) Set minimum capture level (int or str)
at_level(level) Context manager to temporarily change capture level
clear() Clear all captured records

capture_logs Context Manager

For tests that don't use pytest fixtures, use the capture_logs context manager:

from logxide import logging
from logxide.testing import capture_logs

def test_without_fixture():
    logger = logging.getLogger("test")

    with capture_logs(logging.INFO) as captured:
        logger.addHandler(captured.handler)
        logger.info("test message")
        assert "test message" in captured.text

MemoryHandler

Underneath both LogCaptureFixture and capture_logs, the MemoryHandler stores log records in Rust-native memory:

from logxide import MemoryHandler, logging

logger = logging.getLogger("test")
handler = MemoryHandler()
logger.addHandler(handler)

logger.info("Hello!")

handler.records         # [LogRecord(...)]
handler.text            # "INFO test Hello!\n"
handler.record_tuples   # [("test", 20, "Hello!")]
handler.clear()         # Reset for next test

Performance

MemoryHandler stores records in Rust's Vec<LogRecord> behind a Mutex, making it significantly faster than Python-based alternatives for high-volume capture.


Optimization Regression Suite

tests/test_optimizations.py is a tracked regression suite that covers the Step 1–4 optimizations shipped in v0.1.19. It runs alongside the standard test suite.

The suite covers:

  1. Message round-trip verification (Step 1): standard formatting and log round-trips remain correct after removing redundant dynamic message-text caching.
  2. Tuple-to-array serialization (Step 2): tuple-valued fields inside global_context or extra serialize to JSON arrays through the unified Python-to-JSON helper.
  3. Direct ANSI color placeholder support (Step 3): RustFormatter (and Formatter) parse %(ansi_level_color)s and %(ansi_reset_color)s directly.
  4. Compat caller-info activation (Step 4): handlers configured through compat_handlers.py activate the activate_caller_info layer only when the format references caller-info placeholders such as %(funcName)s.

Run it with:

pytest tests/test_optimizations.py