Skip to main content

Developer-friendly API load testing and performance profiling CLI

Project description

⚡ StressKit

Developer-friendly API load testing and performance profiling CLI.

Python 3.10+ PyPI version License: MIT CI

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 wrk or hey — 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 compare to catch regressions before deploying.
  • Truly async — uses asyncio + aiohttp with 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: [![asciicast](https://asciinema.org/a/YOUR_ID.svg)](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:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Write tests for your changes
  4. Ensure all tests pass (pytest tests/ -v)
  5. Lint your code (ruff check .)
  6. Open a Pull Request

License

MIT — see LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

stresskit-1.0.0.tar.gz (28.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

stresskit-1.0.0-py3-none-any.whl (23.5 kB view details)

Uploaded Python 3

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

Hashes for stresskit-1.0.0.tar.gz
Algorithm Hash digest
SHA256 847c40c36916166cfbd2f3db3b44653ed9b8e96a1e81433fbe58748afabd9239
MD5 675fa01638429969f96265de293d4b35
BLAKE2b-256 f739aec7b6ad17e9f1995c0c90104962b45495a97c913006e339a8867641c3ea

See more details on using hashes here.

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

Hashes for stresskit-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2f4f3f6eed28fb0abe54f5f9e61e19b4ec248263ddd0a1442561ecbf39f7d91c
MD5 7e752c0642f6c3d26e08b8ee046f3c2d
BLAKE2b-256 dbbf55728288c2df6c1216d7f928b2f24cdc09605ef3f7f7c35f0eba9d21c877

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page