Three services for deterministically generating HTTP traffic and measuring eBPF agent capture coverage. See CLAUDE.md for full architecture and constraints.
Build the binaries first if you haven't:
./build.shThen run the whole benchmark (clear Kafka topic, start echo-server, start kafka-consumer, run traffic-gen, wait, print results, stop echo-server) with a single script:
./run-benchmark.sh --test-run-name <name> --count <n> [options]Flags can be passed in any order. --test-run-name and --count are required — everything else falls back to a default. Each flag can also be set via an env var (useful in Docker/Kubernetes) — command-line flags take precedence when both are set.
| Flag | Env var | Default | Notes |
|---|---|---|---|
--test-run-name |
TEST_RUN_NAME |
— | required; used as log prefix and x-debug-token prefix |
--count |
COUNT |
— | required; exact number of requests to send |
--rpm |
RPM |
600 |
requests per minute |
--payload |
PAYLOAD |
4kb |
any file in traffic-gen-go/json-files/ — currently 256b, 1kb, 4kb, 10kb, 20kb, 64kb |
--target |
TARGET |
http://localhost:8888 |
|
--timeout |
TIMEOUT |
10m |
how long kafka-consumer waits before giving up |
--mock-kafka |
MOCK_KAFKA |
true |
true bypasses eBPF and produces directly to Kafka (100% coverage); set false to measure real eBPF capture |
Run ./run-benchmark.sh -h for the full usage text.
Quick smoke test with all defaults (600 rpm, 4kb payload, mock Kafka):
./run-benchmark.sh --test-run-name smoke-test --count 1001000 requests at 600 rpm with a 256-byte payload:
./run-benchmark.sh --test-run-name e2e-600rpm-256b --count 1000 --rpm 600 --payload 256b10,000 requests at 1200 rpm with a 64kb payload, mock Kafka:
./run-benchmark.sh --test-run-name load-64kb --count 10000 --rpm 1200 --payload 64kbReal eBPF capture test (no mock-kafka) against a remote target, with a longer timeout:
./run-benchmark.sh --test-run-name ebpf-real-capture --count 5000 --rpm 600 --payload 4kb \
--target http://echo-server:8888 --timeout 20m --mock-kafka falseLogs are written to logs/<test-run-name>/traffic-gen-<test-run-name>.log and logs/<test-run-name>/kafka-consumer-<test-run-name>.log.
run-benchmark.sh assumes all three binaries live on the same filesystem and starts them itself — that doesn't apply once they're deployed as separate pods (per k8s.yaml). For that case, use run-benchmark-k8s.sh instead: it doesn't start anything (the pods already run sleep infinity), it resolves pod names and kubectl execs the actual commands into them, then copies the resulting log files back to your machine.
./run-benchmark-k8s.sh --test-run-name <name> --count <n> [options]| Flag | Env var | Default | Notes |
|---|---|---|---|
--test-run-name |
TEST_RUN_NAME |
— | required; used as log prefix and x-debug-token prefix |
--count |
COUNT |
— | required; exact number of requests to send |
--rpm |
RPM |
600 |
requests per minute |
--payload |
PAYLOAD |
4kb |
payload size baked into the traffic-gen image (256b, 1kb, 4kb, 10kb, 20kb, 64kb) |
--timeout |
TIMEOUT |
10m |
how long kafka-consumer waits before giving up |
--mock-kafka |
MOCK_KAFKA |
true |
true bypasses eBPF and produces directly to kafka-internal:29092; set false to measure real eBPF capture |
--namespace |
NAMESPACE |
default |
k8s namespace the echo-server/traffic-generator/kafka-consumer Deployments live in |
Note there's no --target flag here — it's always http://echo-server:8888 (in-cluster Service DNS), and --brokers is always kafka-internal:29092 (added automatically, not user-configurable). Run ./run-benchmark-k8s.sh -h for the full usage text.
Quick smoke test against the default namespace:
./run-benchmark-k8s.sh --test-run-name k8s-smoke-test --count 1001000 requests at 600 rpm with a 256-byte payload:
./run-benchmark-k8s.sh --test-run-name k8s-256b --count 1000 --rpm 600 --payload 256bReal eBPF capture test (no mock-kafka) in a non-default namespace:
./run-benchmark-k8s.sh --test-run-name real-ebpf --count 5000 --mock-kafka false --namespace traffic-genLogs land at logs/<test-run-name>/traffic-gen-<test-run-name>.log and logs/<test-run-name>/kafka-consumer-<test-run-name>.log, same layout as the bare-metal script — copied back from each pod's /app/logs/ via kubectl cp after the run finishes.