Operations 16 min read

How to Visualize JMeter Performance Data with Grafana, InfluxDB, and Prometheus

This guide walks through the end‑to‑end workflow of sending JMeter test metrics to InfluxDB via Backend Listener, storing them alongside node_exporter data in Prometheus, and visualizing TPS, response time, and resource usage in Grafana dashboards, complete with configuration steps and code examples.

MaGe Linux Operations
MaGe Linux Operations
MaGe Linux Operations
How to Visualize JMeter Performance Data with Grafana, InfluxDB, and Prometheus

JMeter + InfluxDB + Grafana Data Flow

When using JMeter for load testing, the traditional approach of viewing results in the console, plugins, or generated HTML is cumbersome for large‑scale runs. By enabling the Backend Listener, JMeter can stream metrics such as TPS, response time, thread count, and error rate directly to InfluxDB (or Graphite) in real time.

Grafana then reads these time‑series from InfluxDB, allowing you to build dashboards that mirror the console output while offering richer visualisation and historical comparison.

Configuring JMeter Backend Listener

In JMeter 2.13+ you can add a Backend Listener element and choose the InfluxDB or Graphite implementation. The listener sends data asynchronously every summariser.interval seconds (default 30 s). No HTML files are needed; the metrics are stored in InfluxDB for later analysis.

private void addMetrics(String transaction, SamplerMetric metric) {
    // FOR ALL STATUS
    addMetric(transaction, metric.getTotal(), metric.getSentBytes(), metric.getReceivedBytes(), TAG_ALL,
        metric.getAllMean(), metric.getAllMinTime(), metric.getAllMaxTime(),
        allPercentiles.values(), metric::getAllPercentile);
    // FOR OK STATUS
    addMetric(transaction, metric.getSuccesses(), null, null, TAG_OK,
        metric.getOkMean(), metric.getOkMinTime(), metric.getOkMaxTime(),
        okPercentiles.values(), metric::getOkPercentile);
    // FOR KO STATUS
    addMetric(transaction, metric.getFailures(), null, null, TAG_KO,
        metric.getKoMean(), metric.getKoMinTime(), metric.getKoMaxTime(),
        koPercentiles.values(), metric::getKoPercentile);

    metric.getErrors().forEach((error, count) -> addErrorMetric(transaction,
        error.getResponseCode(), error.getResponseMessage(), count));
}

The listener collects global statistics (total requests, bytes sent/received, min/mean/max, percentiles) and separates them by success/failure status.

Sending Metrics to InfluxDB

@Override public void writeAndSendMetrics() {
    if (!copyMetrics.isEmpty()) {
        try {
            if (httpRequest == null) {
                httpRequest = createRequest(url);
            }
            StringBuilder sb = new StringBuilder(copyMetrics.size() * 35);
            for (MetricTuple metric : copyMetrics) {
                sb.append(metric.measurement)
                  .append(metric.tag)
                  .append(" ")
                  .append(metric.field)
                  .append(" ")
                  .append(metric.timestamp + "000000")
                  .append("
");
            }
            StringEntity entity = new StringEntity(sb.toString(), StandardCharsets.UTF_8);
            httpRequest.setEntity(entity);
            lastRequest = httpClient.execute(httpRequest, new FutureCallback<HttpResponse>() {
                @Override public void completed(final HttpResponse response) {
                    int code = response.getStatusLine().getStatusCode();
                    if (MetricUtils.isSuccessCode(code)) {
                        if (log.isDebugEnabled()) {
                            log.debug("Success, number of metrics written: {}", copyMetrics.size());
                        }
                    } else {
                        log.error("Error writing metrics to influxDB Url: {}, responseCode: {}, responseBody: {}", url, code, getBody(response));
                    }
                }
                @Override public void failed(final Exception ex) {
                    log.error("failed to send data to influxDB server : {}", ex.getMessage());
                }
                @Override public void cancelled() {
                    log.warn("Request to influxDB server was cancelled");
                }
            });
        } catch (Exception e) {
            log.error("Exception while sending metrics", e);
        }
    }
}

Each metric line follows InfluxDB line protocol: measurement,tag field timestamp. Successful writes appear in Grafana as the same curves you would see on the JMeter console.

InfluxDB Storage Structure

Two measurements are created: events (test start/stop markers) and jmeter (per‑transaction statistics). Example queries:

> show databases
name: databases
_name_
----
_internal
jmeter

> use jmeter
Using database jmeter

> show measurements
name: measurements
_name_
----
jmeter
events

> select * from jmeter where application='7ddemo' limit 10

The jmeter measurement holds fields such as avg, max, pct95.0, etc., which Grafana can plot over time.

Grafana Configuration

1. Add an InfluxDB data source (URL, database, user, password). 2. Import the official JMeter dashboard (Grafana ID 5496) and select the InfluxDB source. 3. Use queries like:

SELECT last("count") / $send_interval FROM "$measurement_name" WHERE ("transaction" =~ /^$transaction$/ AND "statut" = 'ok') AND $timeFilter GROUP BY time($__interval)

for total TPS (throughput) and:

SELECT mean("pct95.0") FROM "$measurement_name" WHERE ("application" =~ /^$application$/) AND $timeFilter GROUP BY "transaction", time($__interval) fill(null)

to plot the 95th‑percentile response time per transaction.

node_exporter + Prometheus + Grafana Data Flow

For OS‑level metrics, node_exporter exposes counters from /proc. Prometheus scrapes them (e.g., node_cpu_seconds_total) and stores them as time‑series. Grafana then queries these series to display CPU usage, memory, disk I/O, etc.

Example prometheus.yml snippet:

- job_name: 's1'
  static_configs:
  - targets: ['172.17.211.143:9200']

After starting both node_exporter and Prometheus, add Prometheus as a data source in Grafana and import an official node_exporter dashboard (ID 11074).

Typical CPU usage query used in the dashboard:

avg(irate(node_cpu_seconds_total{instance=~"$node",mode="system"}[30m])) by (instance)
+ avg(irate(node_cpu_seconds_total{instance=~"$node",mode="user"}[30m])) by (instance)
+ avg(irate(node_cpu_seconds_total{instance=~"$node",mode="iowait"}[30m])) by (instance)
+ 1 - avg(irate(node_cpu_seconds_total{instance=~"$node",mode="idle"}[30m])) by (instance)

These queries retrieve the same counters that the Linux top command shows, confirming that Grafana is visualising raw OS metrics.

Summary

Understanding the data flow—from JMeter or node_exporter, through InfluxDB or Prometheus, to Grafana—helps performance engineers interpret what the numbers mean, not just how they look. The combination of exporters, time‑series databases, and Grafana dashboards provides real‑time insight while preserving the ability to drill down into raw metrics for root‑cause analysis.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Performance TestingPrometheusJMeterInfluxDBGrafananode_exporter
MaGe Linux Operations
Written by

MaGe Linux Operations

Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.