Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions src/renderkit/logging_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ def _has_handler(logger: logging.Logger, handler_key: str) -> bool:
)


def _get_handler(logger: logging.Logger, handler_key: str) -> logging.Handler | None:
for handler in logger.handlers:
if getattr(handler, "renderkit_handler", None) == handler_key:
return handler
return None


def _log_level() -> int:
level_name = os.environ.get("RENDERKIT_LOG_LEVEL", "INFO").upper()
return getattr(logging, level_name, logging.INFO)
Expand Down Expand Up @@ -92,18 +99,19 @@ def setup_logging(
)

# 3. Manage File Handler
if not _has_handler(root_logger, "file"):
file_handler = _get_handler(root_logger, "file")
if file_handler is None:
file_handler = RotatingFileHandler(
log_path,
maxBytes=5 * 1024 * 1024,
backupCount=3,
encoding="utf-8",
)
file_handler.renderkit_handler = "file"
file_handler.setLevel(logging.INFO) # File captures INFO+
file_handler.setFormatter(file_formatter)
root_logger.addHandler(file_handler)
rk_logger.info("Logging to %s", log_path)
file_handler.setLevel(log_level)

# 4. Manage Console Handler
if enable_console is None:
Expand Down
18 changes: 18 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
"""Shared pytest fixtures for RenderKit tests."""

import logging

import pytest

from renderkit.ui.qt_compat import QApplication


def _close_renderkit_logging_handlers() -> None:
root_logger = logging.getLogger()
for handler in root_logger.handlers.copy():
if getattr(handler, "renderkit_handler", None):
root_logger.removeHandler(handler)
handler.close()


@pytest.fixture(autouse=True)
def cleanup_renderkit_logging_handlers():
"""Keep RenderKit root handlers from leaking between tests."""
_close_renderkit_logging_handlers()
yield
_close_renderkit_logging_handlers()


@pytest.fixture(scope="session")
def qapp():
"""Create a QApplication for Qt widget tests."""
Expand Down
62 changes: 62 additions & 0 deletions tests/test_logging_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""Tests for RenderKit logging helpers."""

from __future__ import annotations

import logging
from pathlib import Path

from renderkit.logging_utils import setup_logging


def _flush_renderkit_handlers() -> None:
for handler in logging.getLogger().handlers:
if getattr(handler, "renderkit_handler", None):
handler.flush()


def test_env_debug_level_reaches_file_log(monkeypatch, tmp_path: Path) -> None:
"""RENDERKIT_LOG_LEVEL should control the file sink level."""
log_path = tmp_path / "renderkit-debug.log"
monkeypatch.setenv("RENDERKIT_LOG_PATH", str(log_path))
monkeypatch.setenv("RENDERKIT_LOG_LEVEL", "DEBUG")

setup_logging(enable_console=False)
logging.getLogger("renderkit.test").debug("debug sentinel")
logging.getLogger("renderkit.test").info("info sentinel")
_flush_renderkit_handlers()

log_text = log_path.read_text(encoding="utf-8")
assert "debug sentinel" in log_text
assert "info sentinel" in log_text


def test_explicit_debug_level_reaches_file_log(monkeypatch, tmp_path: Path) -> None:
"""The explicit setup_logging level should control the file sink."""
log_path = tmp_path / "renderkit-explicit-debug.log"
monkeypatch.setenv("RENDERKIT_LOG_PATH", str(log_path))
monkeypatch.setenv("RENDERKIT_LOG_LEVEL", "INFO")

setup_logging(enable_console=False, level=logging.DEBUG)
logging.getLogger("renderkit.test").debug("explicit debug sentinel")
_flush_renderkit_handlers()

log_text = log_path.read_text(encoding="utf-8")
assert "explicit debug sentinel" in log_text


def test_reconfigured_debug_level_updates_existing_file_handler(
monkeypatch, tmp_path: Path
) -> None:
"""Repeated setup should update the existing file handler level."""
log_path = tmp_path / "renderkit-reconfigured-debug.log"
monkeypatch.setenv("RENDERKIT_LOG_PATH", str(log_path))

setup_logging(enable_console=False, level=logging.INFO)
logging.getLogger("renderkit.test").debug("hidden debug sentinel")
setup_logging(enable_console=False, level=logging.DEBUG)
logging.getLogger("renderkit.test").debug("updated debug sentinel")
_flush_renderkit_handlers()

log_text = log_path.read_text(encoding="utf-8")
assert "hidden debug sentinel" not in log_text
assert "updated debug sentinel" in log_text
Loading