Performance Testing
Advanced 12 min read Performance Testing

Performance Reporting & SLOs

Performance reporting turns raw test output into decisions: the same metrics framed as SLOs with pass/fail budgets, drift trends and root-cause context. Learn to encode SLOs as thresholds, export machine-readable verdicts, and publish them to CI and dashboards.

SLOthresholderror budgetsummary exportdashboardrelease gate
Prerequisites: Metrics & Baselines
Introduction

What is this?

Performance reporting turns raw test output into decisions: it presents the same metrics as SLOs with pass/fail budgets, drift trends and root-cause context so engineers and management can act. Reporting artifacts include the machine-readable summary, a human dashboard (Grafana), and an SLO statement like 'p95 under 250ms with under 1% errors over the load test window'. Done well, a report answers 'is this version shippable?' at a glance.

Motivation

Why do you need it?

  • An SLO gives every run a binary verdict against a target, which is what CI gates and release reviews actually need.
  • Trend reports catch slow degradation that single runs hide — the 'it was fine in April' problem.
  • Reports tied to the git SHA and environment make release comparisons reproducible and auditable.
  • SLO-style error budgets create accountability: teams know how much 'bad' performance they can tolerate before acting.
  • Shared dashboards align engineering and management on the same numbers instead of competing anecdotes.
Think about it

Mental model

Imagine

A pilot's instrument panel

Think of

A performance report

The pilot doesn't get a spreadsheet of raw telemetry; they get calibrated gauges with colored limits. A good report is the same: the key metrics, their budgets, and the alert color — nothing more.

Mechanics

How it works

  • Define the SLOs as threshold expressions (e.g. http_req_failed rate<0.01 and http_req_duration p(95)<250).
  • Run the test and export machine-readable results with --summary-export or --out json.
  • Store results with metadata: git SHA, environment, load model and timestamp.
  • Compute pass/fail and percentiles, and push metrics to a time-series store (InfluxDB or Prometheus) for dashboards.
  • Publish the verdict — CI exit code, dashboard panel, release note — with the before/after delta.

From SLO definition to a published verdict.

Define SLOs
Run test
Export results
Store with metadata
Compute verdict
Publish
Reference

Key commands

k6 run --summary-export summary.json script.js

Write a machine-readable summary for reporting tools and release gates.

A JSON document containing metrics, thresholds and grouped results.
k6 run --out influxdb=http://localhost:8086/k6 script.js

Push every metric to InfluxDB so Grafana can render dashboards.

k6 run --out prometheus-rw=http://prometheus:9090/api/v1/write script.js

Remote-write results to Prometheus for long-term retention and alerting.

jq -r '.metrics.http_req_failed.values.rate' summary.json

Extract a single verdict value for release gating scripts.

git rev-parse --short HEAD

Capture the code version to stamp into the report metadata.

a1b2c3d
Hands-on

Examples

Threshold budgets and a CI-consumable SLO gate

Threshold budgets and a CI-consumable SLO gate
import http from "k6/http"
import { sleep } from "k6"
export const options = {
vus: 100,
duration: "10m",
thresholds: {
http_req_failed: [{ threshold: "rate<0.01", abortOnFail: true }],
http_req_duration: ["p(95)<250", "p(99)<600", "max<2000"],
iterations: ["rate>50"],
},
}
export default function () {
http.get("https://api.example.com/v1/items")
sleep(1)
}

The SLO is encoded as thresholds: at most 1% errors (aborting the run early if breached), p95 under 250ms, p99 under 600ms, and at least 50 iterations per second. The run's exit code and --summary-export JSON then feed CI gates and dashboards without further interpretation.

Real world

In production

  • CI runs the SLO test on every merge and blocks the build when the exit code is non-zero.
  • Grafana dashboards overlay each nightly test's p95/p99 against the error-budget line so drift is visible.
  • Release notes include the before/after percentile delta stamped with the git SHA.
  • Weekly SLO review consumes the summary exports to spot capacity trends before launch events.
Guidelines

Best practices

  • Encode every SLO as a threshold expression so the verdict needs no human interpretation.
  • Stamp every report with git SHA, environment and load model before storing.
  • Keep one canonical dashboard; conflicting numbers from different tools breed distrust.
  • Report error rate and throughput alongside latency — a fast-but-failing system is still failing.
  • Retain raw summary files so 'why did the April run fail' is answerable later.
Watch out

Common mistakes

  • Reporting averages and omitting percentiles, which hides the user-impacting tail.
  • Sending load-test results to a different format or time zone than production metrics, so comparisons mislead.
  • Overwriting result files every run and losing the history needed for trend reports.
  • Giving management a single number without error rate and context, inviting wrong conclusions.
Root cause analysis

Common issues

Error
jq: error (at summary.json:0): Cannot iterate over null
Root cause

summary.json was not written because the run was aborted or --summary-export was omitted.

Fix

Re-run with --summary-export summary.json and confirm the file exists before parsing.

Error
InfluxDB write error: partial write
Root cause

The database is missing, full, or the field schema changed between runs.

Fix

Create the database (CREATE DATABASE k6), check retention, and keep the metric field names consistent.

Error
CI gate passed but the dashboard shows p95 above budget
Root cause

The dashboard queried a different time range or metric resolution than the test run.

Fix

Query the exact run window and store the run's start and end timestamps in the report metadata.

When things break

Debugging tips

  • When a run 'passes' but users complain, check the error budget window and percentile distribution, not just the verdict.
  • Compare the report's p99 to max: a huge gap means outlier requests need tracing, not tuning.
  • Verify the exporter timestamps align with server-side metrics, or dashboards will misalign spikes.
  • If InfluxDB or Prometheus charts are empty, confirm the --out URL and that the write path is reachable.
Interviews

Interview checkpoint

Practice

Hands-on lab

Publish an SLO Verdict from a Load Test
30 min · advanced
In progress
Objectives
  • Encode an SLO as k6 thresholds
  • Export a machine-readable summary
  • Make a run fail deliberately and read the exit code
  • Build a simple CI-style gate script on the exit code

Publish an SLO Verdict from a Load Test

30 min · advanced

0/5 steps
0%
sandbox · Linux sandbox
$
Try these commands
Test yourself

Quick quiz

0/3
1

Which single artifact turns a load test into an automated release gate?

2

A performance SLO is a target, and breaching it should always block a release.

3

The report shows p95 = 240ms (SLO 250ms) but http_req_failed = 4%. What is the correct action?

Quick reference

Cheat sheet

Reporting & SLOs
thresholds: http_req_duration: ['p(95)<250']Encode the SLO in code
abortOnFail: trueStop early on budget breach
--summary-export summary.jsonMachine-readable verdict
--out influxdb=...Stream to a time-series DB
--out prometheus-rw=...Remote-write to Prometheus
git SHA in metadataReproducible reports
Go deeper

Official documentation