菜单
开源

自定义总结

通过 handleSummary(),您可以完全自定义测试结束时的总结。本文档将介绍

  • handleSummary() 的工作原理
  • 如何自定义总结的内容和输出位置
  • 总结对象的数据结构

注意

然而,我们计划也支持 Grafana Cloud 测试。 在此问题中跟踪进展

关于 handleSummary()

测试运行后,k6 将您的指标聚合成一个 JavaScript 对象。handleSummary() 函数将此对象作为参数(在所有示例中称为 data)。

您可以使用 handleSummary() 创建自定义总结或返回默认总结对象。要了解数据外观,请运行此脚本并打开输出文件 summary.json

JavaScript
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 用于标准错误,
  • 系统上文件的任何相对或绝对路径(此操作将覆盖现有文件)

键的值类型可以是 stringArrayBuffer

您可以在一个脚本中返回多个总结输出。例如,此 return 语句将报告发送到标准输出,并将 data 对象写入 JSON 文件。

示例:提取数据属性

这个简单的 handleSummary() 提取 iteration_duration 指标的 median 值并将其打印到标准输出

JavaScript
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() 对默认的测试结束总结进行微小修改。方法如下

  1. 按您需要修改 data 对象。
  2. 在您的 return 语句中,将修改后的对象作为参数传递给 textSummary() 函数。

textSummary() 函数带有一些选项

选项描述
indent如何开始总结缩进
enableColors是否彩色打印总结。

例如,此 handleSummary() 通过以下方式修改默认总结

  • 它删除 http_req_duration{expected_response:true} 子指标。
  • 它删除所有键以 iteration 开头的指标。
  • 它用 字符开始每一行。
JavaScript
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 }),
  };
}

比较默认报告和修改后的报告

示例:创建自定义文件格式

此脚本导入了一个辅助函数,将总结转换为 JUnit XML。输出是一个简短的 XML 文件,报告测试阈值是否失败。

JavaScript
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
<?xml version="1.0"?>
<testsuites tests="1" failures="1">
<testsuite name="k6 thresholds" tests="1" failures="1"><testcase name="http_req_duration - p(95)&lt;200"><failure message="failed" /></testcase>
</testsuite >
</testsuites >

示例:将数据发送到远程服务器

您还可以将生成的报告发送到远程服务器(通过 k6 支持的任何协议)。

JavaScript
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,请执行以下操作

  1. 将此添加到您的 handleSummary() 函数中

    return { 'raw-data.json': JSON.stringify(data)};`
  2. 检查生成的 raw-data.json 文件。

    以下是一个简化的示例,它可能看起来像这样

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"
    }
    // ...
  }
}

自定义输出示例

这些示例是社区贡献。感谢所有分享的人!