Skip to main content
In this lesson we’ll explain how Prometheus metrics are structured, how time series are formed, and how to interpret different metric types. You’ll learn how labels and metric names work, the meaning of # HELP and # TYPE metadata, and practical guidance for avoiding high-cardinality issues. A Prometheus metric has three main parts:
  • a descriptive name,
  • a set of labels (key/value pairs),
  • and a numeric value recorded at a specific time.
The text exposition format looks like:
Example from the Node Exporter:
This indicates that CPU 0 has accumulated 258,277.86 seconds in the “idle” state. If a machine has multiple CPUs, the same metric appears multiple times with different cpu labels:
Each unique metric name + label set identifies a separate stream of timestamped values (a time series). When Prometheus scrapes a target it records the sample timestamp (by default the scrape time) as a Unix timestamp (seconds since the epoch) for samples without an explicit timestamp. For example:
You can convert Unix timestamps using any Unix timestamp converter; dashboards typically render these in local time zones automatically. Stored samples therefore include a value plus a timestamp, e.g.:
The image is a diagram titled "Counter," highlighting metrics like "Total # requests," "Total # Exceptions," and "Total # of job executions," showing how these numbers can only increase.

Time series

A “time series” in Prometheus is a stream of timestamped values that share the same metric name and identical label sets (same keys and values). In other words: metric name + labels = time series. Examples:
Although there are only two metric names above, the different label combinations produce eight distinct time series. As Prometheus scrapes these targets periodically (for example every 15 or 30 seconds), it appends new timestamped values to each time series.

Metric metadata: HELP and TYPE

Prometheus text exposition may include two helpful metadata comments per metric:
  • # HELP — a short human-readable description of the metric.
  • # TYPE — the metric type (counter, gauge, histogram, summary).
Example:
Including # HELP and # TYPE in your exporters makes metrics easier to understand and reduces ambiguity when other engineers query or consume them.

Metric types

Prometheus defines four primary metric types. Here’s a concise reference you can use when designing instrumentation. Histograms collect counts for bucket boundaries (buckets are cumulative). For example, with buckets 0.2s, 0.5s, 1s you get counts of requests that completed in less than 0.2s, less than 0.5s (including those under 0.2s), and less than 1s (including those under 0.5s):
The image is an infographic about histograms, displaying response time and request size metrics along with a bar chart illustrating response time buckets.
Summaries report quantiles directly (for example 20%, 50%, 80%) and are calculated on the client side. Because quantiles in summaries are per-instance they are not directly aggregatable across multiple instances the way histogram bucket counts are.
The image is a summary slide comparing histogram-like data tracking, showing percentiles for response time and request size, with a bar chart illustrating response time percentiles.

Metric names and labels

Metric names should be descriptive and follow Prometheus naming conventions: ASCII letters, numbers, underscores, and colons. Avoid colons in custom metrics — they are typically reserved for recording rules. Labels are key/value pairs that further qualify a metric and let you slice and group metrics by attributes such as path, method, or instance. Label names may include ASCII letters, numbers, and underscores. Why labels are useful — a brief example: A naive approach would create separate metrics per endpoint:
This approach makes it hard to compute totals without knowing each metric name. A better approach uses a single metric with a path label:
You can then compute totals or grouped sums with PromQL:
Add other labels as needed (for example method="GET"). Each unique combination of label keys and values creates a distinct time series.
The image illustrates a comparison of two methods for calculating total API requests in an e-commerce app, highlighting the difficulty of calculating total requests across all paths versus summing requests using a specific method with labeled paths.
Internally, Prometheus stores the metric name as a label called __name__. Example:
Labels that begin and end with double underscores (for example __name__) are internal to Prometheus. Prometheus also automatically assigns two labels to every scraped metric:
  • instance — the target address that was scraped.
  • job — the scrape job name from your Prometheus configuration.
Example scrape job in prometheus.yml:
Avoid high-cardinality labels (for example, user IDs, session IDs, or highly variable full request paths). Every distinct label value combination creates a new time series, which can quickly exhaust memory and storage in Prometheus.

Quick references and further reading

Keep these practical rules in mind:
  • Use meaningful metric names.
  • Favor labels over separate metric names when the distinguishing characteristic is a dimension (e.g., path, method).
  • Choose histograms if you need to aggregate distributions across instances; use summaries for per-instance quantiles when aggregation across instances is not required.
  • Design labels to keep cardinality manageable.

Watch Video