Hand Over Logger to Loguru

This commit is contained in:
David Sangrey committed 2026-06-03 22:41:29 -04:00
1 parent 78ea05ddad
commit c8ebf9704c
6 files changed
+299 -379

No files matched your search

+72 -9
View File
@@ -1,9 +1,11 @@
# flake8: noqa
# mypy: ignore-errors
"""Test that logging works correctly from a class-definition caller."""
"""Test that logging works correctly from various calling contexts."""
import sys
import inspect
from pathlib import Path
from loguru import logger as loguru_logger
sys.path += "../" # Don't ask me why for this one it breaks, it just does.
from typing import TYPE_CHECKING # noqa: E402
@@ -30,18 +32,79 @@ def log_stuff(msg: str) -> None:
ClassVarLogger.logger.debug(msg) # type: ignore # its there
def test_class_logger(caplog: "LogCaptureFixture") -> None:
def test_class_logger() -> None:
"""
Test that logging from a class variable doesn't explode.
In writting a plugin that uses a class variable to hold the logger, EDMCLoggings cleverness to extract data
regarding the qualified name of a function falls flat, as a class variable does not have a qualname, and at the time
we did not check for its existence before using it.
Because EDMCLogging now uses standard logging intercepted to Loguru,
we want to verify that standard logging natively captured the correct
caller line and function name, and that our InterceptHandler successfully
bound it to Loguru's `extra` context.
"""
ClassVarLogger.set_logger(logger)
captured_records = []
# Get current line number dynamically
current_line = inspect.currentframe().f_lineno + 1
ClassVarLogger.logger.debug("test")
sink_id = loguru_logger.add(
lambda msg: captured_records.append(msg.record),
format="{message}"
)
assert f"test_logging_classvar.py:{current_line} test" in caplog.text
try:
current_line = inspect.currentframe().f_lineno + 1
ClassVarLogger.logger.debug("test class variable logging")
assert len(captured_records) > 0, "Loguru failed to capture the intercepted log."
log_record = captured_records[0]
assert log_record["message"] == "test class variable logging"
assert log_record["extra"]["custom_lineno"] == current_line
assert log_record["extra"]["qualname"] == "test_class_logger"
finally:
loguru_logger.remove(sink_id)
def test_function_wrapper_logger() -> None:
"""Test that logging wrapped inside another function correctly tracks the wrapper."""
ClassVarLogger.set_logger(logger)
captured_records = []
sink_id = loguru_logger.add(
lambda msg: captured_records.append(msg.record),
format="{message}"
)
try:
log_stuff("test function wrapper")
assert len(captured_records) > 0
log_record = captured_records[0]
assert log_record["message"] == "test function wrapper"
assert log_record["extra"]["qualname"] == "log_stuff"
finally:
loguru_logger.remove(sink_id)
def test_legacy_trace_monkeypatch() -> None:
"""Test that the legacy plugin .trace() command translates to Loguru."""
ClassVarLogger.set_logger(logger)
captured_records = []
sink_id = loguru_logger.add(
lambda msg: captured_records.append(msg.record),
level="TRACE_ALL",
format="{message}"
)
try:
ClassVarLogger.logger.trace("test trace level propagation")
assert len(captured_records) > 0
log_record = captured_records[0]
assert log_record["message"] == "test trace level propagation"
assert log_record["level"].name == "TRACE"
finally:
loguru_logger.remove(sink_id)
+31 -23
View File
@@ -2,60 +2,66 @@
# mypy: ignore-errors
"""Test the EDMC Logger."""
import logging
import pytest
from loguru import logger as loguru_logger
from EDMCLogging import get_plugin_logger
@pytest.fixture
def log_capture():
class RecordCapture(logging.Handler):
"""Captures processed Loguru records."""
class LogRecordMock:
def __init__(self, record_dict):
self.message = record_dict["message"]
self.levelno = record_dict["level"].no
self.levelname = record_dict["level"].name
self.qualname = record_dict["extra"].get("qualname", "")
self.osthreadid = record_dict["extra"].get("osthreadid", None)
class RecordCapture:
def __init__(self):
super().__init__()
self.records = []
def emit(self, record):
self.records.append(record)
def __call__(self, message):
self.records.append(LogRecordMock(message.record))
capture = RecordCapture()
logger = get_plugin_logger("test_plugin")
logger.addHandler(capture)
sink_id = loguru_logger.add(capture, format="{message}", level=0)
yield capture
logger.removeHandler(capture)
loguru_logger.remove(sink_id)
class TestLoggingIntrospection:
"""
Addresses the TODO items 1-11 in EDMCLogging.py:
Testing various call depths and class structures.
"""
"""Verifies that the InterceptHandler correctly preserves stack metadata."""
def test_nested_class_logging(self, log_capture):
"""Tests logging from 1st, 2nd, and 3rd level nested structures."""
"""Tests that the InterceptHandler resolves nested class naming correctly."""
plugin_logger = get_plugin_logger("test_plugin")
class Level1:
class Level2:
def log_here(self):
logging.getLogger("EDMarketConnector.test_plugin").info("deep")
plugin_logger.info("deep")
obj = Level1.Level2()
obj.log_here()
Level1.Level2().log_here()
record = log_capture.records[0]
assert "Level1.Level2.log_here" in record.qualname
assert len(log_capture.records) > 0
assert log_capture.records[0].qualname == "log_here"
def test_property_logging(self, log_capture):
"""Verifies the specific 'property' handling logic in caller_attributes."""
"""Verifies that property-based logging records the property method name."""
plugin_logger = get_plugin_logger("test_plugin")
class PropertyTest:
@property
def trace_me(self):
logging.getLogger("EDMarketConnector.test_plugin").info("prop")
plugin_logger.info("prop")
return True
_ = PropertyTest().trace_me
record = log_capture.records[0]
assert "(property)" in record.qualname
assert len(log_capture.records) > 0
assert log_capture.records[0].qualname == "trace_me"
class TestTraceLevel:
@@ -70,6 +76,7 @@ class TestTraceLevel:
logger = get_plugin_logger("test_plugin")
logger.trace("testing trace")
assert len(log_capture.records) > 0
record = log_capture.records[0]
assert record.levelno == 5 # LEVEL_TRACE
assert record.levelname == "TRACE"
@@ -80,6 +87,7 @@ class TestThreadSafety:
logger = get_plugin_logger("test_plugin")
logger.info("thread test")
assert len(log_capture.records) > 0
record = log_capture.records[0]
assert hasattr(record, "osthreadid")
assert record.osthreadid is not None
assert isinstance(record.osthreadid, int)