Skip to content

Expert · Monitoring and logging · topic 39 of 53 · 35 min

Prometheus and Grafana

Explanation

Prometheus is an open-source monitoring system that pulls (scrapes) metrics over HTTP from a /metrics page on each target and stores them as time series. You query them with PromQL, for example rate(http_requests_total[5m]), and write alert rules that Alertmanager routes to people. Grafana draws dashboards from Prometheus and many other data sources.

What Prometheus is

Prometheus is a free, open-source monitoring system and time series database. A time series is a list of values with time stamps, like "requests so far" every 15 seconds. It started at SoundCloud and is now a graduated project of the CNCF (Cloud Native Computing Foundation), the same home as Kubernetes. It is the default choice for metrics in most Kubernetes setups.

The parts

  • Prometheus server: scrapes targets on a schedule, stores samples in its local TSDB (time series database) and evaluates alert rules. Its web UI listens on port 9090.
  • Targets: anything that serves metrics as plain text over HTTP, usually at /metrics. Many apps expose this with a client library.
  • Exporters: small programs that translate metrics from things that cannot expose them themselves. node_exporter (port 9100) gives host metrics like CPU, memory, disk and network. There are exporters for MySQL, PostgreSQL, Redis and more, and blackbox_exporter for probing URLs from outside.
  • Service discovery: Prometheus can find targets automatically from Kubernetes, cloud APIs or files, so new pods are scraped without editing config by hand.
  • Alertmanager: receives alerts from Prometheus, removes duplicates, groups related ones, routes them to email, chat or a paging tool, and lets you silence them during maintenance. Port 9093.
  • Pushgateway: only for short batch jobs that finish before Prometheus could scrape them. The job pushes its final numbers there and Prometheus scrapes the gateway. Do not use it for normal services.

Prometheus uses a pull model: it pulls metrics from targets, the targets do not push. A bonus is that a failed scrape is itself a signal: the built-in metric up is 1 when the last scrape worked and 0 when it did not.

output
# HELP http_requests_total Total HTTP requests handled.
# TYPE http_requests_total counter
http_requests_total{method="GET",route="/orders",status="200"} 10234
http_requests_total{method="POST",route="/orders",status="500"} 12
# HELP process_resident_memory_bytes Resident memory size in bytes.
# TYPE process_resident_memory_bytes gauge
process_resident_memory_bytes 5.24288e+07
What a target returns at /metrics: plain text, one sample per line, with labels in curly brackets.

The four metric types

TypeBehaviourExamples
CounterOnly goes up; resets to 0 when the process restartsRequests served, errors, bytes sent
GaugeGoes up and downMemory in use, queue length, temperature, active users
HistogramCounts observations into buckets (_bucket with an le label, plus _sum and _count); percentiles are computed at query time and can be combined across serversRequest duration, response size
SummaryThe client computes chosen quantiles itself; cheap to query, but the quantiles of many servers cannot be correctly combinedRequest duration on a single process

Labels and the cardinality trap

Labels are key-value pairs that split a metric into separate series, such as method="GET" or status="500". Every unique combination of name and labels is its own time series. Cardinality means how many series you end up with. Labels with a few fixed values are fine. A label like user_id, email, order_id or a full URL with IDs in it creates millions of series and can run Prometheus out of memory.

A scrape config

yaml
global:
  scrape_interval: 15s       # how often to scrape every target
  evaluation_interval: 15s   # how often to check alert rules

rule_files:
  - "alerts.yml"

alerting:
  alertmanagers:
    - static_configs:
        - targets: ["alertmanager:9093"]

scrape_configs:
  - job_name: "orders-api"
    metrics_path: /metrics
    static_configs:
      - targets: ["orders-api:8080"]
  - job_name: "node"
    static_configs:
      - targets: ["10.0.1.11:9100", "10.0.1.12:9100"]
prometheus.yml: scrape the orders API and two servers running node_exporter, and send alerts to Alertmanager.

PromQL basics

PromQL is the query language of Prometheus. An instant vector is the latest value of each matching series, for example http_requests_total. A range vector is all samples in a time window, written with square brackets: http_requests_total[5m]. You cannot graph a range vector directly; you pass it to a function like rate().

output
rate(http_requests_total[5m])

sum by (status) (rate(http_requests_total[5m]))

sum(rate(http_requests_total{status=~"5.."}[5m]))
  / sum(rate(http_requests_total[5m]))

histogram_quantile(0.95, sum by (le) (rate(http_request_duration_seconds_bucket[5m])))
PromQL: per-second request rate; the rate per status code; the share of 5xx errors; p95 latency from a histogram.

rate() gives the average per-second increase of a counter over the window, and it handles counter resets when a pod restarts. sum by (status) adds up all series but keeps the status label separate. =~ means "matches this regular expression", so "5.." matches 500 to 599. histogram_quantile() estimates a percentile from histogram buckets; keep the le label when you sum.

Alert rules

yaml
groups:
  - name: orders-api
    rules:
      - alert: OrdersHighErrorRate
        expr: |
          sum(rate(http_requests_total{job="orders-api",status=~"5.."}[5m]))
            / sum(rate(http_requests_total{job="orders-api"}[5m])) > 0.05
        for: 10m
        labels:
          severity: page
        annotations:
          summary: "orders-api error rate is above 5%"
          description: "Error rate is {{ $value | humanizePercentage }} for the last 10 minutes."
          runbook_url: "https://wiki.example.com/runbooks/orders-high-error-rate"
alerts.yml: expr is the condition, for is how long it must stay true, labels help routing, annotations carry the message and runbook link.

While the condition is true but for has not passed, the alert is "pending". Only after 10 minutes in a row does it "fire" and go to Alertmanager. This stops one bad scrape from waking someone up.

Grafana

Grafana is an open-source tool for dashboards. It does not store metrics itself; it connects to data sources such as Prometheus, Loki, Elasticsearch, PostgreSQL, MySQL, Amazon CloudWatch and Azure Monitor, and shows them as panels. Variables add drop-downs (choose the service or namespace) so one dashboard serves many services. Dashboards are saved as JSON, so you can keep them in Git.

On Kubernetes: kube-prometheus-stack

bash
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm install monitoring prometheus-community/kube-prometheus-stack \
  --namespace monitoring --create-namespace
One Helm chart installs the Prometheus Operator, Prometheus, Alertmanager, Grafana, node_exporter, kube-state-metrics and ready-made dashboards and rules.

With the operator, you tell Prometheus what to scrape by creating a ServiceMonitor object next to your app, instead of editing prometheus.yml.

Careful: Common mistakes: (1) Graphing a raw counter; it only climbs. Wrap it in rate(). (2) Using rate() on a gauge; use the gauge directly or avg_over_time(). (3) Summing before rate(): always rate first, then sum. (4) Putting user IDs or order IDs in labels; that explodes cardinality. (5) Using Pushgateway for long-running services; it hides whether they are up.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Prometheus and Grafana · 1/8

Prometheus and Grafana

In this lesson you will meet Prometheus and Grafana, the most common open-source pair for metrics and dashboards.

Prefer a video by a teacher? Find free videos on “prometheus grafana tutorial promql alertmanager for beginners” on YouTube ↗

In real life: A college fest ticket site

A student team runs the ticket site for an engineering college fest. They add a Prometheus client library to their Node.js app, run node_exporter on the two VMs, and install Prometheus and Grafana with Docker Compose. When ticket sales open at 6 pm, the Grafana panel built from sum by (status) (rate(http_requests_total[1m])) shows 500 errors climbing. The p95 panel from histogram_quantile shows the payment callback at 8 seconds. An alert rule with for: 5m pages the team lead, who finds the payment webhook timing out and raises its worker count.

output
sum by (route) (rate(http_requests_total{status=~"5.."}[1m]))
PromQL: 5xx errors per second for each route, to see which page is failing.

Practice (0/3 done)

Task 1 · Question

How does Prometheus normally get metrics from your orders API?

Task 2 · Code · Python

Write counter_rate(samples), a simplified PromQL rate(). samples is a list of (time_in_seconds, counter_value) tuples in time order. Add up the increase between each pair of neighbouring samples. If a value is LOWER than the one before, the counter was reset (the process restarted from 0), so the increase for that step is just the new value. Divide the total increase by the seconds between the first and last sample and round to 3 decimal places. With fewer than 2 samples return 0.0. (Real Prometheus also extrapolates to the window edges; ignore that here.)

Task 3 · Practice

Your team runs a "payments" service on port 9000 at payments:9000 and two Linux hosts at 10.0.2.21 and 10.0.2.22 with node_exporter. Write (a) the scrape_configs part of prometheus.yml, and (b) an alert rule that pages when the p95 latency of payments, from the histogram http_request_duration_seconds, is above 2 seconds for 10 minutes.

Quick quiz

Question 1

1.Which metric type fits "number of items waiting in the email queue right now"?

Question 2

2.What does rate(http_requests_total[5m]) return?

Question 3

3.Which label is a cardinality danger?

Question 4

4.When should you use the Pushgateway?

Question 5

5.An alert rule has for: 10m. What does that mean?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

Which metric type fits "number of items waiting in the email queue right now"?

Answer: Gauge

The queue length goes up and down, so it is a gauge.

What does rate(http_requests_total[5m]) return?

Answer: The average per-second increase of the counter over the last 5 minutes

rate() turns a counter into a per-second rate over the window and handles resets.

Which label is a cardinality danger?

Answer: user_id="9875512"

A user ID has millions of possible values, so it creates millions of time series.

When should you use the Pushgateway?

Answer: For a short nightly batch job that ends before it could be scraped

Pushgateway is only for short-lived batch jobs; long-running services should be scraped.

An alert rule has for: 10m. What does that mean?

Answer: The condition must stay true for 10 minutes before the alert fires

Until for has passed the alert is pending; it fires only if the condition holds the whole time.

How does Prometheus get metrics from a Go service?Related

Answer: Prometheus scrapes an HTTP endpoint such as /metrics

Prometheus pulls metrics over HTTP on a schedule.

From Go in cloud and DevOps: Kubernetes, Terraform and Prometheus

Why add for: 10m to an alert rule?Related

Answer: So a short spike does not page anyone; the condition must hold for 10 minutes

for prevents flapping alerts from brief spikes.

From Alerting and on-call

Your EC2 dashboard shows CPU but no memory use. Why?Related

Answer: EC2 cannot see inside the OS; install the CloudWatch agent

The hypervisor sees CPU, network and disk I/O, but not memory used inside the OS. The CloudWatch agent sends it as a custom metric.

From Monitoring with CloudWatch, CloudTrail and Config

Why should an alert include a runbook_url?Related

Answer: The person paged can follow written first steps instead of guessing at 3 a.m.

A runbook link turns an alert into a clear next action.

From Capstone project: from commit to monitored production

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 2 more topics in “Monitoring and logging” before its exam: Logging: structured, safe and centralised, Alerting and on-call.
  2. Module 9 exam: Monitoring and logging · 13 questions · 20 min, without help. 4 topics of this module still to finish first.
  3. Then the next module, SRE: reliability and incidents. 53 topics left in the course before the final exam.

← Previous: Monitoring and observability: metrics, logs and traces