Prometheus Exporters: Choosing the Right One and Writing Your Own
Exporters turn anything into Prometheus metrics. Here's how I pick a good off-the-shelf exporter and write a custom one when none exists.
- #prometheus
- #exporters
- #instrumentation
- #observability
- #sre
- #monitoring
Prometheus only knows how to scrape an HTTP endpoint that returns metrics in its text format. An exporter is the adapter that makes some other system — a database, a piece of hardware, a third-party API — speak that format. Most of monitoring is just pointing Prometheus at the right exporters. After wiring up hundreds of them, here’s how I choose and build them.
How an exporter actually works
An exporter is a tiny HTTP server that exposes /metrics. When Prometheus scrapes it, it returns plain text:
# HELP node_filesystem_avail_bytes Filesystem space available.
# TYPE node_filesystem_avail_bytes gauge
node_filesystem_avail_bytes{device="/dev/sda1",mountpoint="/"} 1.2e10
That’s the entire contract. Prometheus hits the URL on its scrape interval, parses the text, and stores the series. The exporter’s job is to translate “the current state of some system” into those lines, on demand, every time it’s scraped.
Reach for an existing exporter first
Before writing anything, check whether someone already solved it. The ecosystem is enormous and mature:
- node_exporter — host metrics: CPU, memory, disk, network. On every machine you run.
- cAdvisor / kube-state-metrics — container and Kubernetes object metrics.
- blackbox_exporter — probes endpoints from the outside (HTTP, TCP, ICMP, DNS).
- Database exporters —
postgres_exporter,mysqld_exporter,redis_exporter, etc. - Hundreds more — message queues, web servers, hardware, cloud APIs.
If a reputable exporter exists, use it. It has handled the edge cases you haven’t thought of yet, and you’re not on the hook to maintain it.
How to judge an exporter’s quality
Not all exporters are good. Before adopting one, I check:
- Is it maintained? Recent commits, open issues being answered. An abandoned exporter is tech debt.
- Does it follow naming conventions? Metrics should end in base units (
_bytes,_seconds,_totalfor counters). Bad naming infects every query you’ll ever write. - Does it bound cardinality? An exporter that puts table names, query text, or per-request IDs into labels will eventually kill your Prometheus. Read its label set before you trust it.
- Does it scrape cheaply? Some exporters run expensive queries on every scrape. Check what it does to the system it’s monitoring.
That cardinality check is the one people skip and regret. A “convenient” exporter that emits a series per database connection or per HTTP path can quietly multiply your series count into the millions.
When to write your own
You write a custom exporter when you have a system with no good exporter and metrics you actually need. The two shapes:
Direct instrumentation — your own app, using a client library, exposing /metrics from inside the process. This is the best case; the metrics live where the truth lives.
var requestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "myapp_requests_total",
Help: "Total requests handled.",
},
[]string{"method", "status"}, // bounded labels only
)
func init() { prometheus.MustRegister(requestsTotal) }
// in the handler:
requestsTotal.WithLabelValues(r.Method, statusClass).Inc()
Standalone exporter — a separate process that queries some third-party system and translates the result. You implement a Collector whose Collect method is called on each scrape, queries the source, and emits metrics. The key discipline: do the work in Collect, so each scrape reflects current state, and keep it fast.
Naming and types: get these right once
The conventions aren’t optional flourishes — they make your metrics queryable:
- Counters end in
_totaland only go up.http_requests_total. - Gauges go up and down.
queue_depth,temperature_celsius. - Base units, always: seconds not milliseconds, bytes not megabytes. Prometheus and Grafana know how to scale base units for display.
- Labels are bounded. Same cardinality rules as everything else — no IDs, no unbounded values.
A metric named myapp_latency_ms with a user_id label is two mistakes that will haunt every dashboard you build on it. myapp_request_duration_seconds with method and route labels is correct and will age well.
Validate before you ship
promtool checks your exporter’s output for convention violations:
curl -s localhost:9100/metrics | promtool check metrics
It flags non-standard units, missing HELP/TYPE lines, and counter naming issues. I run it against every exporter I write or adopt — catching a naming problem before it’s in production is free; renaming a metric that dashboards and alerts depend on is not.
Where AI helps
A custom exporter is mostly boilerplate: register the metrics, implement the collector, wire up the HTTP handler. I describe the source system and the metrics I want, and let AI scaffold the collector with the right metric types and bounded labels. It reliably gets the conventions right — base units, _total suffixes, no unbounded labels — which is exactly where hand-written exporters tend to slip.
It also helps audit an existing exporter’s metric list for cardinality and naming smells before you adopt it. We keep monitoring prompts for exporter design, and the alerts our Alert Rule Generator produces assume the conventions a good exporter follows.
The bottom line
Exporters are the unglamorous plumbing of Prometheus, and they’re where a lot of monitoring quality is won or lost. Use a maintained, well-named exporter when one exists; check its cardinality before you trust it; and when you write your own, follow the naming and unit conventions religiously. Get the plumbing right and everything downstream — queries, dashboards, alerts — gets easier.
Generated exporter code is assistive, not authoritative. Always review for cardinality, naming conventions, and scrape cost, and validate output with promtool before deploying.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.