Performance Metrics
Testkube automatically collects performance metrics from major performance testing tools; k6, Artillery, and JMeter are currently supported; the sections below describe how to export reports and collect them as workflow artifacts for each tool. Ready-to-run workflows are in the Basic K6, Basic Artillery, and Basic JMeter examples.
For other tools, or when you need metrics that do not map to a built-in report format, use Influx Line Protocol instead.
The metrics exported by each tool will differ, but you can chart the values you care about and see how they change over time.
For example, charting http_req_duration_p95_ms segmented by Scenario helps you compare p95 latency across load profiles and spot regressions in a single scenario.
k6 Summary Integration
k6 can export a machine-readable summary with the --summary-export flag. To make that summary available as
granular metrics in Testkube:
- Export the summary JSON into an artifact directory.
- Include the JSON file in the workflow artifacts.
- Run the workflow normally.
Testkube detects k6 summary JSON files during artifact post-processing and registers them as k6.summary reports.
The control plane then ingests the report into granular metric series.
For a complete workflow that exports summary.json and uploads it as an artifact, see the
Basic K6 Example.
After the workflow finishes, the summary file remains available as a normal artifact, and Testkube stores the detected k6 metrics as granular series.
k6 Metric Names
Testkube normalizes k6 metric names and summary statistics so they are stable in Insights and API responses. Common examples include:
| k6 summary field | Testkube metric key |
|---|---|
http_req_duration.values["p(95)"] | http_req_duration_p95_ms |
http_req_duration.values.avg | http_req_duration_avg_ms |
http_reqs.values.count | http_reqs_count |
http_reqs.values.rate | http_reqs_rate |
checks.values.passes | checks_passes |
checks.values.fails | checks_fails |
iteration_duration.values.avg | iteration_duration_avg_ms |
Timing metrics are stored in milliseconds. Counter and rate metrics keep their k6 summary values.
Tagged k6 Metrics
k6 can emit tagged metric summaries, for example separate http_req_duration values for successful responses or
custom tags. Testkube preserves stable tag dimensions as series identity fields. This lets you compare the same
metric overall and for a tagged subset when the k6 summary contains those tagged metrics.
For example, a tagged k6 summary metric can produce separate series for:
http_req_duration_p95_mswith no identity fields.http_req_duration_p95_mswith an identity such asexpected_response=true.http_req_duration_p95_mswithscenario=homepageorscenario=docs, when the script defines named scenarios and asks k6 to include those scenario-tagged submetrics in the summary.http_req_duration_p95_mswithendpoint=test-workflow-with-executions-list, when the script tags requests by endpoint and asks k6 to include those endpoint-tagged submetrics in the summary.
k6 does not include every possible tag combination in summary.json automatically. If you need scenario-level or
endpoint-level series in Insights, define the tag values and add thresholds
for the metric/tag combinations you want to chart—for example,
http_req_duration{scenario:homepage} or http_reqs{endpoint:my-operation}.
For endpoint-level metrics, tag each request (for example with tags: { endpoint: "my-operation" }) and add a
matching threshold. The tag key can be any stable name, but endpoint is useful for API and UI performance tests
because it lets Insights split latency by logical operation instead of by raw URL.
Testkube stores tagged summaries as metric keys such as http_req_duration_p95_ms with identity
endpoint=test-workflow-with-executions-list, so the same measure can be segmented or filtered by Endpoint in
Insights.
Use tags intentionally. High-cardinality tags, such as unique URLs or request IDs, can create many metric series and make analysis harder.
Distributed k6 Workflows
For distributed k6 workflows, each worker should write a unique summary filename and upload it as an artifact.
This avoids workers overwriting each other's summary file. See the
Distributed K6 Example for a workflow that exports per-worker
summary-worker-*.json files alongside the HTML dashboard.
Each uploaded k6 summary report is ingested into granular metric series for the workflow execution.
k6 Troubleshooting
If k6 metrics do not appear in Insights:
- Confirm that the k6 command includes
--summary-export. - Confirm that the exported JSON file is included in
artifacts.paths. - Use a
.jsonfile extension for the summary export. - Keep the summary file non-empty and in k6 summary JSON format.
- Check the workflow execution artifacts to confirm the summary file was uploaded.
The summary file can be uploaded alongside other artifacts, such as the k6 HTML dashboard report.
Artillery Report Integration
Artillery can export a machine-readable JSON report with the -o flag. To make that report available as granular
metrics in Testkube:
- Export the Artillery report JSON into an artifact directory.
- Include the JSON file in the workflow artifacts.
- Run the workflow normally.
Testkube detects Artillery JSON files with numeric aggregate metrics under counters, rates, summaries, or
histograms during artifact post-processing and registers them with the artillery.report report type. The control
plane then ingests the report into granular metric series.
For a complete workflow that writes an Artillery JSON report with -o and uploads it as an artifact, see the
Basic Artillery Example.
After the workflow finishes, the report file remains available as a normal artifact, and Testkube stores the detected Artillery aggregate metrics as granular series.
Artillery Metric Names
Testkube normalizes Artillery aggregate metric names and statistics into stable metric keys. Common examples include:
| Artillery report field | Testkube metric key |
|---|---|
aggregate.counters["http.requests"] | http_requests |
aggregate.counters["vusers.created"] | vusers_created |
aggregate.rates["http.request_rate"] | http_request_rate |
aggregate.summaries["http.response_time"].min | http_response_time_min_ms |
aggregate.summaries["http.response_time"].p95 | http_response_time_p95_ms |
aggregate.histograms["http.response_time"].p99 | http_response_time_p99_ms |
aggregate.histograms["vusers.session_length"].p99 | vusers_session_length_p99 |
aggregate.scenariosCreated | scenarios_created |
aggregate.requestsCompleted | requests_completed |
aggregate.codes["200"] | codes_200 |
aggregate.errors.ETIMEDOUT | errors_etimedout |
aggregate.latency.p95 | latency_p95_ms |
aggregate.rps.mean | rps_mean |
aggregate.scenarioDuration.p95 | scenario_duration_p95_ms |
aggregate.counters["vusers.created_by_name.homepage"] | vusers_created with scenario=homepage |
aggregate.scenarioCounts.homepage | scenario_counts with scenario=homepage |
aggregate.summaries["plugins.metrics-by-endpoint.response_time.//"].p95 | http_response_time_p95_ms with transaction=/ |
aggregate.counters["plugins.metrics-by-endpoint.//.codes.200"] | http_codes_200 with transaction=/ |
Latency, response-time, and duration metrics are stored in milliseconds when they include a statistic, such as
min, max, median, p95, or p99. Counter and rate metrics keep their Artillery report values.
The control plane also understands common Artillery aggregate fields such as latency, rps, and
scenarioDuration when those fields are present in a report.
Artillery Segmentation
Artillery metrics can use Scenario and Transaction as identity fields when the uploaded report includes those dimensions. This lets Insights split or filter Artillery report metrics by the logical scenario or endpoint that produced the measurement.
Scenario identities are created from named Artillery scenarios. For example, a scenario named homepage can appear
in the JSON report as vusers.created_by_name.homepage, and Testkube stores the name as scenario=homepage.
Transaction identities are created from endpoint-level Artillery metrics, such as
plugins.metrics-by-endpoint.response_time.// and plugins.metrics-by-endpoint.//.codes.200. Testkube stores the
endpoint as the transaction identity, so the root endpoint // is shown as transaction=/.
Scenario and transaction identities are optional per metric. Artillery aggregate metrics that do not carry scenario
or transaction context are still stored as workflow-level series. For example, global http.response_time values are
available as overall latency metrics, while plugins.metrics-by-endpoint.response_time.<endpoint> values can be
segmented by Transaction. If a Scenario or Transaction filter returns no series for a selected Artillery metric, check
whether the uploaded report contains that identity for the metric key you are charting.
Distributed Artillery Workflows
For distributed Artillery workflows, each worker should write a unique JSON report filename and upload those files as artifacts. Testkube detects each uploaded Artillery report independently.
Artillery Troubleshooting
If Artillery metrics do not appear in Insights:
- Confirm that the Artillery command includes
-o <report-file>. - Confirm that the exported JSON file is included in
artifacts.paths. - Use a
.jsonfile extension for the report. - Keep the report non-empty and in Artillery aggregate JSON format, with numeric aggregate metrics under
counters,rates,summaries, orhistograms. - Check the workflow execution artifacts to confirm the report file was uploaded.
JMeter Statistics Integration
JMeter can generate a dashboard report with the -e and -o flags. That dashboard includes a machine-readable
statistics.json file. To make JMeter statistics available as granular metrics in Testkube:
- Run JMeter with
-e -o <report-directory>. - Put the report directory under an artifact directory.
- Include the report directory in the workflow artifacts.
Testkube detects JMeter dashboard statistics.json files during artifact post-processing and registers them as
jmeter.statistics reports. The control plane then ingests the report into granular metric series.
For a complete workflow that runs JMeter with -e -o and uploads the dashboard directory (including
statistics.json) as artifacts, see the Basic JMeter Example.
After the workflow finishes, the dashboard files remain available as normal artifacts, and Testkube stores the
detected JMeter statistics as granular series. The detected report file is typically
report/statistics.json or artifacts/report/statistics.json, depending on the artifact working directory.
JMeter Metric Names
Testkube normalizes JMeter dashboard statistics into stable metric keys. Common examples include:
| JMeter statistics field | Testkube metric key |
|---|---|
sampleCount | sample_count |
errorCount | error_count |
errorPct | error_pct |
meanResTime | response_time_mean_ms |
medianResTime | response_time_median_ms |
minResTime | response_time_min_ms |
maxResTime | response_time_max_ms |
pct1ResTime | response_time_p90_ms |
pct2ResTime | response_time_p95_ms |
pct3ResTime | response_time_p99_ms |
throughput | throughput |
receivedKBytesPerSec | received_kbytes_per_sec |
sentKBytesPerSec | sent_kbytes_per_sec |
Response-time metrics are stored in milliseconds. JMeter transaction labels, including Total, are stored as
series identity fields so each transaction can be compared across workflow executions.
JMeter Troubleshooting
If JMeter metrics do not appear in Insights:
- Confirm that the JMeter command includes
-e -o <report-directory>. - Confirm that the generated dashboard contains
statistics.json. - Confirm that the report directory is included in
artifacts.paths. - Keep the
statistics.jsonfile non-empty and in JMeter dashboard statistics format. - Check the workflow execution artifacts to confirm the report directory was uploaded.