| Crates.io | culverin |
| lib.rs | culverin |
| version | 0.1.1 |
| created_at | 2025-07-03 09:31:42.509499+00 |
| updated_at | 2025-07-03 09:33:22.531445+00 |
| description | A HTTP load testing tool |
| homepage | |
| repository | https://github.com/muhadif/culverin |
| max_upload_size | |
| id | 1736074 |
| size | 420,556 |
Culverin is a powerful HTTP load testing tool inspired by Vegeta (https://github.com/tsenart/vegeta), written in Rust. It's designed to help you test the performance and reliability of your HTTP services under various load conditions.
# Clone the repository
git clone https://github.com/muhadif/culverin.git
cd culverin
# Run the installation script
chmod +x install.sh
./install.sh
# Clone the repository
git clone https://github.com/muhadif/culverin.git
cd culverin
# Run the installation script
chmod +x install_mac.sh
./install_mac.sh
# Clone the repository
git clone https://github.com/muhadif/culverin.git
cd culverin
# Run the installation script (in PowerShell)
.\install_windows.ps1
If you prefer to install manually or the installation scripts don't work for you:
# Make sure you have Rust and Cargo installed
# Visit https://rustup.rs/ for installation instructions
# Clone the repository
git clone https://github.com/muhadif/culverin.git
cd culverin
# Build and install
cargo install --path .
Culverin provides several commands for load testing and analyzing results:
attack: Run a load test against a targetencode: Convert results to different formatsplot: Generate visualizations from resultsreport: Generate detailed reports from results# Create a targets file
echo "GET http://example.com/" > targets.txt
# Run a load test for 5 seconds at 50 requests per second
culverin attack --duration=5s --rate=50/1s --targets=targets.txt --output=results.bin
# Generate a report
cat results.bin | culverin report
Culverin commands can be piped together for a seamless workflow:
echo "GET http://example.com/" | culverin attack --duration=10s | tee results.bin | culverin report
--cpus int
Number of CPUs to use (default = number of cpus)
--profile string
Enable profiling of [cpu, heap]
--version
Print version and exit
culverin attack [flags]
Flags:
--body string
Requests body file
--cert string
TLS client PEM encoded certificate file
--chunked
Send body with chunked transfer encoding
--connect-to value
A mapping of (ip|host):port to use instead of a target URL's (ip|host):port
--connections int
Max open idle connections per target host (default 10000)
--dns-ttl value
Cache DNS lookups for the given duration [-1 = disabled, 0 = forever] (default 0s)
--duration duration
Duration of the test [0 = forever]
--format string
Targets format [http, json] (default "http")
--h2c
Send HTTP/2 requests without TLS encryption
--header value
Request header
--http2
Send HTTP/2 requests when supported by the server (default true)
--insecure
Ignore invalid server TLS certificates
--keepalive
Use persistent connections (default true)
--key string
TLS client PEM encoded private key file
--laddr value
Local IP address (default 0.0.0.0)
--lazy
Read targets lazily
--max-body value
Maximum number of bytes to capture from response bodies. [-1 = no limit] (default -1)
--max-connections int
Max connections per target host
--max-workers uint
Maximum number of workers
--name string
Attack name
--output string
Output file (default "stdout")
--opentelemetry-addr string
OpenTelemetry exporter listen address [empty = disabled]
--proxy-header value
Proxy CONNECT header
--rate value
Number of requests per time unit [0 = infinity] (default 50/1s)
--redirects int
Number of redirects to follow. -1 will not follow but marks as success (default 10)
--resolvers value
List of addresses (ip:port) to use for DNS resolution
--root-certs value
TLS root certificate files (comma separated list)
--session-tickets
Enable TLS session resumption using session tickets
--targets string
Targets file (default "stdin")
--timeout duration
Requests timeout (default 30s)
--unix-socket string
Connect over a unix socket. This overrides the host address in target URLs
--workers uint
Initial number of workers (default 10)
culverin encode [flags]
Flags:
--output string
Output file (default "stdout")
--to string
Output encoding [csv, json] (default "json")
culverin plot [flags]
Flags:
--output string
Output file (default "stdout")
--threshold int
Threshold of data points above which series are downsampled. (default 4000)
--title string
Title and header of the resulting HTML page (default "Culverin Plot")
culverin report [flags]
Flags:
--buckets string
Histogram buckets, e.g.: "[0,1ms,10ms]"
--every duration
Report interval
--output string
Output file (default "stdout")
--type string
Report type to generate [text, json, hist[buckets], hdrplot] (default "text")
echo "POST http://api.example.com/data" | culverin attack \
--header="Content-Type: application/json" \
--header="Authorization: Bearer token123" \
--body=payload.json \
--duration=30s \
--rate=10/1s
cat results.bin | culverin report --type="hist[0,10ms,25ms,50ms,100ms,250ms,500ms]"
cat results.bin | culverin plot --output=results.html --title="API Performance Test"
cat results.bin | culverin encode --to=csv --output=results.csv
Culverin supports exporting metrics to an OpenTelemetry collector, which allows you to monitor your load tests in real-time using tools like Prometheus, Grafana, or any other system that can consume OpenTelemetry metrics.
echo "GET http://example.com/" | culverin attack \
--duration=30s \
--rate=50/1s \
--opentelemetry-addr="http://localhost:4318/v1/metrics"
The following metrics are exported:
requests: Total number of requestssuccess_requests: Number of successful requestsfailure_requests: Number of failed requestsbytes_in: Total bytes receivedbytes_out: Total bytes sentactive_workers: Number of active workersrequest_duration: Histogram of request durations in secondsTo use this feature, you need to have an OpenTelemetry collector running. You can set up a collector using the OpenTelemetry Collector project.
Culverin can also be used as a library in your Rust applications, allowing you to integrate load testing capabilities directly into your code.
Add Culverin to your Cargo.toml:
[dependencies]
culverin = { git = "https://github.com/muhadif/culverin.git" }
tokio = { version = "1.35", features = ["full"] }
anyhow = "1.0"
Here's a simple example of using Culverin as a library:
use culverin::{AttackBuilder, get, calculate_metrics};
use std::time::Duration;
use anyhow::Result;
#[tokio::main]
async fn main() -> Result<()> {
// Create a target using the helper function
let target = get("https://example.com")?;
// Configure and run the attack
let results = AttackBuilder::new()
.rate(10.0) // 10 requests per second
.duration(Duration::from_secs(5)) // Run for 5 seconds
.timeout(Duration::from_secs(3)) // 3 second timeout
.workers(4) // Use 4 worker threads
.add_header("User-Agent", "culverin-example")
.add_target(target)
.run()
.await?;
// Calculate and display metrics
if let Some(metrics) = calculate_metrics(&results) {
println!("Attack completed!");
println!("Total requests: {}", metrics.requests);
println!("Success rate: {:.2}%", metrics.success_rate * 100.0);
println!("Mean latency: {:.2}ms", metrics.mean.as_secs_f64() * 1000.0);
println!("95th percentile: {:.2}ms", metrics.p95.as_secs_f64() * 1000.0);
println!("Requests/second: {:.2}", metrics.rate);
}
Ok(())
}
For more advanced usage, including custom targets with different HTTP methods, headers, and bodies, see the advanced example.
Target: Represents a target for the load test (method, URL, headers, body)Header: Represents an HTTP header (name, value)AttackResult: Represents the result of a single requestMetrics: Represents metrics from a load testAttackBuilder: Builder for configuring and running an attackget(url): Create a GET targetpost(url, body): Create a POST target with the specified bodytarget(method, url): Create a target with the specified methodcalculate_metrics(results): Calculate metrics from attack resultsThe AttackBuilder provides a fluent API for configuring load tests. Here are some of the key methods:
rate(f64): Set the request rate (requests per second)duration(Duration): Set the attack durationtimeout(Duration): Set the request timeoutworkers(u64): Set the number of workersmax_workers(u64): Set the maximum number of workerskeepalive(bool): Set whether to keep connections alivehttp2(bool): Set whether to use HTTP/2insecure(bool): Set whether to ignore invalid TLS certificatesredirects(i32): Set the number of redirects to followadd_header(name, value): Add a header to all requestsadd_target(target): Add a target to the attacktargets(targets): Set multiple targets for the attackopentelemetry_addr(String): Set the OpenTelemetry exporter address for metricsrun(): Run the attack and collect resultsFor more details, see the library documentation and the example files.
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.