1. Why go through Alloy #
Results and metrics in one place.
The principle #
k6 prints a summary at the end of a test, but during a load test you want to see client-side latency and service saturation in real time. By sending k6 metrics to Alloy, they join Mimir next to production metrics: one dashboard for both.
2. Configuration and run #
Alloy then k6.
config.alloy #
otelcol.receiver.otlp "k6" {
grpc {
endpoint = "0.0.0.0:4317"
}
output {
metrics = [otelcol.processor.batch.k6.input]
}
}
otelcol.processor.batch "k6" {
output {
metrics = [otelcol.exporter.prometheus.mimir.input]
}
}
otelcol.exporter.prometheus "mimir" {
forward_to = [prometheus.remote_write.mimir.receiver]
}
prometheus.remote_write "mimir" {
endpoint {
url = "http://mimir:9009/api/v1/push"
}
}Configuration validated with alloy validate (Alloy v1.21.3, November 2026).
Running the test #
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = { vus: 5, duration: '15s', thresholds: { http_req_duration: ['p(95)<500'] } };
export default function () {
const res = http.get('http://127.0.0.1:8099/');
check(res, { 'statut 200': (r) => r.status === 200 });
sleep(0.5);
}K6_OTEL_GRPC_EXPORTER_INSECURE=true K6_OTEL_METRIC_PREFIX=k6_ \
k6 run --tag testid=checkout-001 -o opentelemetry load.js| Variable | Default | Role |
|---|---|---|
| K6_OTEL_EXPORTER_PROTOCOL | grpc | or http/protobuf |
| K6_OTEL_GRPC_EXPORTER_ENDPOINT | localhost:4317 | Alloy address |
| K6_OTEL_GRPC_EXPORTER_INSECURE | false | No TLS (local network) |
| K6_OTEL_METRIC_PREFIX | empty | Metric prefix, here k6_ |
| K6_OTEL_EXPORT_INTERVAL | 10s | Export frequency |
3. What Alloy receives: a real test #
The produced series.
The metrics #
With otelcol.exporter.debug, Alloy printed every 5 seconds 16 metrics sent by k6 v2.3.0 (excerpt):
ResourceMetrics service.name=k6 service.version=2.3.0
k6_http_reqs{method=GET,scenario=default,status=200,testid=checkout-001,url=http://127.0.0.1:8099/} 90
k6_http_req_duration{…,testid=checkout-001} count=90 sum=467.6 min=0.446 max=21.05 le5=52 le10=27 le25=11Durations are in milliseconds and arrive as histograms. The testid tag passed on the command line is on every series: it lets you compare two runs. At the end, k6 reported 150 requests, 0% failures and a p95 of 12.38 ms.
Cardinality. Theurlandnamelabels create one series per URL: group dynamic URLs with thenameparameter ofhttp.get(for example/product/{id}).
