LoadWave
Guides

Reports

The terminal summary, the self-contained HTML report, and the JSON snapshot — what each is for and what is in it.

Every run produces a terminal summary. Two flags add artefacts that outlive the process.

loadwave run test.yaml --report results.html --out results.json

The terminal summary

Printed at the end of every run, --ui or not:

──────────────────────────────────────────────────────────────────────────────
storefront — completed
30s to 100 VUs, then 5m0s to 100 VUs, then 30s to 0 VUs
ran for 6m0s across 1 agent
──────────────────────────────────────────────────────────────────────────────

METRIC             VALUE
requests           184,209
throughput         512/s
duration p95       46.3ms
failed requests    2,931 (1.59%)
checks passed      181,278 of 184,209

REQUEST          COUNT    AVG     P95     P99     MAX     ERRORS
view product     92,104   30.3ms  48.6ms  50.4ms  91.2ms  3.18%
list products    92,105   15.1ms  24.7ms  25.5ms  62.1ms  0%

THRESHOLD                    ACTUAL  RESULT
http_req_duration p95 < 500  46.34   pass
http_req_failed rate < 0.01  0.0159  FAIL

The header line is worth reading rather than skipping: it restates the profile that actually ran and how many agents contributed. A run that says across 1 agent when you expected four has already told you why the numbers are low.

Warnings appear here too, and they matter:

warning: 1,284 samples were dropped by nodes that hit their series cap;
       a high-cardinality tag is the usual cause
warning: 12 metric batches arrived too late to be counted; check clock skew between hosts

Either one means the reported numbers understate reality. Fix the cause before trusting the run.

The HTML report

loadwave run test.yaml --report results.html

Or the Download report button in the dashboard, or straight from the API:

curl -O http://localhost:8088/api/v1/runs/<id>/report.html

One self-contained file. Charts included, as inline SVG — no scripts, no external assets, no network dependency.

That constraint is the point. It renders the same in an email client, as a CI artefact, as a ticket attachment, or opened in two years to settle an argument about when a regression started. A report that needs a CDN to draw its charts is worthless the moment it leaves the machine that made it.

It contains everything the dashboard showed: the profile, the charts, the per-endpoint breakdown with exact percentiles, the threshold verdicts, agent details, the event log, and the failed-requests table with its response excerpts.

The JSON snapshot

loadwave run test.yaml --out results.json

The whole coordinator snapshot: build info, the run summary, per-series aggregates, correctly merged totals, per-endpoint aggregates, failure kinds, threshold results, time buckets and events.

This is the one to parse when a later pipeline step needs to make a decision or post a comment.

Read totals, not series. series has one entry per label combination; totals has one correctly merged aggregate per metric. Folding series yourself produces plausible-looking numbers that disagree with the thresholds, because means need re-weighting by count and percentiles need the distributions rather than their summaries.

A minimal extraction:

# Did anything breach?
jq '.run.thresholdsBreached' results.json

# Which ones, and by how much
jq -r '.run.thresholds[]
       | select(.passed == false)
       | "\(.metric) \(.stat) \(.op) \(.value) — actual \(.actual)"' results.json

# The whole-run p95
jq '.totals.http_req_duration.p95' results.json

The shapes are documented in the REST API reference, since the file is the same object the API serves.

Naming them per run

Nothing generates unique names for you, which is deliberate — a pipeline usually wants to decide that itself:

loadwave run test.yaml \
  --name "storefront-$GIT_SHA" \
  --tag release="$GIT_SHA" \
  --tag env=staging \
  --out "results-$GIT_SHA.json" \
  --report "results-$GIT_SHA.html"

Tagging the run means the artefact identifies what was measured, which matters as soon as you keep more than one of them. The tags are attached to every metric the run produces, so they survive into both files.

What is not kept

Runs are in-memory. There is no database, retention is a rolling window (--window, default one hour of chart history), and everything is lost when the coordinator exits. Persistence is a roadmap item, deliberately deferred rather than half-built.

If you want a run to survive, write the files.

Next

On this page