HAProxy itself can expose metrics, but Prometheus needs an exporter to scrape them.

Let’s get HAProxy metrics into Prometheus. Imagine you’ve got HAProxy humming along, balancing traffic, but your monitoring system, Prometheus, is clueless about its internal state. That’s where the HAProxy Exporter comes in – it’s the translator, taking HAProxy’s internal stats and making them Prometheus-friendly.

Here’s how it typically looks in action. You’ll have HAProxy running, probably configured with a stats socket to expose its data.

listen stats
    bind :9000
    mode http
    stats enable
    stats uri /
    stats refresh 5s
    stats admin if TRUE
    stats socket /var/run/haproxy.sock mode 660 level admin

Then, you’ll have the HAProxy Exporter running as a separate process, configured to connect to that HAProxy stats socket.

# exporter.yml
scrape_configs:
  - job_name: 'haproxy'
    static_configs:
      - targets: ['localhost:9101'] # Where the exporter is listening
    metrics_path: /metrics
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        regex: (.*):9000 # Assuming HAProxy stats are on :9000
        target_label: instance
      - target_label: __address__
        replacement: 127.0.0.1:9101 # The exporter's address

And your HAProxy Exporter configuration would point to the HAProxy socket:

# Command to run the exporter
./haproxy_exporter --web.listen-address=":9101" --path.haproxy.url="unix:/var/run/haproxy.sock"

Prometheus, configured to scrape localhost:9101, will then pull metrics like haproxy_backend_http_requests_total and haproxy_frontend_connections_current.

The core problem this solves is visibility. HAProxy is a black box to Prometheus without an exporter. The exporter acts as an intermediary, querying HAProxy’s statistics interface (often a Unix socket or a TCP endpoint) and translating that data into the Prometheus exposition format. This allows Prometheus to collect metrics on request rates, connection counts, backend health, error rates, and much more, giving you the insight needed for effective load balancer monitoring and troubleshooting.

Internally, the HAProxy Exporter typically works by:

  1. Connecting to HAProxy: It uses the configured HAProxy URL (e.g., unix:/var/run/haproxy.sock or http://localhost:9000/stats) to establish a connection.
  2. Querying Stats: It sends specific commands (like show stat or show info) to HAProxy via the connection.
  3. Parsing Data: It parses the raw text output from HAProxy’s statistics interface.
  4. Formatting Metrics: It converts the parsed data into Prometheus metric types (counters, gauges, summaries) with appropriate labels (e.g., job, instance, backend, frontend).
  5. Exposing Metrics: It exposes these formatted metrics via an HTTP endpoint (defaulting to :9101/metrics) for Prometheus to scrape.

The exact levers you control are primarily in the HAProxy configuration and the exporter’s command-line flags. For HAProxy, the stats socket or stats uri are crucial. For the exporter, the --path.haproxy.url flag is paramount, ensuring it points to the correct HAProxy stats endpoint. You can also configure which metrics to expose or filter them using exporter-specific flags if needed.

When HAProxy is configured with stats socket and the exporter is successfully connecting to it, the exporter will start exposing metrics prefixed with haproxy_. If you see haproxy_exporter_scrapes_total incrementing but no haproxy_* metrics, it means the exporter is running and being scraped, but it’s failing to get any data from HAProxy. This almost always points to an issue with the --path.haproxy.url configuration, either the socket path being wrong, the Unix domain socket permissions incorrect, or the HTTP stats endpoint being inaccessible.

The next step is often to dive into HAProxy’s backend health metrics, like haproxy_backend_servers_status, to understand why specific servers might be marked as DOWN.

Want structured learning?

Take the full Haproxy course →