Integrating JMeter with Prometheus and Grafana
Set up real-time JMeter metrics visualization using Prometheus and Grafana for better load test monitoring and analysis.
Mark
Performance Testing Expert
JMeter’s built-in reporting is useful but limited for real-time monitoring during test execution. By integrating with Prometheus and Grafana, you get live dashboards, alerting capabilities, and the ability to correlate load test metrics with application infrastructure metrics.
Architecture Overview
The integration works as follows:
JMeter → Prometheus Remote Write → Prometheus Server → Grafana Dashboard
JMeter uses a Backend Listener to push metrics in Prometheus format, which Prometheus scrapes and Grafana visualises.
Setting Up Prometheus
Install Prometheus locally or use Docker:
# docker-compose.yml
version: '3'
services:
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--web.enable-remote-write-receiver'
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana-data:/var/lib/grafana
volumes:
grafana-data:
Configure Prometheus to accept remote writes:
# prometheus.yml
global:
scrape_interval: 15s
remote_write:
- url: "http://localhost:9090/api/v1/write"
Start the services:
docker-compose up -d
JMeter Prometheus Backend Listener
Install the Prometheus Listener plugin. Download from JMeter Plugins Manager or manually:
wget https://repo1.maven.org/maven2/com/github/johrstrom/jmeter-prometheus-plugin/0.6.0/jmeter-prometheus-plugin-0.6.0.jar \
-O $JMETER_HOME/lib/ext/jmeter-prometheus-plugin-0.6.0.jar
Add the Backend Listener to your test plan:
- Right-click Test Plan → Add → Listener → Backend Listener
- Select
com.github.johrstrom.listener.PrometheusListeneras Backend Listener implementation
Configure the listener:
| Property | Value |
|---|---|
| prometheus.save.threads | true |
| prometheus.save.jvm | true |
| prometheus.port | 9270 |
Alternative: Prometheus Remote Write
For direct push to Prometheus without exposing a port:
<!-- In your JMeter test plan -->
<BackendListener guiclass="BackendListenerGui" testclass="BackendListener" testname="Prometheus Backend Listener">
<elementProp name="arguments" elementType="Arguments">
<collectionProp name="Arguments.arguments">
<elementProp name="prometheus.remote.url" elementType="Argument">
<stringProp name="Argument.name">prometheus.remote.url</stringProp>
<stringProp name="Argument.value">http://localhost:9090/api/v1/write</stringProp>
</elementProp>
</collectionProp>
</elementProp>
</BackendListener>
Available Metrics
The plugin exposes several metrics:
| Metric | Type | Description |
|---|---|---|
| jmeter_running_threads | Gauge | Current active threads |
| jmeter_requests_total | Counter | Total requests made |
| jmeter_response_time_seconds | Histogram | Response time distribution |
| jmeter_failures_total | Counter | Failed requests |
| jmeter_success_total | Counter | Successful requests |
| jmeter_sent_bytes_total | Counter | Bytes sent |
| jmeter_received_bytes_total | Counter | Bytes received |
Labels include:
sampler- The sampler namecode- HTTP response codesuccess- true/false
Grafana Dashboard Setup
- Access Grafana at
http://localhost:3000(admin/admin) - Add Prometheus data source: Configuration → Data Sources → Add → Prometheus
- Set URL to
http://prometheus:9090(orhttp://localhost:9090if not using Docker network) - Create a new dashboard
Essential Panels
Request Rate:
sum(rate(jmeter_requests_total[1m])) by (sampler)
Response Time Percentiles:
histogram_quantile(0.95, sum(rate(jmeter_response_time_seconds_bucket[1m])) by (le, sampler))
Error Rate:
sum(rate(jmeter_failures_total[1m])) / sum(rate(jmeter_requests_total[1m])) * 100
Active Threads:
jmeter_running_threads
Throughput by Sampler:
sum(rate(jmeter_requests_total[1m])) by (sampler)
Complete Dashboard JSON
Import this dashboard configuration:
{
"title": "JMeter Load Test",
"panels": [
{
"title": "Requests per Second",
"type": "timeseries",
"targets": [{
"expr": "sum(rate(jmeter_requests_total[1m])) by (sampler)",
"legendFormat": "{{sampler}}"
}],
"gridPos": {"x": 0, "y": 0, "w": 12, "h": 8}
},
{
"title": "Response Time (p95)",
"type": "timeseries",
"targets": [{
"expr": "histogram_quantile(0.95, sum(rate(jmeter_response_time_seconds_bucket[1m])) by (le, sampler))",
"legendFormat": "{{sampler}}"
}],
"gridPos": {"x": 12, "y": 0, "w": 12, "h": 8}
},
{
"title": "Active Threads",
"type": "gauge",
"targets": [{
"expr": "jmeter_running_threads"
}],
"gridPos": {"x": 0, "y": 8, "w": 6, "h": 4}
},
{
"title": "Error Rate %",
"type": "stat",
"targets": [{
"expr": "sum(rate(jmeter_failures_total[1m])) / sum(rate(jmeter_requests_total[1m])) * 100"
}],
"gridPos": {"x": 6, "y": 8, "w": 6, "h": 4}
}
]
}
Alerting on Performance Issues
Set up Grafana alerts for automatic notification:
# Alert rule for high response time
apiVersion: 1
groups:
- name: jmeter-alerts
rules:
- alert: HighResponseTime
expr: histogram_quantile(0.95, sum(rate(jmeter_response_time_seconds_bucket[5m])) by (le)) > 2
for: 2m
labels:
severity: warning
annotations:
summary: "High response time detected"
description: "95th percentile response time is above 2 seconds"
- alert: HighErrorRate
expr: sum(rate(jmeter_failures_total[5m])) / sum(rate(jmeter_requests_total[5m])) > 0.05
for: 1m
labels:
severity: critical
annotations:
summary: "High error rate detected"
description: "Error rate is above 5%"
Correlating with Application Metrics
The real power comes from viewing JMeter metrics alongside application metrics. If your application already exports Prometheus metrics:
# JMeter throughput vs Application CPU
jmeter_requests_total alongside node_cpu_seconds_total
# Response time vs Database connections
jmeter_response_time_seconds alongside pg_stat_activity_count
Create a combined dashboard with:
- Top row: JMeter load metrics
- Middle row: Application metrics (CPU, memory, connections)
- Bottom row: Infrastructure metrics (database, cache)
Running Tests with Prometheus Integration
Non-GUI mode with Prometheus listener:
jmeter -n -t test-plan.jmx -l results.jtl \
-Jprometheus.port=9270 \
-Jprometheus.save.threads=true
The metrics endpoint will be available at http://localhost:9270/metrics for Prometheus to scrape.
Docker-Based Test Execution
For containerised testing:
version: '3'
services:
jmeter:
image: justb4/jmeter:latest
volumes:
- ./tests:/tests
- ./results:/results
command: -n -t /tests/load-test.jmx -l /results/results.jtl
ports:
- "9270:9270"
networks:
- monitoring
prometheus:
image: prom/prometheus:latest
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
networks:
- monitoring
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
networks:
- monitoring
networks:
monitoring:
Configure Prometheus to scrape JMeter:
# prometheus.yml
scrape_configs:
- job_name: 'jmeter'
static_configs:
- targets: ['jmeter:9270']
Advantages Over Built-In Reporting
| Feature | Built-in HTML Report | Prometheus + Grafana |
|---|---|---|
| Real-time | No (post-test) | Yes |
| Custom dashboards | Limited | Fully customisable |
| Alerting | No | Yes |
| Correlation with other metrics | No | Yes |
| Historical comparison | Manual | Built-in |
| Team visibility | Share files | Shared dashboards |
The Prometheus and Grafana integration transforms JMeter from a command-line tool into a real-time monitoring solution. This visibility is invaluable when running long soak tests or when you need to correlate load test results with infrastructure behaviour.
Tags: