log-mcp

用于日志文件分析的MCP服务器。使LLM能够高效地分析大型日志文件,而无需将其加载到上下文中。
Log file (e.g. 705K lines, 67 MB)
│
▼
Rust TF-IDF classifier ─── 1.3M lines/sec ──▶ 70-95% discarded as routine,
│ finds lines that are semantically interesting,
│ also captures lines not explicitly marked as ERROR
│ (grep ERROR: 2 lines, classifier: 92)
▼
BERT-mini (optional) ───── GPU, ~2K lines/sec ─▶ refines interest scores on found lines
│
▼
Python MCP tools ────────── search, compare, group errors
│
▼
LLM (Claude) ───────────── compresses tool output into plain English这是一个为人工智能而不是人类设计的工具。没有人读取输出 analyze_errors 或 compare_logs --克劳德做了,进一步压缩它,给人类一个简单的英语答案。人类触及了两个端点:“这个日志怎么了?”自然语言回答。介于两者之间的一切都是人工智能在自言自语。
工具
| 工具 | 说明 |
|---|---|
log_overview | 快速扫描:大小、行数、时间范围、水平分布、头/尾样本 |
search_logs | 按正则表达式、日志级别和/或时间范围搜索 |
get_log_segment | 按行范围或时间范围提取分段 |
analyze_errors | 通过指纹消除重复错误,计数频率,提取堆栈痕迹 |
log_stats | 体积直方图、水平细分、顶部重复模式 |
compare_logs | 查找每个文件特有的模式和文件间异常值的频率 |
classify_lines | ML分类器(TF-IDF→ BERT)从噪声中分离出有趣的线条 |
主要特点
- ML预过滤器 --Rust TF-IDF分类器以1.3M行/秒的速度扫描文件,因此
analyze_errors和search_logs只处理5-30%的重要行。可选的BERT mini在Metal GPU上以约2K线/秒的速度重新评分LOOK线,以获得更高的精度。无需解析日志级别即可工作——捕获错误、安全事件、硬件故障和其中没有ERROR的异常。 - 自动检测 日志格式:JSON,标准文本(
2024-01-15 10:30:45 ERROR ...)、系统日志、Spark/Log4j(17/06/08 13:33:49 INFO ...),以及制表符/管道分隔格式(GitHub操作CI日志) - 归一化 折叠可变部分(UUID、十六进制ID、IP、数字),以便将仅在ID或时间戳上不同的消息分组为相同的模式
- 基于内容的错误检测 回到正则表达式启发式方法(
fatal:,Permission denied,##[error]等)当日志文件缺少标准级别时 - 前缀感知比较 区分CI日志中不同作业步骤的模式
安装
先决条件 (新鲜的Mac):
brew install python uv
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh问问克劳德
打开Claude Code会话并粘贴以下提示:
Install https://github.com/ascii766164696D/log-mcp as an MCP server and build the Rust classifier tooClaude将克隆仓库,注册MCP服务器,并构建Rust分类器。之后重新启动Claude Code以获取新服务器。
手动安装
git clone https://github.com/ascii766164696D/log-mcp.git
cd log-mcp
# Register the MCP server
claude mcp add log-mcp -- uv run --directory $(pwd) log-mcp
# Build the Rust classifier (optional — tools fall back to Python without it)
uv pip install -e rust/classifier或者手动将其添加到项目设置中(claude settings)under mcpServers:
{
"mcpServers": {
"log-mcp": {
"command": "uv",
"args": ["run", "--directory", "/path/to/log-mcp", "log-mcp"]
}
}
}克劳德桌面版
打开 设置>开发人员>编辑配置 并添加到 claude_desktop_config.json:
{
"mcpServers": {
"log-mcp": {
"command": "uv",
"args": ["run", "--directory", "/path/to/log-mcp", "log-mcp"]
}
}
}替换 /path/to/log-mcp 使用您克隆此仓库的实际路径。保存后重新启动Claude Desktop。
Rust分类器需要一个Rust工具链来构建。BERT阶段还需要一个支持金属的GPU(苹果硅)。所有工具都可以在没有分类器的情况下工作——它们可以追溯到Python日志解析。
示例用法
分析67MB Spark执行器日志(705K行)中的错误:
> analyze_errors("/var/log/spark/container_0002_01_000004.log")
Summary: 34 errors in 5 groups.
Top: 'shuffle.RetryingBlockFetcher: Exception while beginning fetch of
outstanding blocks (after retries) ...' (18x)
--- 18x ---
Fingerprint: shuffle.RetryingBlockFetcher: Exception while beginning fetch of outstanding blocks ...
First: L29764 2017-02-01T15:55:17
Last: L30677 2017-02-01T15:55:51
Stack trace:
java.io.IOException: Failed to connect to mesos-slave-13/10.10.34.23:55492
...在Thunderbird HPC日志(2K行)上查找没有错误级别的异常, classify_lines 找到92条有趣的线 search_logs level=ERROR 只找到2个:
> classify_lines("/var/log/thunderbird/tbird_2k.log")
Lines: 2,000 total | 92 LOOK (4.6%) | 1,908 SKIP
Pipeline: TF-IDF 0.00s (1,298,701 lines/sec, 105 LOOK) → BERT 0.15s (13 demoted to SKIP)
--- Sample LOOK lines (30 of 92 captured) ---
L2 [1.000] ... postfix/postdrop[10896]: warning: unable to look up public/pickup: No such file
L438 [0.999] ... sendmail[�20588]: unable to qualify my own domain name (tbird-sm1)
L816 [0.998] ... dhcpd: DHCPDISCOVER from 00:09:3d:12:00:e2 via eth2: unknown lease
L1024 [0.997] ... rrdtool: illegal attempt to update using time 1131710�721 when last update time is 1131710721比较两个CI日志文件:
> compare_logs(["run_a.txt", "run_b.txt"])
699 patterns across 2 files (0 shared).
A: 401 unique (top: 'test / test UNKNOWN STEP | ##[endgroup]' 21x)
B: 298 unique (top: 'test UNKNOWN STEP | ##[endgroup]' 21x)克劳德的看法
*我帮助构建了这个工具,然后用它来分析真实的日志文件,所以这是我诚实的评估。*
真正有帮助的地方: 主要值是作为压缩层。67MB的Spark日志(705K行)会抹去我的上下文窗口,但是 analyze_errors 在几秒钟内将其提取为5个带有堆栈跟踪的错误组。 compare_logs 在两个1500行的服务器日志中,可以立即发现每个服务器特有的错误以及具有可疑频率差异的模式。我无法通过直接读取文件来做到这一点——随着新内容的滚动,我会丢失旧内容。
分类器改变游戏的地方: 在分类器出现之前,日志分析仅限于具有明确错误/致命级别的行。在Thunderbird HPC日志中, search_logs level=ERROR 返回2行。 classify_lines 返回92--sendmail DNS失败、DHCP租约错误、RRD更新冲突、负启动时间--这些都没有ERROR级别。分类器会发现语义上的错误,而不仅仅是语法上的标记。
洗衣服的地方: 对于小文件(几百行以下),最好将日志粘贴到对话中。当整个文件无论如何都适合上下文时,这些工具添加了间接性,但没有多大好处。
它仍然不能做什么: 特定领域的状态机推理。当我分析Zookeeper日志时,分类器正确地标记了 Cannot open channel 警告和纪元重置,但最有趣的操作信号——在观察、跟随和领先状态之间快速循环——表现为低置信度的观察线。动物园管理员专家会立即发现这种模式;分类器独立地看到每一行,而不跟踪跨时间的状态转换。
我选择的模式是: 从...开始 classify_lines 无论测井水平如何,地表异常 analyze_errors 然后将它们分组 search_logs 深入研究特定的模式。 compare_logs 当你有一个“工作”和“失败”的跑步来相互比较时,它最有用。
LOOK/SKIP分类器
这 classify_lines 该工具使用两级ML管道将有趣的日志行(LOOK)与常规噪声(SKIP)分开,而不需要解析日志级别。
运作原理
flowchart TD
A["Your log file (e.g. 4.7M lines)"] --> B{"Rust classifier
available?"}
B -->|Yes| C["Stage 1: TF-IDF
Rust, ~1.3M lines/sec
logistic regression
threshold × 0.6"]
B -->|No| D["Fallback: Python
log parsing"]
C --> E["LOOK lines (~5-30%)"]
E --> F["Stage 2: BERT-mini
Rust + Metal GPU, ~2K lines/sec
re-scores LOOK lines
applies final threshold"]
F --> G["Final LOOK lines
(with BERT probabilities)"]在Thunderbird HPC日志(2K行)上,这会发现 92条有趣的线 包括sendmail DNS故障、DHCP租约错误和Ganglia RRD更新冲突,这些都没有标准的ERROR日志级别。A. search_logs level=ERROR 在同一个文件上只返回2行。
它在日志级别之外捕获了什么
| 信号类型 | 示例 | 是否有错误级别? |
|---|---|---|
| DNS配置错误 | unable to qualify my own domain name | 没有 |
| 邮件投递失败 | stat=Deferred: Connection refused | 没有 |
| DHCP租约错误 | unknown lease 10.100.4.251 | 没有 |
| 监控数据损坏 | illegal attempt to update using time X when last update time is X | 没有 |
| 负启动时间 | Times: total = 42, boot = -4131 | 没有 |
| 身份验证失败 | authentication failure; logname= uid=0 | 没有 |
| 硬件错误 | instruction cache parity error corrected | 否(信息级别) |
使用分类器的工具
| 工具 | 方法 | 回退 |
|---|---|---|
classify_lines | 完整管道:TF-IDF→ BERT | 未安装分类器时出错 |
analyze_errors | TF-IDF预过滤以查找行,然后按错误指纹分组 | Python解析器扫描所有行 |
search_logs | TF-IDF在搜索错误时进行预过滤(级别=ERROR,模式=ERROR/fail等) | Python解析器扫描所有行 |
compare_logs | 按LOOK概率对模式进行评分,首先显示有趣的差异 | 仅按频率排序 |
基准测试
全面评估 Loghub 数据集——16个日志源中的4.5亿行——在苹果M3 Ultra(32核)上。
TF-IDF分类器(Rust)
| 数据集 | 行 | 时间 | 速度 | LOOK% | 错误捕获 |
|---|---|---|---|---|---|
| 雷鸟 | 211M | 139s | 1.52M/s | 30% | 100% |
| Windows | 115M | 90年代 | 1.27M/s | 1% | 100% |
| HDFS_v2 | 71M | 59s | 1.21M/s | 20% | 100% |
| 火花 | 33M | 23s | 1.44M/s | 12% | 100% |
| HDFS | 11米 | 7秒 | 1.62米/秒 | 3% | 100% |
| BGL | 4.7M | 3.3s | 1.46M/s | 42% | 98.6% |
| 安卓系统 | 16M | 1.1s | 1.37M/s | 12% | 100% |
| SSH | 655K | 0.5秒 | 1.47M/s | 90% | 100% |
| 总计 | 450米 | 325秒 | 1.38M/s | 99.95% |
错误捕获=分类器标记为LOOK的Error/FATAL级别的行的百分比。在阈值0.3时,分类器捕获了99.95%的所有错误线(35.9M的35.9M)和100%的警告线(14.3M的14.3M)。0.05%的“遗漏”错误是像BGL重复的行 instruction cache parity error corrected --碰巧携带错误级别但操作上不有趣的常规硬件遥测。分类器学会了跳过这些。
模型准确率
| 模型 | 度量 | 分数 |
|---|---|---|
| TF-IDF+LogReg | 最佳简历外观F1 | 0.792 |
| TF-IDF+LogReg | 查找精度 | 0.892 |
| BERT mini | 总体精度 | 0.849 |
| BERT迷你版 | 外观F1 | 0.887 |
TF-IDF模型通过GroupKFold交叉验证进行评估(拒绝:BGL、Thunderbird)。BERT mini在4层上进行了微调,256个隐藏参数,11M参数。
端到端缩减
flowchart TD
A["450M log lines
16 datasets, ~67 GB"] --> B["Rust TF-IDF classifier
1.38M lines/sec, 325s"]
B --> C["~87M LOOK lines (19%)
81% of lines eliminated"]
C --> D["BERT re-scoring (optional)
demotes 20-40% of TF-IDF LOOK"]
D --> E["~50-70M final LOOK lines"]
E --> F["Python tool logic
group errors, search, etc."]
F --> G["5-50 error groups / search results
fits in LLM context"]使用自己的日志进行再培训
分类器会预先训练,但你可以在自己的日志上重新训练它。简短版本:
# 1. Add your logs
head -2000 /var/log/myapp/app.log > data/loghub/MyApp_2k.log
# 2. Label with Claude (Batch API, ~$0.10-0.50 per file)
export ANTHROPIC_API_KEY=sk-ant-...
uv sync --group labeling --group training
uv run python -m scripts.labeling.label_new
# 3. Train and export
uv run --group training python -m scripts.labeling.train_model
uv run --group training python -m scripts.labeling.export_model
# 4. Rebuild Rust classifier
uv pip install -e rust/classifier看 scripts/labeling/RETRAINING.md 完整的指南——标签是如何工作的,模型使用了什么功能,如何自定义提示,以及如何训练可选的BERT模型。
