本文说明当前版本实际采用的产品设计、系统架构、数据流、功能拆分、核心算法、资源边界和验证方式。它面向以下读者:
本文描述的是「当前实现」,不是早期设想。发生冲突时,判断优先级为:
CLAUDE.md 中的硬约束。README.md 中的概览说明。项目解决的是运维人员在个人电脑上离线分析 MongoDB 诊断文件的问题,包含两个相互独立但共用运行外壳的工作区:
MongoDB Log:解析结构化日志、旧版单行日志和 .gz 日志,生成慢查询统计、运行诊断和脱敏 Markdown 报告。MongoDB Metric:解析 MongoDB FTDC 文件,建立紧凑索引,再按指标组查询并绘制时间序列。127.0.0.1:18080。-Xms128m -Xmx2g。浏览器页面、后端服务、分析计算和文件存储全部位于同一台电脑。页面通过本机 REST API 访问 Spring Boot 服务,不引入远端依赖。
Log 按行读取,FTDC 按 BSON 文档和 Block 读取。系统尽量只保留聚合值、固定容量明细和当前解码 Block,避免把完整输入展开到内存。
需要业务精确性的统计基于全部有效数据计算;只有明细保留和图表点数受限。例如:
min、max、avg 和全零判断基于全部有效点。MongoDB 不同版本、日志格式和配置提供的字段不同。所有可选指标都按字段是否存在判断;缺失字段展示为「日志未提供」,不会补成零。
JSON、JSONL、FTDC catalog 和索引先写临时文件,再原子移动到正式位置。FTDC 工作目录在全部文件建索引成功后才整体发布到任务目录。
页面提供测量值、聚合结果和排查线索,但不把线索写成确定根因。例如出现 COLLSCAN 时,只建议结合索引、过滤条件和集合规模继续核对。
浏览器
└── Vue 3 单页应用
├── MongoDB Log 工作区
├── MongoDB Metric 工作区
└── 内存与数据维护入口
│ HTTP/JSON/Multipart
▼
Spring Boot 本地服务
├── web REST 接口、参数校验、统一错误响应
├── task 上传、任务状态、异步执行、恢复与删除
├── parser Log 与 FTDC 格式解析
├── analysis 聚合、诊断、FTDC 序列查询与降采样
├── report 脱敏 Markdown 报告
├── storage JSON/JSONL、catalog、二进制索引
└── config 单线程执行器、解析器装配、浏览器启动
│
▼
本地 data 目录
├── Log 任务元数据和结果
└── FTDC 任务元数据、源副本、catalog 和 blocks.idx
| 包 | 核心职责 | 设计要点 |
|---|---|---|
config |
组装解析器、创建任务执行器、启动浏览器 | 只负责运行配置,不承载业务逻辑 |
web |
REST API、参数校验、错误映射 | Controller 不直接实现解析算法 |
task |
任务创建、状态迁移、后台执行、清理 | Log 与 FTDC 生命周期分开建模 |
parser |
输入格式识别和字段提取 | 解析失败显式分类,不静默丢弃 |
analysis |
统计、诊断、序列合并与降采样 | 完整统计与有界输出分离 |
storage |
任务与结果持久化 | 临时文件加原子移动,删除前校验路径 |
report |
生成 AI 可读报告 | 只读取已持久化结果,并统一脱敏 |
| 位置 | 核心职责 |
|---|---|
App.vue |
工作区切换、Log 任务状态、结果视图和全局页面状态 |
api/*.js |
REST 请求、错误消息和文件下载 |
components/ |
Log 上传、任务列表、统计、诊断、慢查询详情、通用图表 |
components/ftdc/ |
FTDC 上传、任务列表、指标组选取和图表 |
utils/format.js |
时间、字节、时长、百分比格式化 |
utils/queryExplanation.js |
基于实际字段生成保守的查询解读 |
Log 和 FTDC 都采用相同的四态模型:
QUEUED → RUNNING → COMPLETED
↘ FAILED
202 Accepted 和 QUEUED 任务。RUNNING 和开始时间。COMPLETED。FAILED 和可读错误消息。QUEUED 或 RUNNING 任务,会标记为失败,不继续使用可能不完整的中间状态。TaskExecutorConfig 创建一个守护单线程执行器。Log 分析和 FTDC 建索引共用它,因此上传任务按队列顺序处理,不会同时争抢大量内存和磁盘带宽。
FTDC 建索引、序列查询以及内部分页/导出组件共用 FtdcOperationGate。它使用公平的单许可 Semaphore,确保重型 FTDC 操作串行执行,并在异常后释放许可。
pending 标记阻止同一任务的状态请求重叠。AbortController 用于丢弃旧任务、旧指标组或已关闭详情抽屉的迟到响应。用户可以为任务命名,并上传普通文本、结构化 JSON 或 .gz 日志。多个文件按选择顺序合并为一个分析任务。
.zip、.bz2、.xz 和 .7z;.gz 根据文件名后缀进入 GZip 解码。data/work/<task-id>,用户原文件不被修改。TaskServiceAnalysisTaskTaskInputFile后台逐文件、逐行解析日志,并持续更新处理字节数和行数。
TaskRunner 用 BufferedReader 读取 UTF-8 文本。.gz 文件通过 GZIPInputStream 解压,不生成完整解压副本。CountingInputStream 统计原始上传副本的已读字节。data/work/<task-id>;清理失败会使任务进入失败状态,避免界面声称已经完整结束。TaskRunnerCountingInputStream同一任务可以包含 MongoDB 结构化日志和旧版单行日志。
CompositeLogParser 去除 BOM 后检查行首:
{ 开头时交给 StructuredLogParser。LegacyLogParser。每一行都返回 ParseOutcome,状态为:
| 状态 | 含义 | 是否可以携带部分字段 |
|---|---|---|
SUCCESS |
已完整解析当前支持字段 | 是 |
PARTIAL |
主体可用,但部分字段无效或缺失 | 是 |
SKIPPED |
空行或非 MongoDB 日志 | 否 |
FAILED |
看起来是目标格式,但结构或关键字段无效 | 否 |
错误码进入 parseErrors 聚合,页面披露失败、部分解析和跳过数量。
解析 MongoDB 4.4 及以上常见结构化日志字段,同时兼容字段增减。
Document.parse,支持 Extended JSON。t.$date、日期对象、数字时间戳和 ISO 时间字符串都可转换为 UTC Epoch Milliseconds。s、c、id、ctx、msg 和 attr 提取日志信封与业务字段。msg 等于 Slow query 时认定慢查询,避免把其他带耗时字段的日志混入统计。attr.command 的第一个命令名,再回退到 attr.type 或 command。find、aggregate、insert、update、delete、getMore、findAndModify、createIndexes 等命令的模式提取。durationMillis、cpuNanos、reslen 只接受可精确转换的非负整数。remote 和 client 会去除端口;IPv6 方括号地址单独处理。svc、tags 和 truncated 进入信封元数据,用于数据质量诊断。attributes 中供诊断和详情使用。StructuredLogParserParsedLogEntryLogEnvelopeMetadata解析旧版时间、级别、组件、上下文和消息格式,并从消息中提取慢查询、连接和心跳信息。
find、aggregate、insert、update、remove、getMore、findAndModify 和 createIndexes。BalancedDocumentExtractor 按花括号深度提取嵌套命令,并正确忽略字符串中的花括号和转义引号。ObjectId、NumberLong、Timestamp 等 BSON 构造器替换为占位值。PARTIAL。NETWORK 日志用于连接统计,不误判为慢查询。Heartbeat failed,不会把 checkpoint 恢复文本误判成心跳失败。LegacyLogParserBalancedDocumentExtractor把字面值不同但结构相同的查询归入同一模式。
?。{}。Namespace + 操作类型 + 模式,避免跨集合或跨操作混合。QueryPatternNormalizer基于所有成功提取耗时的慢查询生成统计。
| Key | 范围 |
|---|---|
lt_100ms |
<100ms |
100ms_500ms |
100ms-500ms |
500ms_1s |
500ms-1s |
1s_3s |
1s-3s |
3s_10s |
3s-10s |
10s_30s |
10s-30s |
30s_60s |
30s-60s |
gte_60s |
>=60s |
边界采用左闭右开,最后一档无上限。每档记录数量、占比、总耗时、平均耗时和最大耗时。
cpuNanos 时,汇总才标记 cpuAvailable=true。insert、update、delete、find 按 10% 区间统计;旧版 remove 映射到 delete。旧版连接消息中的当前连接数按 UTC 小时聚合为平均值。没有样本的小时不会自动补零。
AnalysisAccumulatorDurationDistributionAnalysisSummaryAggregateStatPatternStatTopSlowQueryCollector 使用固定容量最小堆:
这保证 Top 5000 是从全部慢查询中精确选取,不是抽样。
PatternStat 持久化。运行诊断独立于慢查询汇总,输出到 diagnostics.json,不会改变旧的 summary.json 口径。
近似计数器满时对全部候选计数减一并移除零值,这是有界高频项估计,不应解释为完整精确枚举。
当前实现会标记:
COLLSCAN。这些规则只生成线索,不生成自动根因。
DiagnosticAccumulatorLogDiagnosticsdata/
├── tasks-index.json
├── tasks/<task-id>/
│ ├── metadata.json
│ ├── summary.json
│ ├── diagnostics.json
│ └── top-slow-queries.jsonl
└── work/<task-id>/
tasks-index.json 支持任务列表快速恢复。metadata.json 保存独立状态。.tmp 文件发布,再尝试原子移动。diagnostics.json 时接口明确提示重新上传。TaskRepositoryFileTaskRepositorylocalStorage,可单独拖动或一键恢复默认布局。timestamp + duration + queryId 的轻量数据。用户可下载当前 Log 任务的 Markdown 报告,供人工检查或交给 AI 二次分析。
MarkdownReportService一个任务上传 1~20 个非空 FTDC 文件,文件按内容验证,不依赖扩展名。
0000-...、0001-...,顺序同时决定重复时间戳的优先级。data/ftdc/work/<task-id>/source。FtdcTaskServiceFtdcTaskFtdcTaskRunner逐文档读取 FTDC 文件,定位 type=1 指标 Block。
FtdcFileReader 使用 FileChannel 按偏移读取 BSON 长度和当前文档。type 和缺少二进制 data。解压一个 Block,读取 baseline、Schema、样本数量、delta 偏移和零游程信息。
| 项目 | 上限 |
|---|---|
| 声明解压长度 | 10,000,000 字节 |
| 单 Block 样本数 | 100,000 |
| 指标数 × 样本数 | 1,000,000 |
start 时间指标。/ 拼成指标路径。/t 和 /i。FtdcFileReaderFtdcBlockScannerFtdcBaselineFlattenerFtdcVarIntReader建索引阶段只保存以后定位和恢复指标列所需的信息,不保存完整展开时间序列。
catalog.json 保存:
blocks.idx二进制索引保存:
blocks.spool,避免在建索引时把全部 Block 索引留在 Java 对象中。blocks.idx。catalog.json 通过临时文件加原子移动发布。data/ftdc/tasks/<task-id>。FtdcCatalogFtdcBlockIndexFtdcIndexWriterFtdcIndexReader产品只允许按指标组查询,避免用户一次触发大量零散请求。
start、end、globalLock/totalTime 和部分内部时间戳不作为业务组展示。serverStatus/ 前缀从展示名称中去除。FtdcMetricGroups查询一个指标组时,每个 Block 只恢复时间列和该组实际存在的指标列。
FileChannel,一个源文件只在首次需要时打开。ColumnDecoder。Map<String, List<Long>>。查询前重新核对每个源副本的文件大小和 SHA-256。副本被外部改动后立即拒绝查询,避免索引指向错误数据。
FtdcMetricDecoderFtdcIndexReaderFtdcSeriesService多个 FTDC 文件可以包含交叠时间范围,查询结果必须按时间有序且去重。
直接返回 FTDC 恢复后的累计值或即时值。
null。current - previous。遍历全部有效点时同步计算:
minmaxaverageallZero这些值不从降采样结果反推。
当 FTDC 采样中断时,在图表中插入 null,防止折线跨越空白时间连接。
null 点,前端悬浮值显示 -。null 判断断裂,不从降采样点间距自行猜测。源码中存在单指标查询、原始值分页和 GZip CSV 导出服务:
FtdcSeriesService.seriesFtdcSeriesService.pageFtdcMetricExportService当前 FtdcTaskController 没有为它们声明 REST 路由,前端也没有入口。因此它们属于内部已测试组件,不属于当前发布的产品功能。文档、AI 改写和 API 兼容性判断都必须保持这个区分。
data/ftdc/
├── tasks-index.json
├── tasks/<task-id>/
│ ├── metadata.json
│ ├── catalog.json
│ ├── blocks.idx
│ └── source/<uploaded-file>
└── work/<task-id>/
FTDC 必须保留源副本以支持后续按需解码,因此磁盘占用与上传文件总量接近,并额外增加 catalog 和索引。删除任务只删除应用托管副本,不触碰用户原文件。
/api/system/memory 返回 JVM 已用堆、最大堆和使用百分比。页面启动后立即读取,并每 5 秒刷新。该数值是 JVM 堆,不代表进程总 RSS 或系统内存。
COMPLETED 和 FAILED。应用启动完成后尝试打开当前配置的本地地址。桌面能力不可用或打开失败只写警告,不影响服务继续运行。可通过 mongodblog.open-browser=false 禁用。
| 方法 | 路径 | 用途 | 关键限制 |
|---|---|---|---|
POST |
/api/tasks |
创建 Log 任务 | Multipart,文件不能为空 |
GET |
/api/tasks |
获取任务列表 | 按创建时间倒序 |
GET |
/api/tasks/{taskId} |
获取任务状态 | 活动任务用于轮询 |
DELETE |
/api/tasks/{taskId} |
删除终态任务 | 活动任务返回冲突 |
GET |
/api/tasks/{taskId}/summary |
获取慢查询汇总 | 仅已完成任务 |
GET |
/api/tasks/{taskId}/diagnostics |
获取运行诊断 | 历史任务可能不存在 |
GET |
/api/tasks/{taskId}/slow-queries |
分页筛选 Top 5000 | size 为 1~200 |
GET |
/api/tasks/{taskId}/slow-query-points |
获取散点轻量数据 | 只返回保留明细 |
GET |
/api/tasks/{taskId}/slow-queries/{queryId} |
获取单条详情 | 重新解析保留原始行 |
GET |
/api/tasks/{taskId}/report.md |
下载 Markdown 报告 | UTF-8 附件 |
| 方法 | 路径 | 用途 | 关键限制 |
|---|---|---|---|
POST |
/api/ftdc-tasks |
创建 FTDC 任务 | 1~20 个非空文件 |
GET |
/api/ftdc-tasks |
获取任务列表 | 按创建时间倒序 |
GET |
/api/ftdc-tasks/{taskId} |
获取任务状态 | 活动任务用于轮询 |
DELETE |
/api/ftdc-tasks/{taskId} |
删除终态任务 | 活动任务返回冲突 |
GET |
/api/ftdc-tasks/{taskId}/groups |
获取指标组 | 任务必须完成 |
GET |
/api/ftdc-tasks/{taskId}/groups/{groupId}/series |
查询指标组 | maxPoints 为 1~1,200,view 为 raw 或 delta |
| 方法 | 路径 | 用途 |
|---|---|---|
GET |
/api/system/memory |
获取 JVM 堆使用情况 |
DELETE |
/api/system/data |
清空全部终态任务和托管数据 |
统一返回:
{
"code": "INVALID_REQUEST",
"message": "可读错误信息",
"details": {}
}
主要映射:
| HTTP 状态 | 错误码 | 场景 |
|---|---|---|
400 |
INVALID_REQUEST |
参数、文件数量或范围无效 |
404 |
NOT_FOUND |
任务、指标组或明细不存在 |
409 |
TASK_NOT_READY |
请求未完成任务的结果 |
409 |
TASK_ACTIVE |
删除活动任务或活动时清空数据 |
413 |
UPLOAD_TOO_LARGE |
Multipart 超过 12 GB |
422 |
FTDC_FORMAT_ERROR |
FTDC 内容损坏或超出格式边界 |
500 |
TASK_DELETE_FAILED |
托管数据删除失败 |
mvn clean package
├── clean:删除旧构建产物
├── prepare-package:在 web 目录执行 npm ci
├── prepare-package:执行 npm run build
├── copy-resources:复制本次前端静态资源
└── spring-boot-maven-plugin:生成可执行 JAR
最终产物为 target/mongodb-log-analyzer.jar。发布目录还应包含三个平台启动脚本。
null 显示、全零隐藏和面板批量控制。localStorage 和小屏布局。mvn test
cd web
npm test -- --run
npm run build
cd ..
mvn clean package
真实 FTDC 验收测试需要外部样本路径,未配置时会按条件跳过;不能把跳过描述成已使用真实样本验证。
NOFOLLOW_LINKS 检查符号链接和文件类型。data 目录内的托管数据。AnalysisAccumulator 的操作、Namespace、模式、计划和客户端聚合 Map 会随不同值数量增长;原始行是流式的,但这些核心聚合并非全部固定容量。任何功能改动都必须同时检查以下位置:
CLAUDE.md 中是否存在不可破坏的统计、资源或隐私约束。README.md、用户指南、本文和 AI 改写指南是否需要同步。ROADMAP.md。更具体的 AI 开发流程见 AI 二次改写指南 。