自定义总结
通过 handleSummary()
,您可以完全自定义测试结束时的总结。本文档将介绍
handleSummary()
的工作原理- 如何自定义总结的内容和输出位置
- 总结对象的数据结构
注意
然而,我们计划也支持 Grafana Cloud 测试。 在此问题中跟踪进展。
关于 handleSummary()
测试运行后,k6 将您的指标聚合成一个 JavaScript 对象。handleSummary()
函数将此对象作为参数(在所有示例中称为 data
)。
您可以使用 handleSummary()
创建自定义总结或返回默认总结对象。要了解数据外观,请运行此脚本并打开输出文件 summary.json
。
import http from 'k6/http';
export default function () {
http.get('https://test.k6.io');
}
export function handleSummary(data) {
return {
'summary.json': JSON.stringify(data), //the default data object
};
}
从根本上说,handleSummary()
只是一个可以访问数据对象的函数。因此,您可以将总结数据转换为任何文本格式:JSON、HTML、控制台、XML 等。您可以将自定义总结管道到标准输出或标准错误,将其写入文件,或将其发送到远程服务器。
k6 在测试生命周期结束时调用 handleSummary()
。
使用 handleSummary()
以下部分将介绍 handleSummary()
语法并提供一些示例。
要查找总结对象的结构,请参考参考部分。
语法
k6 要求 handleSummary()
返回一个表示总结指标的 {key1: value1, key2: value2, ...}
映射。
键必须是字符串。它们决定了 k6 显示或保存内容的位置
stdout
用于标准输出stderr
用于标准错误,- 系统上文件的任何相对或绝对路径(此操作将覆盖现有文件)
键的值类型可以是 string
或 ArrayBuffer
。
您可以在一个脚本中返回多个总结输出。例如,此 return
语句将报告发送到标准输出,并将 data
对象写入 JSON 文件。
示例:提取数据属性
这个简单的 handleSummary()
提取 iteration_duration
指标的 median
值并将其打印到标准输出
import http from 'k6/http';
export default function () {
http.get('https://test.k6.io');
}
export function handleSummary(data) {
const med_latency = data.metrics.iteration_duration.values.med;
const latency_message = `The median latency was ${med_latency}\n`;
return {
stdout: latency_message,
};
}
示例:修改默认输出
如果导出了 handleSummary()
,k6 不会打印默认总结。但是,如果您想保留默认输出,可以从 K6 JS 工具库导入 textSummary
。例如,您可以将自定义 HTML 报告写入文件,并使用 textSummary()
函数将默认报告打印到控制台。
您也可以使用 textSummary()
对默认的测试结束总结进行微小修改。方法如下
- 按您需要修改
data
对象。 - 在您的
return
语句中,将修改后的对象作为参数传递给textSummary()
函数。
textSummary()
函数带有一些选项
选项 | 描述 |
---|---|
indent | 如何开始总结缩进 |
enableColors | 是否彩色打印总结。 |
例如,此 handleSummary()
通过以下方式修改默认总结
- 它删除
http_req_duration{expected_response:true}
子指标。 - 它删除所有键以
iteration
开头的指标。 - 它用
→
字符开始每一行。
import http from 'k6/http';
import { textSummary } from 'https://jslib.k6.io/k6-summary/0.0.2/index.js';
export default function () {
http.get('https://test.k6.io');
}
export function handleSummary(data) {
delete data.metrics['http_req_duration{expected_response:true}'];
for (const key in data.metrics) {
if (key.startsWith('iteration')) delete data.metrics[key];
}
return {
stdout: textSummary(data, { indent: '→', enableColors: true }),
};
}
比较默认报告和修改后的报告
为简洁起见,这些输出受 summaryTrendStats
选项限制。
默认报告如下
HTTP
http_req_blocked...............: med=10.39µs count=5 p(99)=451.07ms p(99.99)=469.67ms
http_req_connecting............: med=0s count=5 p(99)=223.97ms p(99.99)=233.21ms
http_req_duration..............: med=202.26ms count=5 p(99)=225.81ms p(99.99)=226.71ms
{ expected_response:true }...: med=202.26ms count=5 p(99)=225.81ms p(99.99)=226.71ms
http_req_failed................: 0.00% ✓ 0 ✗ 5
http_req_receiving.............: med=278.27µs count=5 p(99)=377.64µs p(99.99)=381.29µs
http_req_sending...............: med=47.57µs count=5 p(99)=108.42µs p(99.99)=108.72µs
http_req_tls_handshaking.......: med=0s count=5 p(99)=204.42ms p(99.99)=212.86ms
http_req_waiting...............: med=201.77ms count=5 p(99)=225.6ms p(99.99)=226.5ms
http_reqs......................: 5 3.352646/s
EXECUTION
iteration_duration.............: med=204.41ms count=5 p(99)=654.78ms p(99.99)=672.43ms
iterations.....................: 5 3.352646/s
vus............................: 1 min=1 max=1
vus_max........................: 1 min=1 max=1
NETWORK
data_received..................: 63 kB 42 kB/s
data_sent......................: 830 B 557 B/s
修改后的报告如下
HTTP
→ http_req_blocked...........: med=10.98µs count=5 p(99)=485.16ms p(99.99)=505.18ms
→ http_req_connecting........: med=0s count=5 p(99)=245.05ms p(99.99)=255.15ms
→ http_req_duration..........: med=208.68ms count=5 p(99)=302.87ms p(99.99)=306.61ms
→ http_req_failed............: 0.00% ✓ 0 ✗ 5
→ http_req_receiving.........: med=206.12µs count=5 p(99)=341.05µs p(99.99)=344.13µs
→ http_req_sending...........: med=47.8µs count=5 p(99)=166.94µs p(99.99)=170.92µs
→ http_req_tls_handshaking...: med=0s count=5 p(99)=207.2ms p(99.99)=215.74ms
→ http_req_waiting...........: med=208.47ms count=5 p(99)=302.49ms p(99.99)=306.23ms
→ http_reqs..................: 5 3.054928/s
EXECUTION
→ vus........................: 1 min=1 max=1
→ vus_max....................: 1 min=1 max=1
NETWORK
→ data_received..............: 63 kB 39 kB/s
→ data_sent..................: 830 B 507 B/s
示例:创建自定义文件格式
此脚本导入了一个辅助函数,将总结转换为 JUnit XML。输出是一个简短的 XML 文件,报告测试阈值是否失败。
import http from 'k6/http';
// Use example functions to generate data
import { jUnit } from 'https://jslib.k6.io/k6-summary/0.0.2/index.js';
import k6example from 'https://raw.githubusercontent.com/grafana/k6/master/examples/thresholds_readme_example.js';
export default k6example;
export const options = {
vus: 5,
iterations: 10,
thresholds: {
http_req_duration: ['p(95)<200'], // 95% of requests should be below 200ms
},
};
export function handleSummary(data) {
console.log('Preparing the end-of-test summary...');
return {
'junit.xml': jUnit(data), // Transform summary and save it as a JUnit XML...
};
}
跨越阈值的测试输出类似于
<?xml version="1.0"?>
<testsuites tests="1" failures="1">
<testsuite name="k6 thresholds" tests="1" failures="1"><testcase name="http_req_duration - p(95)<200"><failure message="failed" /></testcase>
</testsuite >
</testsuites >
示例:将数据发送到远程服务器
您还可以将生成的报告发送到远程服务器(通过 k6 支持的任何协议)。
import http from 'k6/http';
// use example function to generate data
import k6example from 'https://raw.githubusercontent.com/grafana/k6/master/examples/thresholds_readme_example.js';
export const options = { vus: 5, iterations: 10 };
export function handleSummary(data) {
console.log('Preparing the end-of-test summary...');
// Send the results to some remote server or trigger a hook
const resp = http.post('https://quickpizza.grafana.com/api/post', JSON.stringify(data));
if (resp.status != 200) {
console.error('Could not send summary, got status ' + resp.status);
}
}
注意
最后的示例使用了导入的辅助函数。这些函数可能会更改,因此请关注 jslib.k6.io 获取最新信息。
当然,我们也欢迎对 jslib 提交 PR!
总结数据参考
总结数据包含您的测试运行时间和所有内置和自定义指标(包括检查)的信息。
所有指标都在顶层 metrics
对象中。在此对象中,每个指标都有一个对象,其键是指标的名称。例如,如果您的 handleSummary()
参数名为 data
,则函数可以通过 data.metrics.http_req_duration
访问有关 http_req_duration
指标的对象。
指标 schema
下表描述了指标对象的 schema。具体值取决于指标类型
属性 | 描述 |
---|---|
type | 给出指标类型的字符串 |
contains | 描述数据的字符串 |
values | 包含总结指标值的对象(每个指标类型的属性不同) |
thresholds | 包含指标阈值信息的对象(如果适用) |
thresholds.{name} | 阈值名称 (object) |
thresholds.{name}.ok | 阈值是否被跨越 (boolean) |
注意
如果您使用
summaryTrendStats
选项更改默认的趋势指标,则趋势值的键将相应更改。
总结 JSON 示例
要查看您的特定测试运行中的总结 data
,请执行以下操作
将此添加到您的 handleSummary() 函数中
return { 'raw-data.json': JSON.stringify(data)};`
检查生成的
raw-data.json
文件。以下是一个简化的示例,它可能看起来像这样
{
"root_group": {
"path": "",
"groups": [
// Sub-groups of the root group...
],
"checks": [
{
"passes": 10,
"fails": 0,
"name": "check name",
"path": "::check name"
}
// More checks...
],
"name": ""
},
"options": {
// Some of the global options of the k6 test run,
// Currently only summaryTimeUnit and summaryTrendStats
},
"state": {
"testRunDurationMs": 30898.965069
// And information about TTY checkers
},
"metrics": {
// A map with metric and sub-metric names as the keys and objects with
// details for the metric. These objects contain the following keys:
// - type: describes the metric type, e.g. counter, rate, gauge, trend
// - contains: what is the type of data, e.g. time, default, data
// - values: the specific metric values, depends on the metric type
// - thresholds: any thresholds defined for the metric or sub-metric
//
"http_reqs": {
"type": "counter",
"contains": "default",
"values": {
"count": 40,
"rate": 19.768856959496336
}
},
"vus": {
"type": "gauge",
"contains": "default",
"values": {
"value": 1,
"min": 1,
"max": 5
}
},
"http_req_duration": {
"type": "trend",
"contains": "time",
"values": {
// actual keys depend depend on summaryTrendStats
"avg": 268.31137452500013,
"max": 846.198634,
"p(99.99)": 846.1969478817999
// ...
},
"thresholds": {
"p(95)<500": {
"ok": false
}
}
},
"http_req_duration{staticAsset:yes}": {
// sub-metric from threshold
"contains": "time",
"values": {
// actual keys depend on summaryTrendStats
"min": 135.092841,
"avg": 283.67766343333335,
"max": 846.198634,
"p(99.99)": 846.1973802197999
// ...
},
"thresholds": {
"p(99)<250": {
"ok": false
}
},
"type": "trend"
}
// ...
}
}
自定义输出示例
这些示例是社区贡献。感谢所有分享的人!