Add enable_rich_logging setting to disable rich formatting (#2893)

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Bill Easton <strawgate@users.noreply.github.com>
This commit is contained in:
Bill Easton 2026-01-16 19:29:29 -06:00 committed by GitHub
commit 81cbb9bee2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 68 additions and 4 deletions

View file

@ -195,6 +195,18 @@ class Settings(BaseSettings):
docket: DocketSettings = DocketSettings()
enable_rich_logging: Annotated[
bool,
Field(
description=inspect.cleandoc(
"""
If True, will use rich formatting for log output. If False,
will use standard Python logging without rich formatting.
"""
)
),
] = True
enable_rich_tracebacks: Annotated[
bool,
Field(

View file

@ -57,6 +57,18 @@ def configure_logging(
logger.propagate = False
logger.setLevel(level)
# Remove any existing handlers to avoid duplicates on reconfiguration
for hdlr in logger.handlers[:]:
logger.removeHandler(hdlr)
# Use standard logging handlers if rich logging is disabled
if not fastmcp.settings.enable_rich_logging:
# Create a standard StreamHandler for stderr
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
logger.addHandler(handler)
return
# Configure the handler for normal logs
handler = RichHandler(
console=Console(stderr=True),
@ -91,10 +103,6 @@ def configure_logging(
traceback_handler.addFilter(lambda record: record.exc_info is not None)
# Remove any existing handlers to avoid duplicates on reconfiguration
for hdlr in logger.handlers[:]:
logger.removeHandler(hdlr)
logger.addHandler(handler)
logger.addHandler(traceback_handler)

View file

@ -1,5 +1,6 @@
import logging
import fastmcp
from fastmcp.utilities.logging import configure_logging, get_logger
@ -54,3 +55,46 @@ def test_configure_logging_traceback_defaults_can_be_overridden():
assert logger.handlers
# The traceback handler should have been created with custom values
# We can't directly inspect RichHandler internals easily, but we verified no error was raised
def test_configure_logging_with_rich_disabled():
"""Test that disabling rich logging uses standard StreamHandler."""
original_enable_rich = fastmcp.settings.enable_rich_logging
try:
fastmcp.settings.enable_rich_logging = False
configure_logging()
logger = logging.getLogger("fastmcp")
assert logger.handlers
# Should only have one handler when rich logging is disabled
assert len(logger.handlers) == 1
# Should be a StreamHandler, not RichHandler
assert isinstance(logger.handlers[0], logging.StreamHandler)
assert not hasattr(
logger.handlers[0], "console"
) # RichHandler has console attribute
finally:
fastmcp.settings.enable_rich_logging = original_enable_rich
# Reconfigure to restore state
configure_logging()
def test_configure_logging_with_rich_enabled():
"""Test that enabling rich logging uses RichHandler."""
original_enable_rich = fastmcp.settings.enable_rich_logging
try:
fastmcp.settings.enable_rich_logging = True
configure_logging()
logger = logging.getLogger("fastmcp")
assert logger.handlers
# Should have two handlers when rich logging is enabled (normal + traceback)
assert len(logger.handlers) == 2
# Both should be RichHandler instances
from rich.logging import RichHandler
assert all(isinstance(h, RichHandler) for h in logger.handlers)
finally:
fastmcp.settings.enable_rich_logging = original_enable_rich
# Reconfigure to restore state
configure_logging()