From d2474d558c9a7c27eaa3173a0464394b44d86d45 Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Mon, 14 Apr 2025 15:45:05 -0400 Subject: [PATCH] Only apply log config to FastMCP loggers --- src/fastmcp/utilities/logging.py | 20 ++++++++++++++------ tests/conftest.py | 0 tests/utilities/test_logging.py | 30 ++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 6 deletions(-) create mode 100644 tests/conftest.py create mode 100644 tests/utilities/test_logging.py diff --git a/src/fastmcp/utilities/logging.py b/src/fastmcp/utilities/logging.py index 1535d1e56..cce488b45 100644 --- a/src/fastmcp/utilities/logging.py +++ b/src/fastmcp/utilities/logging.py @@ -20,15 +20,23 @@ def get_logger(name: str) -> logging.Logger: def configure_logging( - level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] = "INFO", + level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] | int = "INFO", ) -> None: """Configure logging for FastMCP. Args: level: the log level to use """ - logging.basicConfig( - level=level, - format="%(message)s", - handlers=[RichHandler(console=Console(stderr=True), rich_tracebacks=True)], - ) + # Only configure the FastMCP logger namespace + handler = RichHandler(console=Console(stderr=True), rich_tracebacks=True) + formatter = logging.Formatter("%(message)s") + handler.setFormatter(formatter) + + fastmcp_logger = logging.getLogger("FastMCP") + fastmcp_logger.setLevel(level) + + # Remove any existing handlers to avoid duplicates on reconfiguration + for hdlr in fastmcp_logger.handlers[:]: + fastmcp_logger.removeHandler(hdlr) + + fastmcp_logger.addHandler(handler) diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/utilities/test_logging.py b/tests/utilities/test_logging.py new file mode 100644 index 000000000..30ea963e9 --- /dev/null +++ b/tests/utilities/test_logging.py @@ -0,0 +1,30 @@ +import logging + +from fastmcp.utilities.logging import get_logger + + +def test_logging_doesnt_affect_other_loggers(caplog): + # set FastMCP loggers to CRITICAL and ensure other loggers still emit messages + original_level = logging.getLogger("FastMCP").getEffectiveLevel() + + try: + logging.getLogger("FastMCP").setLevel(logging.CRITICAL) + + root_logger = logging.getLogger() + app_logger = logging.getLogger("app") + fastmcp_logger = logging.getLogger("FastMCP") + fastmcp_server_logger = get_logger("server") + + with caplog.at_level(logging.INFO): + root_logger.info("--ROOT--") + app_logger.info("--APP--") + fastmcp_logger.info("--FASTMCP--") + fastmcp_server_logger.info("--FASTMCP SERVER--") + + assert "--ROOT--" in caplog.text + assert "--APP--" in caplog.text + assert "--FASTMCP--" not in caplog.text + assert "--FASTMCP SERVER--" not in caplog.text + + finally: + logging.getLogger("FastMCP").setLevel(original_level)