logger.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. /**
  2. * 日志工具模块
  3. *
  4. * 支持不同级别的日志记录(info, error, warn, debug)
  5. * 优先通过 MCP 协议的日志通知功能发送日志,如果 MCP Server 不可用则回退到 console.error
  6. */
  7. const LOG_LEVELS = {
  8. DEBUG: 0,
  9. INFO: 1,
  10. WARN: 2,
  11. ERROR: 3,
  12. };
  13. // MCP 日志级别映射
  14. const MCP_LOG_LEVELS = {
  15. DEBUG: 'debug',
  16. INFO: 'info',
  17. WARN: 'warning',
  18. ERROR: 'error',
  19. };
  20. // 从环境变量获取日志级别,默认为 INFO
  21. const getLogLevel = () => {
  22. const level = process.env.LOG_LEVEL?.toUpperCase() || 'INFO';
  23. return LOG_LEVELS[level] ?? LOG_LEVELS.INFO;
  24. };
  25. const currentLogLevel = getLogLevel();
  26. // 全局 MCP Server 实例(由 index.js 设置)
  27. let mcpServer = null;
  28. /**
  29. * 设置 MCP Server 实例,用于发送日志通知
  30. */
  31. export function setMcpServer(server) {
  32. mcpServer = server;
  33. }
  34. /**
  35. * 通过 MCP 协议发送日志通知
  36. * 根据 MCP 协议规范,日志通知应该通过 stdout 以 JSON-RPC 通知消息的形式发送
  37. * 同时也会输出到 stderr 作为备份,确保日志始终可见
  38. */
  39. function sendLogToMcp(level, message) {
  40. if (mcpServer) {
  41. try {
  42. // MCP 协议的日志通知格式:通过 stdout 发送 JSON-RPC 通知消息
  43. // 格式:{"jsonrpc": "2.0", "method": "notifications/message", "params": {"level": "info", "message": "..."}}
  44. const logNotification = {
  45. jsonrpc: '2.0',
  46. method: 'notifications/message',
  47. params: {
  48. level: MCP_LOG_LEVELS[level] || 'info',
  49. message: message,
  50. },
  51. };
  52. // 输出 JSON-RPC 格式的日志通知到 stdout(MCP 协议的标准方式)
  53. // 注意:必须以换行符结尾,并且是有效的 JSON
  54. console.log(JSON.stringify(logNotification));
  55. // 同时输出到 stderr 作为备份,确保日志始终可见
  56. // 这样即使 MCP 客户端没有正确处理通知,日志也能在 stderr 中看到
  57. console.error(formatLogMessage(level, message));
  58. return true;
  59. } catch (error) {
  60. // 如果发送失败,回退到 stderr 输出(普通格式)
  61. console.error(`[${level}] Failed to send log via MCP: ${error.message}`);
  62. return false;
  63. }
  64. }
  65. return false;
  66. }
  67. /**
  68. * 格式化日志消息
  69. * 不包含时间戳,因为 Cursor 会自动添加
  70. */
  71. function formatLogMessage(level, message) {
  72. return `[${level}] ${message}`;
  73. }
  74. /**
  75. * 记录 INFO 级别的日志(正常操作信息)
  76. * 优先通过 MCP 协议格式发送,同时也会输出到 stderr 确保可见
  77. */
  78. export function info(message) {
  79. if (currentLogLevel <= LOG_LEVELS.INFO) {
  80. // 尝试通过 MCP 协议格式发送日志(同时会输出到 stderr 作为备份)
  81. const sent = sendLogToMcp('INFO', message);
  82. if (!sent) {
  83. // 如果 MCP Server 不可用,回退到 stderr 输出(普通格式)
  84. console.error(formatLogMessage('INFO', message));
  85. }
  86. }
  87. }
  88. /**
  89. * 记录 ERROR 级别的日志(错误信息)
  90. */
  91. export function error(message) {
  92. if (currentLogLevel <= LOG_LEVELS.ERROR) {
  93. const sent = sendLogToMcp('ERROR', message);
  94. if (!sent) {
  95. console.error(formatLogMessage('ERROR', message));
  96. }
  97. }
  98. }
  99. /**
  100. * 记录 WARN 级别的日志(警告信息)
  101. */
  102. export function warn(message) {
  103. if (currentLogLevel <= LOG_LEVELS.WARN) {
  104. const sent = sendLogToMcp('WARN', message);
  105. if (!sent) {
  106. console.error(formatLogMessage('WARN', message));
  107. }
  108. }
  109. }
  110. /**
  111. * 记录 DEBUG 级别的日志(调试信息)
  112. */
  113. export function debug(message) {
  114. if (currentLogLevel <= LOG_LEVELS.DEBUG) {
  115. const sent = sendLogToMcp('DEBUG', message);
  116. if (!sent) {
  117. console.error(formatLogMessage('DEBUG', message));
  118. }
  119. }
  120. }