Files
qiming/qiming-mcp-proxy/docs/LOG_CONFIGURATION.md
2026-06-01 13:03:20 +08:00

13 KiB
Raw Blame History

mcp-proxy 日志配置指南

概述

mcp-proxy 支持灵活的日志配置,可以通过配置文件或环境变量进行配置,非常适合与 Tauri 等客户端集成。

日志功能特性

  • 按日期滚动:每天自动创建新的日志文件
  • 自动清理:保留最近 N 天的日志文件
  • 多级别过滤:支持 trace/debug/info/warn/error
  • 双输出:同时输出到控制台和文件
  • 结构化日志:使用 tracing 框架
  • 环境变量覆盖:支持运行时动态配置

配置方式

方式 1: 环境变量(推荐用于 Tauri 集成)

环境变量具有最高优先级,会覆盖配置文件中的设置。

# 设置日志目录Tauri 可以传递应用数据目录)
export MCP_PROXY_LOG_DIR="/path/to/logs"

# 设置日志级别
export MCP_PROXY_LOG_LEVEL="info"

# 设置服务器端口
export MCP_PROXY_PORT="18099"

Windows (PowerShell):

$env:MCP_PROXY_LOG_DIR = "C:\Users\YourName\AppData\Roaming\YourApp\logs"
$env:MCP_PROXY_LOG_LEVEL = "info"
$env:MCP_PROXY_PORT = "18099"

Windows (CMD):

set MCP_PROXY_LOG_DIR=C:\Users\YourName\AppData\Roaming\YourApp\logs
set MCP_PROXY_LOG_LEVEL=info
set MCP_PROXY_PORT=18099

方式 2: 配置文件

创建 config.yml 文件:

server:
  port: 18099

log:
  level: "info"
  path: "./logs"
  retain_days: 7

配置文件查找顺序:

  1. /app/config.yml (Docker 容器内)
  2. ./config.yml (当前工作目录)
  3. 环境变量 BOT_SERVER_CONFIG 指定的路径

Tauri 集成示例

Rust 端 (nuwax-agent)

use std::process::Command;
use std::path::PathBuf;
use tauri::api::path::app_data_dir;

pub async fn start_mcp_proxy(
    tauri_config: &tauri::Config,
    port: u16,
) -> Result<Child> {
    // 获取 Tauri 应用数据目录
    let app_data = app_data_dir(tauri_config)
        .ok_or_else(|| anyhow::anyhow!("无法获取应用数据目录"))?;
    
    // 创建日志目录
    let log_dir = app_data.join("logs").join("mcp-proxy");
    std::fs::create_dir_all(&log_dir)?;
    
    let log_dir_str = log_dir.to_string_lossy().to_string();
    
    tracing::info!("MCP Proxy 日志目录: {}", log_dir_str);
    
    // 查找 mcp-proxy 可执行文件
    let mcp_proxy_path = resolve_npm_bin("mcp-proxy").await?;
    
    // 启动进程,传递环境变量
    let mut cmd = tokio::process::Command::new(&mcp_proxy_path);
    
    cmd.env("MCP_PROXY_LOG_DIR", &log_dir_str);
    cmd.env("MCP_PROXY_LOG_LEVEL", "info");
    cmd.env("MCP_PROXY_PORT", port.to_string());
    
    // Windows: 隐藏 CMD 窗口
    #[cfg(windows)]
    {
        use std::os::windows::process::CommandExt;
        const CREATE_NO_WINDOW: u32 = 0x08000000;
        cmd.creation_flags(CREATE_NO_WINDOW);
    }
    
    // 捕获 stdout/stderr 用于调试
    cmd.stdout(std::process::Stdio::piped());
    cmd.stderr(std::process::Stdio::piped());
    
    let mut child = cmd.spawn()?;
    
    // 读取并记录输出
    if let Some(stdout) = child.stdout.take() {
        tokio::spawn(async move {
            let reader = tokio::io::BufReader::new(stdout);
            let mut lines = reader.lines();
            while let Ok(Some(line)) = lines.next_line().await {
                tracing::info!("[mcp-proxy stdout] {}", line);
            }
        });
    }
    
    if let Some(stderr) = child.stderr.take() {
        tokio::spawn(async move {
            let reader = tokio::io::BufReader::new(stderr);
            let mut lines = reader.lines();
            while let Ok(Some(line)) = lines.next_line().await {
                tracing::error!("[mcp-proxy stderr] {}", line);
            }
        });
    }
    
    Ok(child)
}

TypeScript/JavaScript 端

import { Command } from '@tauri-apps/api/shell';
import { appDataDir, join } from '@tauri-apps/api/path';

async function startMcpProxy(port: number = 18099) {
  // 获取应用数据目录
  const appData = await appDataDir();
  const logDir = await join(appData, 'logs', 'mcp-proxy');
  
  console.log(`MCP Proxy 日志目录: ${logDir}`);
  
  // 创建命令
  const command = new Command('mcp-proxy', [], {
    env: {
      MCP_PROXY_LOG_DIR: logDir,
      MCP_PROXY_LOG_LEVEL: 'info',
      MCP_PROXY_PORT: port.toString(),
    }
  });
  
  // 监听输出
  command.on('output', (data) => {
    console.log('[mcp-proxy]', data);
  });
  
  command.on('error', (error) => {
    console.error('[mcp-proxy error]', error);
  });
  
  // 执行命令
  const child = await command.spawn();
  
  console.log(`MCP Proxy 已启动PID: ${child.pid}`);
  
  return child;
}

日志文件格式

文件命名规则

日志目录/
├── log.2026-02-12      # 2026年2月12日的日志
├── log.2026-02-13      # 2026年2月13日的日志
└── log.2026-02-14      # 2026年2月14日的日志当前

自动清理:默认保留最近 5 天的日志,可通过 retain_days 配置。

日志内容示例

2026-02-12T14:30:15.123456Z  INFO mcp_proxy: ========================================
2026-02-12T14:30:15.123789Z  INFO mcp_proxy: MCP-Proxy 服务启动
2026-02-12T14:30:15.124012Z  INFO mcp_proxy: 命令: proxy (HTTP 服务器模式)
2026-02-12T14:30:15.124234Z  INFO mcp_proxy: 版本: 0.1.39
2026-02-12T14:30:15.124456Z  INFO mcp_proxy: 配置信息:
2026-02-12T14:30:15.124678Z  INFO mcp_proxy:   - 监听端口: 18099
2026-02-12T14:30:15.124890Z  INFO mcp_proxy:   - 日志目录: /path/to/logs
2026-02-12T14:30:15.125012Z  INFO mcp_proxy:   - 日志级别: info
2026-02-12T14:30:15.125234Z  INFO mcp_proxy:   - 日志保留: 7 天
2026-02-12T14:30:15.125456Z  INFO mcp_proxy: 环境变量覆盖:
2026-02-12T14:30:15.125678Z  INFO mcp_proxy:   - MCP_PROXY_LOG_DIR: /custom/log/path
2026-02-12T14:30:15.125890Z  INFO mcp_proxy: ========================================
2026-02-12T14:30:15.234567Z  INFO mcp_proxy: 尝试绑定到地址: 0.0.0.0:18099
2026-02-12T14:30:15.345678Z  INFO mcp_proxy: 成功绑定到地址: 0.0.0.0:18099
2026-02-12T14:30:15.456789Z  INFO mcp_proxy: 初始化应用状态...
2026-02-12T14:30:15.567890Z  INFO mcp_proxy: 应用状态初始化完成
2026-02-12T14:30:15.678901Z  INFO mcp_proxy: 初始化路由...
2026-02-12T14:30:15.789012Z  INFO mcp_proxy: 路由初始化完成
2026-02-12T14:30:15.890123Z  INFO mcp_proxy: ✅ 服务启动成功,监听地址: 0.0.0.0:18099
2026-02-12T14:30:15.901234Z  INFO mcp_proxy: ✅ 健康检查端点: http://0.0.0.0:18099/health
2026-02-12T14:30:15.912345Z  INFO mcp_proxy: ✅ MCP 服务列表: http://0.0.0.0:18099/mcp
2026-02-12T14:30:16.023456Z  INFO mcp_proxy: ✅ MCP服务状态检查定时任务已启动
2026-02-12T14:30:16.134567Z  INFO mcp_proxy: 系统信息:
2026-02-12T14:30:16.145678Z  INFO mcp_proxy:   - 操作系统: windows
2026-02-12T14:30:16.156789Z  INFO mcp_proxy:   - 架构: x86_64
2026-02-12T14:30:16.167890Z  INFO mcp_proxy:   - 工作目录: "C:\\Users\\YourName\\AppData\\Local"
2026-02-12T14:30:16.178901Z  INFO mcp_proxy: 🚀 HTTP 服务器启动,等待连接...

日志级别说明

级别 用途 建议场景
trace 最详细的调试信息 开发调试
debug 调试信息 开发和测试
info 一般信息 生产环境推荐
warn 警告信息 最小日志
error 错误信息 仅记录错误

启动时的 stderr 输出

即使日志写入文件mcp-proxy 也会在启动时向 stderr 输出关键信息:

========================================
MCP-Proxy 启动中...
版本: 0.1.39
配置加载完成:
  - 端口: 18099
  - 日志目录: /path/to/logs
  - 日志级别: info
  - 日志保留天数: 7
========================================

这确保即使日志系统初始化失败,也能看到基本的启动信息。

故障排查

问题 1: 日志文件未创建

可能原因

  • 日志目录路径不存在或无权限
  • 环境变量设置错误

解决方案

# 检查日志目录是否存在
ls -la /path/to/logs

# 检查环境变量
echo $MCP_PROXY_LOG_DIR

# 手动创建目录
mkdir -p /path/to/logs
chmod 755 /path/to/logs

问题 2: 看不到日志输出

可能原因

  • 日志级别设置过高(如 error
  • Windows 下 CMD 窗口被隐藏

解决方案

# 降低日志级别
export MCP_PROXY_LOG_LEVEL="debug"

# 或使用 RUST_LOG 环境变量
export RUST_LOG="mcp_proxy=debug"

问题 3: 日志文件过多

可能原因

  • retain_days 设置过大

解决方案

# 设置保留天数(通过配置文件)
# config.yml
log:
  retain_days: 3  # 只保留 3 天

# 或手动清理旧日志
find /path/to/logs -name "log.*" -mtime +7 -delete

完整示例nuwax-agent 集成

// nuwax-agent-core/src/service/mcp_proxy.rs

use anyhow::{Context, Result};
use tokio::process::Child;
use std::path::PathBuf;

pub struct McpProxyConfig {
    pub port: u16,
    pub log_dir: PathBuf,
    pub log_level: String,
}

pub async fn start_mcp_proxy(config: McpProxyConfig) -> Result<Child> {
    // 确保日志目录存在
    std::fs::create_dir_all(&config.log_dir)
        .context("创建 MCP Proxy 日志目录失败")?;
    
    tracing::info!("启动 MCP Proxy:");
    tracing::info!("  - 端口: {}", config.port);
    tracing::info!("  - 日志目录: {}", config.log_dir.display());
    tracing::info!("  - 日志级别: {}", config.log_level);
    
    // 查找可执行文件
    let mcp_proxy_path = which::which("mcp-proxy")
        .or_else(|_| {
            // Fallback: 尝试 npm 全局路径
            let home = std::env::var("HOME")
                .or_else(|_| std::env::var("USERPROFILE"))?;
            
            #[cfg(windows)]
            let npm_bin = PathBuf::from(&home).join(".local/bin/mcp-proxy.cmd");
            
            #[cfg(not(windows))]
            let npm_bin = PathBuf::from(&home).join(".local/bin/mcp-proxy");
            
            if npm_bin.exists() {
                Ok(npm_bin)
            } else {
                Err(which::Error::CannotFindBinaryPath)
            }
        })
        .context("找不到 mcp-proxy 可执行文件")?;
    
    tracing::info!("mcp-proxy 路径: {}", mcp_proxy_path.display());
    
    // 构建命令
    let mut cmd = tokio::process::Command::new(&mcp_proxy_path);
    
    // 设置环境变量
    cmd.env("MCP_PROXY_LOG_DIR", config.log_dir.to_string_lossy().as_ref());
    cmd.env("MCP_PROXY_LOG_LEVEL", &config.log_level);
    cmd.env("MCP_PROXY_PORT", config.port.to_string());
    
    // 捕获输出
    cmd.stdout(std::process::Stdio::piped());
    cmd.stderr(std::process::Stdio::piped());
    
    // Windows: 隐藏 CMD 窗口
    #[cfg(windows)]
    {
        use std::os::windows::process::CommandExt;
        const CREATE_NO_WINDOW: u32 = 0x08000000;
        cmd.creation_flags(CREATE_NO_WINDOW);
    }
    
    // 启动进程
    let mut child = cmd.spawn()
        .context("启动 mcp-proxy 进程失败")?;
    
    // 异步读取 stdout
    if let Some(stdout) = child.stdout.take() {
        use tokio::io::{AsyncBufReadExt, BufReader};
        
        tokio::spawn(async move {
            let reader = BufReader::new(stdout);
            let mut lines = reader.lines();
            
            while let Ok(Some(line)) = lines.next_line().await {
                tracing::info!("[mcp-proxy] {}", line);
            }
        });
    }
    
    // 异步读取 stderr
    if let Some(stderr) = child.stderr.take() {
        use tokio::io::{AsyncBufReadExt, BufReader};
        
        tokio::spawn(async move {
            let reader = BufReader::new(stderr);
            let mut lines = reader.lines();
            
            while let Ok(Some(line)) = lines.next_line().await {
                tracing::error!("[mcp-proxy stderr] {}", line);
            }
        });
    }
    
    tracing::info!("MCP Proxy 进程已启动PID: {:?}", child.id());
    
    Ok(child)
}

环境变量参考

环境变量 类型 默认值 说明
MCP_PROXY_PORT u16 3000 HTTP 服务监听端口
MCP_PROXY_LOG_DIR String ./logs 日志文件目录
MCP_PROXY_LOG_LEVEL String info 日志级别 (trace/debug/info/warn/error)
RUST_LOG String - Rust 标准日志环境变量(更细粒度控制)
BOT_SERVER_CONFIG String - 自定义配置文件路径

高级用法RUST_LOG

RUST_LOG 环境变量提供更细粒度的日志控制:

# 只显示 mcp_proxy 模块的 debug 级别日志
export RUST_LOG="mcp_proxy=debug"

# 显示多个模块的日志
export RUST_LOG="mcp_proxy=debug,tokio=info,hyper=warn"

# 显示所有模块的 trace 级别日志(非常详细)
export RUST_LOG="trace"

# 组合使用
export RUST_LOG="debug,mcp_proxy=trace,hyper::proto=error"

注意RUST_LOG 优先级高于 MCP_PROXY_LOG_LEVEL

总结

  • 使用 MCP_PROXY_LOG_DIR 环境变量指定日志目录Tauri 集成推荐)
  • 日志文件按日期自动滚动,默认保留 5 天
  • 关键启动信息会输出到 stderr即使日志系统失败也能看到
  • 支持通过环境变量动态配置,无需修改配置文件
  • Windows 下可以隐藏 CMD 窗口,但仍然捕获日志输出

更多信息请参考: