WSS
On this page
Monitoring & ObservabilityRequiredUpdated

Prometheus exposition format

The open, text-based standard for exposing dimensional metric data over HTTP so that monitoring systems can scrape and index it.

What it is

In the past, monitoring agents were “push-based.” A server would run a proprietary binary that continuously pushed CPU metrics to a central vendor database.

Prometheus reversed this paradigm using a “pull-based” architecture. Applications do not push metrics anywhere. Instead, the application runs a tiny web server and exposes its current metric state as a plain-text HTTP endpoint (usually at /metrics).

The Prometheus Exposition Format is the strict, standardized syntax used to format this text. The central Prometheus server is configured with a list of target IPs; it simply loops through them, sending an HTTP GET /metrics to each one, downloading the text, parsing it, and indexing it into its time-series database.

Why it matters

The Prometheus Exposition Format is incredibly simple and entirely human-readable. It does not use complex XML, binary payloads, or deep JSON trees. Because it is simple plain text, any application in any programming language can expose metrics simply by concatenating strings.

This simplicity led to massive industry adoption. It became the de facto standard for cloud-native metrics. Today, almost every infrastructure tool (Kubernetes, Envoy, Traefik, PostgreSQL exporters) natively exposes this exact text format out of the box, allowing operators to monitor disparate systems using a single unified toolset. The format has since been officially standardized by the CNCF as the OpenMetrics standard.

How to implement

To expose metrics, an application must serve an HTTP response with the Content-Type: text/plain header. The payload must adhere to the exposition format syntax.

The Syntax

The format is line-based. Each line represents a single data point. Comments start with #.

The structure is: metric_name{label_name="label_value"} value timestamp

  • Metric Name: (Required) A string describing the metric (e.g., http_requests_total).
  • Labels: (Optional) Key-value pairs enclosed in {} that provide dimensional context (e.g., {status="200", method="GET"}).
  • Value: (Required) A float or integer representing the current state of the metric.
  • Timestamp: (Optional) A unix timestamp in milliseconds. Usually omitted, allowing the Prometheus server to assign the timestamp when it scrapes the data.

Example Payload

# HELP http_requests_total The total number of HTTP requests.
# TYPE http_requests_total counter
http_requests_total{method="post",status="200"} 1027
http_requests_total{method="post",status="500"} 12
http_requests_total{method="get",status="200"} 4509

# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 124.5

# HELP queue_depth Current number of items in the processing queue.
# TYPE queue_depth gauge
queue_depth 42

Common mistakes

Violating the Counter Rule

In Prometheus, a counter metric must only ever go up (or reset to zero if the application restarts). If an engineer uses a counter to track the number of active users, and they decrement the counter when a user logs off, the metric is invalid. If a metric goes up and down (like active users, memory usage, or queue depth), it must be explicitly defined as a gauge.

Emitting Timestamps Incorrectly

Developers often try to be helpful by attaching exact timestamps to their metrics. If the application’s clock is drifting by even a few seconds relative to the Prometheus server’s clock, Prometheus will reject the metrics entirely as “out of order” or “too far in the future.” Unless you are building an offline batch-processing job, omit the timestamp and let the scraper handle the time.

Malformed Label Syntax

The format is notoriously strict about whitespace.

  • http_requests_total {status="200"} is invalid (space before brace).
  • http_requests_total{status = "200"} is invalid (spaces around the equals sign). While the format is technically just strings, developers should always use an official Prometheus client library (e.g., client_golang or client_python) to generate the output rather than attempting to write string-concatenation logic themselves.

Verification

Because the format is plain text served over standard HTTP, verifying that an application is correctly exposing metrics is trivial. You do not need a Prometheus server to test it.

Simply curl the application’s metric endpoint:

curl -s http://localhost:8080/metrics | grep "http_requests_total"

If the terminal outputs the raw, correctly formatted text lines, the application is successfully instrumented and ready to be scraped.

Related topics

Sources & further reading