关于 k6-cloud-investigate-test
通过九步流程调查 Grafana Cloud k6 测试和运行结果的工作流型技能。它结合运行元数据、指标、日志和实际执行的脚本快照,并检查日期范围以及运行结果与脚本内检查的区别。
主要功能
- 01九步调查工作流
- 02分页发现测试运行
- 03核对日期范围是否匹配
- 04三层通过与失败分析
- 05检查指标、日志和脚本快照
适用场景
- 01调查失败或异常的测试运行
- 02比较通过与失败的运行
- 03确认近期运行是否符合指定时间范围
- 04追踪多次运行间的指标或脚本变化
MCP 相关
它通过 Grafana 插件代理调用 gcx API:REST 端点使用 v6,指标查询使用 v5。输入未说明它与 MCP 的关系。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ grafana/ skills --skill k6-cloud-investigate-test安装后在 Claude Code 中输入/k6-cloud-investigate-test确认已加载。
附带文件references/worked-example.md
详细介绍
k6 Cloud 测试调查
用于调查 Grafana Cloud k6 测试或运行的结构化 9 步工作流。
此技能仅包含工作流。所有 API 调用都通过 gcx api,针对插件代理执行;REST 使用 v6,指标使用 v5。有关底层机制(gcx 身份验证、路径约定、端点发现、日志查询、脚本编辑、阈值语义和注意事项),请参阅 k6-manage 技能——以下每个步骤都会引用它。
此技能独有的内容:
- 按顺序排列的调查流程(下文的步骤 1-9)
- 日期对齐检查(“过去 7 天” ≠ “最近 7 次运行”)
- 3 层通过/失败判定(
result与status,以及按检查项查询checks) - 一个包含实际数字的示例(
references/worked-example.md)
核心原则
- 先读后写。 执行任何 PUT 之前,务必先 GET 脚本。
gcx k6 load-tests update-script是一项写入操作,会用你传入的文件替换线上脚本——有用户仅仅为了“看看它访问的 URL”而运行该命令,结果导致生产脚本被覆盖。如果需要了解 URL,请改用带有-vvv --log-http-payload的任何非变更命令。 - 列举运行时要分页。
/test_runs端点最多返回 1000 行,而且gcx k6 runs list --limit 0不会自动跟进@nextLink。请使用k6-manage§3 中记录的gcx api循环。 - 核实日期范围。 用户提到“过去 7 天”“本周”或“最近的运行”时,确认最新运行的
created是否确实落在该时间范围内。如果不符,指出这一差距。 check()不会导致运行失败;只有thresholds才会。 而且,没有观测数据的阈值会报告为 ✓ 通过。完整说明请参阅下文的“阈值语义”;步骤 5 中按检查项查询checks指标可以捕获这两种情况。
前提条件
已安装 gcx,并已针对用户的堆栈完成身份验证。请参阅 k6-manage §1。使用以下命令验证:
gcx --context <stack> config check # expect "✔ Connectivity: online"
调查工作流
步骤 1:确定测试和目标运行
根据用户提供的 URL:
/a/k6-app/tests/<id>→ 负载测试(许多运行的父级)/a/k6-app/runs/<id>→ 某次特定运行
要从运行查找测试:通过 gcx api 获取运行;路径格式规则请参阅 k6-manage §2:
gcx --context <stack> api /api/plugins/k6-app/resources/cloud/cloud/v6/test_runs/<run_id>
然后从响应中读取 .test_id。要列出某个测试的运行,请参阅步骤 3。
步骤 2:获取测试元数据和脚本
gcx --context <stack> k6 load-tests get <test_id> -o json
获取脚本时,请按照 k6-manage §5 中安全编辑方法的 GET 部分操作——如果之后要编辑,请保存备份。
脚本有两个端点,这一区别对调查很重要。 k6-manage §5 对两者都有说明:当前负载测试脚本,以及每次运行实际执行的脚本快照。只要运行后编辑过脚本,两者就会出现差异。如果问题涉及“发生了什么变化”“为什么这次运行失败”,或者你要检查几天前的运行,也要通过 k6-manage §5 中的运行脚本端点获取运行捆绑的快照,并与当前负载测试脚本(或另一次运行的快照)进行差异比较。当前负载测试脚本并不是分析过去某次运行的正确依据。
步骤 3:列出运行并进行分页
针对 /cloud/v6/load_tests/<test_id>/test_runs,使用 k6-manage §3 中记录的 gcx api + @nextLink 循环模式。收集完 all_runs 后:
print(f"Total: {len(all_runs)}")
runs_sorted = sorted(all_runs, key=lambda r: r['created'], reverse=True)
for r in runs_sorted[:10]:
print(f" {r['created']:30s} id={r['id']:>8} status={r['status']:<10} result={r.get('result','?')}")
向用户报告:运行总数、日期范围、最近一次运行的日期。如果“最近一次运行”距今超过一天,请明确指出——用户可能以为定时任务仍在触发,实际上并没有。
步骤 4:确认日期范围符合用户意图
如果用户询问“过去 7 天”/“本周”/“最近”,应按日期范围筛选,而不是按行数筛选——“最近 7 次运行”可能涵盖一天,也可能涵盖一年,具体取决于测试运行的频率。
last7 = [r for r in all_runs if r['created'] >= '<today_minus_7_days_iso>']
如果 len(last7) == 0:立即告知用户。不要继续使用过时数据。
第 5 步:确定通过/失败状态
对于每次运行,检查以下三个相互独立的层面:
| 层面 | 字段 | 含义 |
|---|---|---|
| 运行级结果 | result(passed / failed / error / aborted) | 是否超出阈值 |
| 运行级状态 | status(completed / aborted) | 运行是否正常结束 |
| 脚本内检查 | v5 checks 指标,按 check 标签聚合 | 每项检查的成功率 |
如果用户认为某次运行“失败”,但报告的结果是 result: passed,请检查第三个层面。常见情况是:每次迭代的 check() 都返回 false,但由于没有为 checks 定义阈值,运行仍然“通过”。有关详细说明,请参阅下文的“阈值语义”(零观测陷阱、abortOnFail 的云端延迟、运算符支持)。
通过 v5 查询每项检查的细分结果(query_aggregate_k6 的参数格式见 k6-manage/references/metrics.md §7):
gcx --context <stack> api \
"/api/plugins/k6-app/resources/cloud/cloud/v5/test_runs/<run_id>/query_aggregate_k6(query='ratio by (check)',metric='checks')"
响应中的每个结果条目都带有一个 check 标签,其中包含检查名称和一个值:成功率(0.0–1.0)。如需获取原始成功/失败计数,也可查询 increase_nz by (check)(成功次数)和 increase_z by (check)(失败次数)。
第 6 步:获取运行指标
使用 k6-manage/references/metrics.md 中记录的 v5 指标端点。典型工作流:
# 6a. List metrics available for the run (metrics.md §1)
gcx --context <stack> api /api/plugins/k6-app/resources/cloud/cloud/v5/test_runs/<run_id>/metrics
# 6b. List labels for a metric to know what's available to filter/group by (metrics.md §4)
gcx --context <stack> api \
"/api/plugins/k6-app/resources/cloud/cloud/v5/test_runs/<run_id>/labels?match[]=http_req_duration"
# 6c. Time-series — pick a query method that matches the metric's type (metrics.md §6)
gcx --context <stack> api \
"/api/plugins/k6-app/resources/cloud/cloud/v5/test_runs/<run_id>/query_range_k6(query='histogram_quantile(0.95) by (name,status)',metric='http_req_duration',step=10)"
# 6d. Scalar aggregate over the whole run (metrics.md §7)
gcx --context <stack> api \
"/api/plugins/k6-app/resources/cloud/cloud/v5/test_runs/<run_id>/query_aggregate_k6(query='increase',metric='http_reqs')"
根据指标类型选择合适的查询方法很重要,详见 k6-manage/references/metrics.md 中的“查询方法”表格。对于浏览器测试,URL/状态细分来自 labels + label/{name}/values(metrics.md §4/§5),而不是单独的标签端点。
第 7 步:获取运行日志
遵循 k6-manage §4 中的 Loki 操作说明(使用 gcx api 请求 /api/plugins/k6-app/resources/logs/...,选择器为 {test_run_id="<id>"},必须带上 X-K6TestRun-Id 标头,将 start/end 范围限定在 run.created/run.ended)。将响应保存到 /tmp/run_<id>_logs.json,并按其中的说明根据该文件撰写摘要。
第 8 步:(如有要求)安全地编辑脚本
使用 k6-manage §5 中完整的安全编辑操作说明(GET → 备份 → 编辑 → k6 inspect → 1 次迭代的冒烟测试 → 使用 Content-Type: application/octet-stream 执行 PUT → 验证 sha256)。
如果编辑涉及阈值,还需阅读下文的“阈值语义”,了解零观测陷阱、abortOnFail 的云端延迟以及运算符支持情况(尽管文档未说明,==/!= 仍然有效)。
第 9 步:报告
根据问题类型选择模板。
单次运行调查(“运行 X 怎么了”):
Test: <name> (id <test_id>)
Run: <run_id> @ <created> → <ended>, load_zone=<zone>, result=<result>
Logs (<n> streams, <m> lines):
- <stream summary>
Metrics (key indicators):
- <metric>: <method> = <value> (n=<count>)
...
Per-check breakdown:
- <check name>: <success_rate> (succ=<n>, fail=<n>)
...
Diagnosis: <one-paragraph>
多次运行对比(“通过和失败的运行之间有哪些不同”“这个改动导致了失败吗”):
Question: <one-line restatement of what the user is trying to attribute>
Run timeline (relevant window):
| Run ID | Created (UTC) | Result | exec_duration | processing_duration | k6 build | error code | key check ratios |
|---|---|---|---|---|---|---|---|
| ... | ... | passed | 60s | 195s | <build> | — | 1.0/1.0/1.0 |
| ... | ... | failed | 27s | 193s | <build> | — | 0.0/n=0/n=0 |
| ... | ... | error | 51s | 3601s aborted | <build> | 8016 | 1.0/1.0/1.0 |
Differences that matter:
- <field>: <value-in-passing> vs <value-in-failing> — <interpretation>
...
Script diff (if relevant): <bundled-script diff between a representative passing and failing run, summarised>
Diagnosis: <one-paragraph attributing the change to test-side, SUT-side, or platform-side, with the supporting evidence>
该表格能清楚展示并排异常(例如,通过和失败的运行中某列的值相同,就能排除该维度是原因;某列的值在两者之间变化,就可能是原因)。
如果用户要求导出原始数据,也请将其保存到 /tmp/k6inv/run<id>/,并告知相应路径。
阈值语义
决定运行 result 的是阈值,而不是 check() 调用。这里有几个容易误导初次调查者、不太直观的情况,因此集中说明如下。第 5 步(“确定通过/失败状态”)和第 8 步(“安全地编辑脚本”)都依赖本节内容。
result 的含义
result 值 | 含义 |
|---|---|
passed | 所有阈值均通过(或未定义任何阈值) |
failed | 至少有一个阈值未通过 |
error | 脚本在完成前崩溃(例如,浏览器无法启动),或者 k6 Cloud 在平台端中止了运行。要判断是哪种情况,请检查该次运行中的 status_history[*].extra.code — 非空代码表示平台中止(例如,在 processing_metrics 期间,8016 = “测试运行超过最长持续时间”)。平台中止并非代码的问题,尽管它们会显示为 error。 |
aborted | 用户或系统中止了运行 |
check() 调用不会直接影响 result。它们会将观测结果写入内置的 checks 速率指标,之后阈值可以对其进行评估。如果没有阈值引用 checks,检查失败不会反映在运行级别的 result 中。
“零观测 = 通过”陷阱
当底层指标没有样本时,k6 会将阈值报告为 ✓ 通过 — 即使阈值表达式本应求值为 false:
checks{check:response is 200}
✓ 'rate==1.0' rate=0.00% ← ✓ pass!?
如果脚本在执行到相关的 check() 调用之前抛出异常,就会遇到这个问题。在 catch 块中强制记录一次检查观测,让阈值能够看到一些内容:
try {
const r = await page.goto(URL);
check(r, { "response is 200": x => x.status() === 200 });
// ... rest of iteration body
check(true, { "script completed without exception": () => true });
} catch (e) {
console.error(e);
check(null, { "script completed without exception": () => false });
} finally {
await page.close();
}
然后将 'checks{check:script completed without exception}': ['rate==1.0'] 添加到阈值中。这样既能捕获导航失败,也能捕获后续阶段的异常。
abortOnFail 云端延迟
k6 在云端运行时,每 60 秒评估一次阈值。
abortOnFail功能最多可能延迟 60 秒。
对于短于 60 s 的运行,迭代可能自然结束,导致 abortOnFail 尚未触发。阈值仍会在运行结束时进行评估,且 result 会变为 failed — 只是中止无法节省执行时间。
运算符
文档中展示了 <、>、<=、>=。== 和 != 也可用,尽管文档中没有列出。对于 rate 指标(值为 0.00–1.00),rate==1.0 表示“每次观测都非零”,而 rate==0 表示“所有观测均为零”。
特定工作流的注意事项
规范注意事项列表(认证过期、重复的 cloud/cloud/、脚本 PUT 返回 415、Loki 缺少 X-K6TestRun-Id、脚本 PUT 不会更新 updated、gcx k6 runs list --limit 0 不会跟进 @nextLink)请参阅 k6-manage §7。以下条目仅适用于本次调查工作流:
| 症状 | 原因 | 解决方法 |
|---|---|---|
| “最新一次运行是 6 个月前”,但计划显示为每天运行 | 你没有对 /test_runs 进行分页 | 使用 k6-manage §3(步骤 3)中的 @nextLink 循环 |
| “最近 7 天”报告只包含较早的运行记录 | 按行数而非日期进行筛选 | 按 created >= <iso_date> 重新筛选(步骤 4) |
| 阈值报告显示 ✓ 通过,但检查失败 | 检查观测数为零;迭代在运行 check() 前已中止 | 请参阅上文“阈值语义” |
result: error,但脚本日志/指标看起来正常 | 很可能是平台中止(例如 processing_metrics 超过 1 小时上限,code 8016)。执行本身已正常完成。 | 检查该次运行中的 status_history[*].extra.code。平台代码非空 → 不是你的代码导致的。请参阅“阈值语义” |
| 通过读取当前负载测试脚本来调查过去的运行 | 运行执行后脚本可能已被编辑——你读到的并非当时实际运行的内容 | 通过每次运行对应的端点获取该次运行打包后的脚本(k6-manage §5),并与当前负载测试脚本进行差异比较后再下结论 |
| 刚刚覆盖了用户的脚本 | 调用了 update-script 来“查看 URL” | 从步骤 2 中创建的备份恢复。若要在不写入的情况下了解 URL,请对任何非变更命令使用 -vvv --log-http-payload。 |
CLI --iterations 1 破坏了浏览器场景 | 它会完全覆盖场景块 | 改用 sed 在文件中编辑 iterations: |
参考资料
references/worked-example.md— 一份合成调查示例,包含逼真的调查结果,可用作步骤 9 报告的模板。