"""日志记录模块."""
import logging
import sys
from pathlib import Path
from typing import Optional
def setup_logger(
name: str = "grace-mcp",
level: int = logging.INFO,
log_file: Optional[Path] = None,
enable_console: bool = True
) -> logging.Logger:
"""
设置日志记录器.
Args:
name: 日志记录器名称
level: 日志级别
log_file: 日志文件路径(可选)
enable_console: 是否启用控制台输出(默认 True,MCP 模式下应设为 False)
Returns:
配置好的日志记录器
"""
logger = logging.getLogger(name)
logger.setLevel(level)
# 避免重复添加处理器
if logger.handlers:
return logger
# 控制台处理器 - 仅在非 MCP 模式下启用
# MCP 协议要求通过 stdio 通信时,只能输出 JSON-RPC 格式的消息
# 任何非 JSON 的输出(包括 stderr)都会导致 Cursor 记录为错误
# 因此,在 MCP 模式下应该完全禁用控制台日志输出
if enable_console:
console_handler = logging.StreamHandler(sys.stderr)
console_handler.setLevel(level)
console_format = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
console_handler.setFormatter(console_format)
logger.addHandler(console_handler)
# 文件处理器(如果指定了日志文件)
if log_file:
log_file.parent.mkdir(parents=True, exist_ok=True)
file_handler = logging.FileHandler(log_file, encoding='utf-8')
file_handler.setLevel(level)
file_format = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
file_handler.setFormatter(file_format)
logger.addHandler(file_handler)
return logger
# 检测是否在 MCP 模式下运行(通过 stdio 通信)
# 如果 sys.stdin 是 TTY,说明不是通过 stdio 运行(可能是直接运行脚本)
# 如果 sys.stdin 不是 TTY,说明是通过 stdio 运行(MCP 模式)
_is_mcp_mode = not sys.stdin.isatty() if hasattr(sys.stdin, 'isatty') else True
# 默认日志记录器 - 在 MCP 模式下禁用控制台输出
default_logger = setup_logger(enable_console=not _is_mcp_mode)