بنقرة واحدة
apm-trace-analysis
// 蓝鲸监控 APM 调用链分析专家。通过蓝鲸监控平台的 bkmonitor-tracing MCP 服务中的 search_spans 工具,查询和分析 APM Span 数据。当需要:(1) 通过 trace_id/request_id 查询完整调用链,(2) 定位调用链中的 Error Span 和耗时异常 Span,(3) 分析微服务间的调用关系和错误传播路径,(4) 结合 APM 数据辅助排查作业平台任务执行异常时使用。
// 蓝鲸监控 APM 调用链分析专家。通过蓝鲸监控平台的 bkmonitor-tracing MCP 服务中的 search_spans 工具,查询和分析 APM Span 数据。当需要:(1) 通过 trace_id/request_id 查询完整调用链,(2) 定位调用链中的 Error Span 和耗时异常 Span,(3) 分析微服务间的调用关系和错误传播路径,(4) 结合 APM 数据辅助排查作业平台任务执行异常时使用。
经 APIGW 调用蓝鲸作业平台(BK-Job)开放接口,支持检索定时任务与最近定时执行的状态/日志、执行方案搜索与带参启动、按实例 ID 查询任务状态与执行日志。列举类查询默认先最近 20 条;大列表在本地用 jq 或短脚本过滤后再摘要。含 plan-execute 操作确认门禁(G1–G4)、对用户输出规范与可选业务记忆 memory/businesses。技能包以含 SKILL.md 的目录为根,可部署在 Cursor、CodeBuddy、OpenClaw 等任意技能加载路径下,脚本与文档路径均相对该根目录。当用户提及作业平台、蓝鲸作业、定时任务、cron、执行方案、job_plan、job_instance、APIGW 调用作业接口、执行作业方案时使用。
蓝鲸作业平台日志查询专家。当需要:(1) 编写 KQL 查询语句查询作业执行日志,(2) 排查任务执行失败问题,(3) 分析 GSE/CMDB 调用问题,(4) 查看任务完整链路日志时使用。提供 KQL 语法指导和常用查询模板。
蓝鲸作业平台任务耗时分布分析专家。当用户需要:(1) 分析任务各阶段耗时分布,(2) 定位任务执行中的性能瓶颈,(3) 了解任务执行链路和各阶段涉及的中间件,(4) 生成任务耗时分布统计报告时使用。基于六阶段模型,通过 request_id 查询完整链路日志进行分析。
| name | apm-trace-analysis |
| description | 蓝鲸监控 APM 调用链分析专家。通过蓝鲸监控平台的 bkmonitor-tracing MCP 服务中的 search_spans 工具,查询和分析 APM Span 数据。当需要:(1) 通过 trace_id/request_id 查询完整调用链,(2) 定位调用链中的 Error Span 和耗时异常 Span,(3) 分析微服务间的调用关系和错误传播路径,(4) 结合 APM 数据辅助排查作业平台任务执行异常时使用。 |
使用蓝鲸监控平台 bkmonitor-tracing MCP 服务的 search_spans 工具,查询和分析 APM 调用链数据。
通过 use_mcp_tool 调用,serverName 为 bkmonitor-tracing,toolName 为 search_spans。
所有参数封装在 body_param 对象中:
| 参数 | 必填 | 类型 | 说明 |
|---|---|---|---|
app_name | ✅ | string | APM 应用名称(从 Prompt 的「环境参数」部分获取 <app_name> 的实际值) |
bk_biz_id | ✅ | string | 蓝鲸业务 ID(从 Prompt 的「环境参数」部分获取 <bk_biz_id> 的实际值) |
start_time | ✅ | string | 开始时间戳(秒),根据上下文自行确定合适的时间。与 end_time 的差值 ≤ 86400 |
end_time | ✅ | string | 结束时间戳(秒),根据上下文自行确定合适的时间。与 start_time 的差值 ≤ 86400 |
filters | 否 | array | 过滤条件数组,详见下方 |
limit | 否 | string | 返回最大 Span 数,固定传 "10" |
offset | 否 | string | 分页偏移量,默认 "0" |
sort | 否 | array | 排序条件,默认 ["-elapsed_time"](耗时降序) |
start_time 和 end_time。不要固定从当前时间往前算,而应根据实际场景选择最合理的时间窗口end_time - start_time 必须 ≤ 86400(即 60×60×24 秒)。如果超过此限制,API 会报错。如果需要查询的 trace 发生在较早的时间,应将 start_time 和 end_time 设为包含该时间点的 1 天窗口内,而非从当前时间往前算"10":避免返回内容过大导致 token 超限每个 filter 对象结构:
{
"key": "字段名",
"operator": "操作符",
"value": [值数组],
"options": { "group_relation": "AND" } // 可选,多 filter 时建议加
}
常用操作符:equal、not_equal、like
常用 filter key:
| key | 说明 | 示例 value |
|---|---|---|
trace_id | 链路追踪 ID | ["b0a9Ce0e-xxxx"] |
status.code | Span 状态码(0=正常, 2=错误) | [2] |
parent_span_id | 父 Span ID,用于查询某个 Span 的子 Span | ["c4df181a145794de"] |
resource.service.name | 服务名 | ["job-execute"] |
span_name | Span 操作名 | ["POST"] |
attributes.http.status_code | HTTP 状态码 | [500] |
attributes.http.method | HTTP 方法 | ["POST"] |
这是最核心的查询——通过 request_id(即 trace_id)获取完整调用链。
{
"serverName": "bkmonitor-tracing",
"toolName": "search_spans",
"arguments": "{\"body_param\":{\"app_name\":\"<app_name>\",\"bk_biz_id\":\"<bk_biz_id>\",\"start_time\":\"{根据上下文确定}\",\"end_time\":\"{根据上下文确定}\",\"filters\":[{\"key\":\"trace_id\",\"operator\":\"equal\",\"value\":[\"{trace_id}\"]}],\"limit\":\"10\",\"offset\":\"0\"}}"
}
当只关心出错的 Span 时,增加 status.code = 2 的过滤:
{
"filters": [
{
"key": "status.code",
"operator": "equal",
"value": [2],
"options": { "group_relation": "AND" }
},
{
"key": "trace_id",
"operator": "equal",
"value": ["{trace_id}"],
"options": { "group_relation": "AND" }
}
],
"limit": "10"
}
如果调用链较长(Span 数 > 10),通过 offset 分页:
"offset": "0", "limit": "10""offset": "10", "limit": "10"当发现某个 Error Span 或耗时异常 Span 后,可以通过 parent_span_id 过滤来查询它的子 Span,观测子 Span 的指标和行为,判断是否是导致父 Span 异常的根因。
{
"filters": [
{
"key": "parent_span_id",
"operator": "equal",
"value": ["{目标Span的span_id}"],
"options": { "group_relation": "AND" }
},
{
"key": "trace_id",
"operator": "equal",
"value": ["{trace_id}"],
"options": { "group_relation": "AND" }
}
],
"limit": "10"
}
逐层下钻方法:
span_id=A,status.code=2),用 parent_span_id=A 查询其子 Spanspan_id=B),用 parent_span_id=B 继续查询其子 Span(即 Error Span 的孙子 Span)逐层下钻示意图:
[Error Span A] status.code=2, exception=Read timed out
↓ 查询 parent_span_id=A 的子 Span
└── [Span B] status.code=0, elapsed_time=692s ⚠️ 耗时异常
↓ 查询 parent_span_id=B 的子 Span(孙子 Span)
├── [Span C] MongoDB update (elapsed_time=0.99s) ✅
├── [Span D] MongoDB update (elapsed_time=1.01s) ✅
└── ... 发现大量串行 MongoDB 操作 → 根因:批量串行写入
💡 关键技巧:通过不断替换
parent_span_id的值为下一层 Span 的span_id,可以沿着调用树逐层下钻,精准定位到导致上层 Error 或耗时异常的最底层根因。
⚠️ 重要提示:以
response_body.data.data数组为准,忽略response_body.data.total
search_spans返回的 JSON 结构中,response_body.data.total字段不准确,不能反映真实查到的 Span 数量。例如实际查到 2 条 Span 数据,但total可能返回 0。正确做法:始终以
response_body.data.data数组中的实际元素为准来判断查询结果,不要依赖total字段做任何判断(如是否有更多数据需要分页、是否查询为空等)。
| 字段 | 含义 | 分析要点 |
|---|---|---|
trace_id | 链路 ID | 同一请求的所有 Span 共享此 ID |
span_id | 当前 Span 的唯一 ID | 用于构建调用拓扑 |
parent_span_id | 父 Span ID | 核心:通过 parent-child 关系还原调用树 |
span_name | 操作名称 | 如 POST、SELECT、update xxx |
resource.service.name | 所属服务名 | 如 job-execute、job-logsvr |
status.code | 状态码 | 0=正常, 2=错误 |
status.message | 状态消息 | 错误时包含简要说明 |
elapsed_time | 耗时(微秒) | 692498971 微秒 ≈ 692 秒 ≈ 11.5 分钟 |
start_time / end_time | 起止时间(微秒时间戳) | 用于排序和时间线分析 |
kind | Span 类型 | 2=SERVER, 3=CLIENT |
events.attributes.exception.type | 异常类型 | 如 java.net.SocketTimeoutException |
events.attributes.exception.message | 异常消息 | 如 Read timed out |
events.attributes.exception.stacktrace | 异常堆栈 | 完整的 Java Stack Trace |
attributes.http.method | HTTP 方法 | GET/POST 等 |
attributes.http.path | 请求路径 | 如 /service/log/batch |
attributes.http.status_code | HTTP 状态码 | 200/500 等 |
resource.k8s.pod.name | K8S Pod 名 | 定位具体实例 |
elapsed_time 的单位是微秒(μs):
692498971 μs = 692.5 秒 ≈ 11.5 分钟拿到 Span 数据后,按以下步骤分析:
通过 span_id 和 parent_span_id 的对应关系,构建调用拓扑:
[Root Span] span_id=A, parent_span_id=""
├── [Child Span] span_id=B, parent_span_id=A
│ ├── [Grandchild Span] span_id=C, parent_span_id=B
│ └── [Grandchild Span] span_id=D, parent_span_id=B
└── [Child Span] span_id=E, parent_span_id=A
筛选 status.code = 2 的 Span,这些是出错的环节。重点关注:
events.attributes.exception.type:异常类型events.attributes.exception.message:异常消息events.attributes.exception.stacktrace:异常堆栈对所有 Span 按 elapsed_time 排序,找出耗时显著偏高的 Span。对比:
关键分析逻辑:Error Span 不一定是根因,需要结合耗时分析:
示例:
[Span A] job-execute → POST /service/log/batch (status.code=2, 异常: Read timed out)
└── [Span B] job-logsvr → POST /service/log/batch (status.code=0, elapsed_time=692秒)
分析:
SocketTimeoutException: Read timed out),是表象⚠️ 不要只看 Error Span:error 是结果(表象),耗时异常才可能是原因(根因)。通过
parent_span_id找到 Error Span 的子 Span,分析其耗时是否异常。
输出结构化结论:
**APM 调用链分析**:
- 调用拓扑:`{服务A}` → `{服务B}` → `{服务C/中间件}`
- Error Span:`{Span名称}`(服务:{service.name},异常:{exception.type}: {exception.message})
- 耗时异常 Span:`{Span名称}`(服务:{service.name},耗时:{elapsed_time换算后})
- 根因判定:{结合 Error Span 和耗时异常 Span 的综合分析结论}
如果 search_spans 工具不可用或查询无结果(该请求可能未被 APM 采样到),跳过 APM 分析步骤,直接从日志分析入手,不影响整体分析流程。
详细的查询示例和输出解析,参见 references/search-spans-examples.md。