BenchSpy - Standard Report
StandardReport
supports three types of data sources:
Direct
Loki
Prometheus
Each allows you to use either pre-defined metrics or create custom ones.
Pre-defined (Standard) Metrics
Direct and Loki
Both query executors focus on the characteristics of the load generated by WASP
. Their datasets are nearly identical because the Direct
executor queries load-specific data before it is sent to Loki. The Loki
executor, however, offers richer querying options (via LogQL
) and access to the actual load profile (rather than the configured one).
Predefined metrics for both include:
- Median latency
- 95th percentile latency
- Max latency
- Error rate
Latency is the round-trip time from sending a request to receiving a response from the Application Under Test (AUT).
Error rate is the ratio of failed responses to total responses. This includes requests that timed out or returned errors from Gun
or Vu
implementations.
Prometheus
Prometheus metrics focus on resource consumption by the AUT rather than load generation. These metrics include:
- Median CPU usage
- 95th percentile CPU usage
- Max CPU usage
- Median memory usage
- 95th percentile memory usage
- Max memory usage
Prometheus queries focus on total consumption, which combines the usage of the underlying system and your application.
How to Use Pre-defined Metrics
To use pre-defined metrics, call the NewStandardReport
method:
report, err := benchspy.NewStandardReport(
"v1.1.1",
// Query executor types for which standard metrics should be generated
benchspy.WithStandardQueries(
benchspy.StandardQueryExecutor_Prometheus,
benchspy.StandardQueryExecutor_Loki,
),
// Prometheus configuration is required if using standard Prometheus metrics
benchspy.WithPrometheusConfig(benchspy.NewPrometheusConfig("node[^0]")),
// WASP generators
benchspy.WithGenerators(gen),
)
require.NoError(t, err, "failed to create the report")
Custom Metrics
WASP Generator
Since WASP
stores AUT responses in each generator, you can create custom metrics based on this data. For example, to calculate the timeout ratio:
var generator *wasp.Generator
var timeouts = func(responses *wasp.SliceBuffer[*wasp.Response]) (float64, error) {
if len(responses.Data) == 0 {
return 0, nil
}
timeoutCount := 0.0
inTimeCount := 0.0
for _, response := range responses.Data {
if response.Timeout {
timeoutCount++
} else {
inTimeCount++
}
}
return timeoutCount / (timeoutCount + inTimeCount), nil
}
directExecutor, err := NewDirectQueryExecutor(generator, map[string]DirectQueryFn{
"timeout_ratio": timeouts,
})
require.NoError(t, err, "failed to create Direct Query Executor")
Loki
Creating custom LogQL
queries is even simpler. Use NewLokiQueryExecutor
with a map of desired queries:
var generator *wasp.Generator
lokiQueryExecutor := benchspy.NewLokiQueryExecutor(
map[string]string{
"responses_over_time": fmt.Sprintf("sum(count_over_time({my_label=~\"%s\", test_data_type=~\"responses\", gen_name=~\"%s\"} [5s])) by (node_id, gen_name)", label, gen.Cfg.GenName),
},
generator.Cfg.LokiConfig,
)
note
To write effective LogQL
queries for WASP
, familiarize yourself with generator labeling and the test_data_types
used by WASP
.
Prometheus
Adding custom PromQL
queries is equally straightforward:
promConfig := benchspy.NewPrometheusConfig()
prometheusExecutor, err := benchspy.NewPrometheusQueryExecutor(
map[string]string{
"cpu_rate_by_container": "rate(container_cpu_usage_seconds_total{name=~\"chainlink.*\"}[5m])[30m:1m]",
},
promConfig,
)
require.NoError(t, err)
Using Custom Queries with StandardReport
To use custom queries in a StandardReport
, pass the custom QueryExecutors
created above using the WithQueryExecutors
option instead of the StandardQueryExecutorType
:
report, err := benchspy.NewStandardReport(
"v1.2.3",
benchspy.WithQueryExecutors(directExecutor, lokiQueryExecutor, prometheusExecutor),
benchspy.WithGenerators(gen),
)
require.NoError(t, err, "failed to create baseline report")