Developer-friendly API load testing and performance profiling CLI
Project description
⚡ StressKit
Developer-friendly API load testing and performance profiling CLI.
StressKit takes an API endpoint, hammers it with configurable concurrent requests, and generates a clean, professional performance report — all from your terminal.
Why StressKit?
- Better UX than
wrkorhey— color-coded terminal output, latency histograms, throughput sparklines, and exportable reports out of the box. - Built for developer workflows — auto-saves every run to local history, supports JSON/CSV export, and lets you compare runs with
stresskit compareto catch regressions before deploying. - Truly async — uses
asyncio+aiohttpwith proper connection pooling for accurate, high-concurrency load generation. Not threads. Not forks.
Installation
pip install stresskit
Or install from source:
git clone https://github.com/rdheri/stresskit.git
cd stresskit
pip install -e ".[dev]"
Quick Start
Basic GET test (100 requests, 10 concurrent workers)
stresskit run https://httpbin.org/get
POST with custom headers and body
stresskit run https://httpbin.org/post \
-m POST \
-H "Authorization: Bearer token123" \
-H "Content-Type: application/json" \
-b '{"user": "test", "action": "create"}' \
-c 20 -n 500
Duration-based test (run for 30 seconds)
stresskit run https://api.example.com/health -d 30 -c 50
Export results
stresskit run https://httpbin.org/get -o report.json
stresskit run https://httpbin.org/get -o results.csv
Example Output
⚡ StressKit v1.0.0
Target: https://httpbin.org/get
Method: GET
Concurrency: 10
Requests: 100
╭──────────────────────────────────────────────╮
│ StressKit Report • 2025-03-15T14:32:01Z │
╰──────────────────────────────────────────────╯
Overview
┌──────────────────┬───────────┐
│ URL │ httpbin… │
│ Method │ GET │
│ Concurrency │ 10 │
│ Total Requests │ 100 │
│ Successful │ 100 │
│ Failed │ 0 │
│ Elapsed Time │ 2.34s │
│ Throughput │ 42.7 req/s│
└──────────────────┴───────────┘
Latency
┌──────────────┬────────────┐
│ Min │ 45.21 ms │ ← green
│ Max │ 312.87 ms │ ← yellow
│ Mean │ 98.43 ms │ ← green
│ Median (p50) │ 89.12 ms │
│ p90 │ 178.56 ms │
│ p95 │ 234.89 ms │ ← yellow
│ p99 │ 298.34 ms │
│ Std Dev │ 52.31 ms │
└──────────────┴────────────┘
Latency Distribution
45.2 - 71.9 ms │ ████████████████████ 28
71.9 - 98.7 ms │ ████████████████████████████ 35
98.7 - 125.4 ms │ ██████████████ 18
125.4 - 152.1 ms │ ████████ 9
178.9 - 312.9 ms │ ████ 5
Throughput Timeline (req/s per second)
▃▅▇█▇▆▅▇█▆ (peak: 52 req/s)
CLI Reference
stresskit run <URL>
| Flag | Short | Description | Default |
|---|---|---|---|
--method |
-m |
HTTP method (GET, POST, PUT, DELETE, PATCH) | GET |
--concurrency |
-c |
Number of concurrent workers | 10 |
--requests |
-n |
Total number of requests | 100 |
--duration |
-d |
Run for N seconds (overrides --requests) |
— |
--header |
-H |
Custom header, repeatable ("Key: Value") |
— |
--body |
-b |
JSON request body | — |
--timeout |
-t |
Request timeout in seconds | 30 |
--output |
-o |
Export to .json or .csv file |
— |
--compare |
— | Path to previous JSON report for delta comparison | — |
--threshold-good |
— | Latency threshold for green (ms) | 200 |
--threshold-warn |
— | Latency threshold for yellow/red (ms) | 500 |
stresskit compare <file1.json> <file2.json>
Loads two saved JSON reports and displays a side-by-side comparison table:
stresskit compare before.json after.json
╭──────────────────────────────────────────────╮
│ StressKit Comparison │
╰──────────────────────────────────────────────╯
Performance Delta
┌─────────────────┬─────────┬─────────┬─────────┬──────────┐
│ Metric │ before │ after │ Delta │ % Change │
├─────────────────┼─────────┼─────────┼─────────┼──────────┤
│ Requests/sec │ 42.70 │ 67.30 │ ▲ 24.60 │ ▲ 57.6% │ ← green
│ Mean Latency │ 98.43 │ 62.18 │ ▼ 36.25 │ ▼ 36.8% │ ← green
│ p95 Latency │ 234.89 │ 145.32 │ ▼ 89.57 │ ▼ 38.1% │ ← green
│ Failed Requests │ 0.00 │ 3.00 │ ▲ 3.00 │ ▲ — │ ← red
└─────────────────┴─────────┴─────────┴─────────┴──────────┘
stresskit history
stresskit history --limit 10
Shows past runs from the local SQLite database at ~/.stresskit/runs.db.
Metrics Reference
Latency: min, max, mean, median, p50, p75, p90, p95, p99, standard deviation
Throughput: total requests/second, successful requests/second
Errors: HTTP status code breakdown, timeout count, connection error count
Timeline: per-second throughput shown as a Unicode sparkline
Histogram: latency distribution rendered as a color-coded horizontal bar chart
Project Structure
stresskit/
├── pyproject.toml # Package config, dependencies, CLI entry point
├── README.md
├── LICENSE
├── stresskit/
│ ├── __init__.py # Version
│ ├── cli.py # Typer CLI definitions and commands
│ ├── engine.py # Async load testing engine (aiohttp)
│ ├── stats.py # Statistics computation (percentiles, histograms)
│ ├── reporter.py # Rich terminal output rendering
│ ├── exporter.py # JSON/CSV export logic
│ ├── comparator.py # Report comparison logic
│ ├── history.py # SQLite history logging and retrieval
│ └── models.py # Pydantic models for all data structures
├── tests/
│ ├── test_engine.py
│ ├── test_stats.py
│ ├── test_comparator.py
│ └── test_cli.py
└── .github/workflows/ci.yml
Development
# Clone and install
git clone https://github.com/rdheri/stresskit.git
cd stresskit
pip install -e ".[dev]"
# Run tests
pytest tests/ -v
# Run with coverage
pytest tests/ -v --cov=stresskit --cov-report=term-missing
# Lint
ruff check stresskit/ tests/
# Type check
mypy stresskit/
Creating a Demo Recording
Since StressKit is a CLI tool, the best way to showcase it is with a terminal recording:
Option 1: asciinema (recommended)
# Install
pip install asciinema
# Record
asciinema rec stresskit-demo.cast
# Inside the recording, run:
stresskit run https://httpbin.org/get -c 20 -n 200
# Stop recording with Ctrl+D, then upload:
asciinema upload stresskit-demo.cast
Embed in README: [](https://asciinema.org/a/YOUR_ID)
Option 2: terminalizer (GIF)
npm install -g terminalizer
terminalizer record stresskit-demo
# Run your commands, then Ctrl+D
terminalizer render stresskit-demo -o demo.gif
Publishing to PyPI
# 1. Create accounts at https://pypi.org and https://test.pypi.org
# 2. Build the package
pip install build twine
python -m build
# 3. Upload to Test PyPI first
twine upload --repository testpypi dist/*
# 4. Test the install
pip install --index-url https://test.pypi.org/simple/ stresskit
# 5. Upload to production PyPI
twine upload dist/*
Or use the GitHub Actions workflow — just push a version tag:
git tag v1.0.0
git push origin v1.0.0
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Write tests for your changes
- Ensure all tests pass (
pytest tests/ -v) - Lint your code (
ruff check .) - Open a Pull Request
License
MIT — see LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file stresskit-1.0.0.tar.gz.
File metadata
- Download URL: stresskit-1.0.0.tar.gz
- Upload date:
- Size: 28.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
847c40c36916166cfbd2f3db3b44653ed9b8e96a1e81433fbe58748afabd9239
|
|
| MD5 |
675fa01638429969f96265de293d4b35
|
|
| BLAKE2b-256 |
f739aec7b6ad17e9f1995c0c90104962b45495a97c913006e339a8867641c3ea
|
File details
Details for the file stresskit-1.0.0-py3-none-any.whl.
File metadata
- Download URL: stresskit-1.0.0-py3-none-any.whl
- Upload date:
- Size: 23.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2f4f3f6eed28fb0abe54f5f9e61e19b4ec248263ddd0a1442561ecbf39f7d91c
|
|
| MD5 |
7e752c0642f6c3d26e08b8ee046f3c2d
|
|
| BLAKE2b-256 |
dbbf55728288c2df6c1216d7f928b2f24cdc09605ef3f7f7c35f0eba9d21c877
|