Metrics
Built-in metrics, custom metrics, and thresholds
Built-in HTTP Metrics
http_req_duration - Total request time (ms)
http_req_blocked - Time waiting for connection (ms)
http_req_connecting - TCP connection time (ms)
http_req_tls_handshaking - TLS handshake time (ms)
http_req_sending - Time sending request (ms)
http_req_waiting - Time waiting for response (TTFB) (ms)
http_req_receiving - Time receiving response (ms)
http_req_failed - Rate of failed requests
http_reqs - Total number of requests
data_sent - Total bytes sent
data_received - Total bytes received
Other Built-in Metrics
checks - Rate of passed checks
iterations - Total completed iterations
workers - Current number of active workers
workers_max - Maximum workers during test
Iteration Timing Metrics
iteration - Duration excluding sleep time (actual work)
iteration_total - Duration including sleep time (wall-clock)
Example: If an iteration makes two 50ms requests with a 500ms sleep between them, iteration reports ~100ms (work) while iteration_total reports ~600ms (work + sleep).
Connection Pool Metrics
Fusillade automatically tracks HTTP connection pool reuse. No configuration is needed — pool metrics are collected for every test run.
pool_hitsNumber of requests that reused an existing connection from the pool
pool_missesNumber of requests that required a new connection to be established
Example Report Output
┌─────────────────────────────────────────────────┐
│ Connection Pool │
├─────────────────────────────────────────────────┤
│ Reused connections .. 14,823 (92.6%) │
│ New connections ..... 1,177 (7.4%) │
└─────────────────────────────────────────────────┘A high pool_hits percentage indicates efficient connection reuse, reducing TCP/TLS handshake overhead and improving throughput. JSON and HTML exports include pool_hits and pool_misses fields in the summary object.
Thresholds
Define pass/fail criteria for your tests. Failed thresholds cause non-zero exit codes for CI/CD.
export const options = {
thresholds: {
// 95th percentile response time under 500ms
'http_req_duration': ['p95 < 500'],
// 99th percentile under 1 second
'http_req_duration': ['p99 < 1000'],
// Average under 200ms
'http_req_duration': ['avg < 200'],
// Error rate under 1%
'http_req_failed': ['rate < 0.01'],
// At least 100 requests
'http_reqs': ['count > 100'],
// Multiple conditions (all must pass)
'http_req_duration': ['p95 < 500', 'p99 < 1000'],
}
};Threshold Operators
p95 < 500 - 95th percentile under 500
p99 < 1000 - 99th percentile under 1000
avg < 200 - Average under 200
min > 10 - Minimum above 10
max < 5000 - Maximum under 5000
rate < 0.01 - Rate under 1% (for error rates)
count > 100 - Count greater than 100
Note: Spaces around operators are required.
Per-URL Thresholds
export const options = {
thresholds: {
// All requests
'http_req_duration': ['p95 < 500'],
// Specific endpoint using tags
'http_req_duration{url:https://api.example.com/users}': ['p95 < 200'],
'http_req_duration{url:https://api.example.com/search}': ['p95 < 1000'],
// By name tag
'http_req_duration{name:GET /users/:id}': ['p95 < 300'],
}
};Abort on Threshold Failure
export const options = {
thresholds: {
'http_req_failed': ['rate < 0.1'],
},
abort_on_fail: true, // Stop test immediately if threshold breached
};
// Or via CLI:
// fusillade run test.js --abort-on-failCustom Metrics
Define custom business-level metrics. All functions accept an optional tags object as the last parameter.
metrics.histogramAdd(name, value, [tags])Track distribution (timing, size)
metrics.counterAdd(name, value, [tags])Cumulative sum (events, totals)
metrics.gaugeSet(name, value, [tags])Current value (queue depth, etc)
metrics.rateAdd(name, success, [tags])Track success rate (boolean)
export const options = {
thresholds: {
'checkout_duration': ['p95 < 500'],
'items_sold': ['count > 100'],
'payment_success': ['rate > 0.99'],
}
};
export default function() {
const start = Date.now();
// Your custom logic
const res = http.get('https://api.example.com/data');
const data = res.json();
// Track custom timings (with optional tags)
metrics.histogramAdd('checkout_duration', Date.now() - start, { region: 'us-east' });
// Track counts
metrics.counterAdd('items_sold', 3, { category: 'electronics' });
// Track current state
metrics.gaugeSet('queue_depth', 42);
// Track success rate
metrics.rateAdd('payment_success', true, { provider: 'stripe' });
}Thresholds on Custom Metrics
export const options = {
thresholds: {
// Histogram thresholds
'data_processing_time': ['p95 < 100'],
// Counter thresholds
'items_processed': ['count > 1000'],
// Rate thresholds
'valid_responses': ['rate > 0.99'],
}
};Runtime Statistics Access
Query collected statistics during the test to enable adaptive testing scenarios.
stats.get(name)Query collected statistics for a named request or metric
p95 - 95th percentile latency (ms)
p99 - 99th percentile latency (ms)
avg - Average latency (ms)
count - Total request count
min - Minimum latency (ms)
max - Maximum latency (ms)
# Adaptive Testing with stats.get()
export default function() {
http.get('https://api.example.com/data', { name: 'getData' });
// Query stats for a named request
const s = stats.get('getData');
print(`p95: ${s.p95}ms, avg: ${s.avg}ms, count: ${s.count}`);
// Adaptive behavior based on performance
if (s.p95 > 500) {
print('Warning: p95 latency exceeds 500ms');
}
}Metrics Export
Export metrics to various destinations for analysis and monitoring.
# JSON Export
$ fusillade run test.js --export-json results.json# HTML Report
$ fusillade run test.js --export-html report.html# CSV Export
$ fusillade run test.js --out csv=metrics.csv# JUnit XML (CI/CD)
$ fusillade run test.js --out junit=results.xml# OpenTelemetry
$ fusillade run test.js --out otlp=http://localhost:4317# StatsD/Datadog/Graphite
$ fusillade run test.js --out statsd=localhost:8125Real-time Metrics Streaming
Stream metrics to an external endpoint during test execution. Periodic payloads include aggregate stats and per-endpoint breakdown when endpoint tracking is enabled.
# Stream to metrics endpoint
$ fusillade run test.js --metrics-url https://metrics.example.com/ingest
# With authentication
$ fusillade run test.js \
--metrics-url https://metrics.example.com/ingest \
--metrics-auth "Authorization: Bearer TOKEN"
# Disable per-endpoint data in streaming payloads
$ fusillade run test.js --metrics-url https://example.com/ingest --no-endpoint-trackingPer-Endpoint Metrics
By default, Fusillade tracks metrics for each unique endpoint (URL + method) in your test. This data is streamed in real-time and displayed as time-series charts in the test detail view.
What is tracked per endpoint
requests - Total requests to this endpoint
avg_latency_ms - Average response time
p95_latency_ms - 95th percentile response time
errors - Number of failed requests
Dashboard visualization
The test detail page shows per-endpoint time-series charts for latency, requests, and errors. Each endpoint is displayed as a separate line with its own color. During live tests, the dashboard shows a real-time endpoint latency chart.
Disabling endpoint tracking
For tests with high URL cardinality (e.g., URLs containing unique IDs), disable endpoint tracking to reduce memory usage and data volume.
# Via CLI flag
$ fusillade run test.js --no-endpoint-tracking
# Via script options
export const options = {
track_endpoints: false,
};Custom Summary Handler
Generate custom reports using the handleSummary lifecycle hook.
export function handleSummary(data) {
// data contains all metrics and thresholds
console.log('Total requests:', data.metrics.http_reqs.count);
console.log('P95 latency:', data.metrics.http_req_duration.p95);
console.log('Error rate:', data.metrics.http_req_failed.rate);
// Return files to write
return {
'summary.json': JSON.stringify(data, null, 2),
'summary.txt': generateTextReport(data),
};
}
function generateTextReport(data) {
return `
Load Test Report
================
Total Requests: ${data.metrics.http_reqs.count}
Success Rate: ${((1 - data.metrics.http_req_failed.rate) * 100).toFixed(2)}%
P95 Latency: ${data.metrics.http_req_duration.p95.toFixed(2)}ms
`;
}