Sign in
← Observability
10 min · medium · Lesson 4 of 6

Grafana: dashboards and panels

Why visualize metrics, how dashboards and panels are built, and why a good dashboard answers a question instead of showing everything at once.

Why visualize metrics

Prometheus from the previous lesson stores metrics and can answer PromQL queries. But staring at numbers and raw queries isn't practical: the eye doesn't catch a trend in a column of digits. Grafana draws metrics as graphs. It connects to Prometheus as a data source and shows what's happening over time.

Grafana is a visualization layer: it doesn't store metrics itself. The data lives in Prometheus (and other sources), and Grafana queries and draws it. In its own database Grafana keeps only its own settings: users, dashboards, the list of data sources. By default that's a SQLite file inside Grafana.

Where Grafana gets its data

A data source is a record in Grafana about where to go for data: a type (Prometheus, Loki, PostgreSQL), an address and access parameters. A panel doesn't know Prometheus's address; it references a data source.

The request to Prometheus is sent by the Grafana server, not your browser. The browser asks Grafana for a graph; Grafana goes to the address from the data source and sends back the response. This mode is called Server (in the config, access: proxy), and it's the default for Prometheus. Hence the rule: the data source's address must open from the machine or container where Grafana runs. What opens in your own browser means nothing to it.

You can check a data source with the Save & test button on its page (Connections → Data sources). Grafana will go to the address and report whether it worked.

Dashboards and panels

A dashboard is a page with graphs on one topic (a service, a cluster, a queue). It's made of panels, each showing one metric or comparison.

API dashboard RPS Latency p95/p99 5xx errors Memory

Each panel is a PromQL query rendered over time. The "5xx errors" panel shows rate(http_requests_total{status="500"}[5m]) from the Prometheus lesson, just as a graph instead of a number.

A panel has three parts: a data source, a query and a view (graph, number, table). You change the query and view in the panel editor: Edit in the panel menu. For one-off questions without a dashboard there's the Explore section: you write a query there and see the result right away.

At the top of the dashboard you pick a time range (Last 15 minutes, Last 6 hours). All panels render for that range.

A good dashboard answers a question

It's tempting to put every metric you have on a dashboard. That makes it useless: you can't find the one graph you need among a hundred during an incident. A good dashboard is built around the question it has to answer.

A common set for a service is the golden signals from the Google SRE book: traffic (requests per second), errors (the 5xx share), latency (p95/p99), saturation (CPU, memory). Four panels are usually enough to tell in seconds whether a service is healthy. You look at the details on separate dashboards once you already know where to dig.

For a service with the metrics http_requests_total and the histogram http_request_duration_seconds, the queries look roughly like this:

sum(rate(http_requests_total{service="api"}[5m]))
sum(rate(http_requests_total{service="api",status=~"5.."}[5m])) / sum(rate(http_requests_total{service="api"}[5m]))
histogram_quantile(0.99, sum by (le) (rate(http_request_duration_seconds_bucket{service="api"}[5m])))

The first counts traffic, the second the share of 5xx responses, the third the p99 latency from the histogram buckets. Saturation comes from resource metrics, for example process memory.

Variables and templates

To avoid building an identical dashboard for every service, Grafana has variables. You build the dashboard with a service variable and use it in queries ({service="$service"}). A dropdown shows up at the top, and one dashboard displays any service. It's the same idea of reuse as variables in Terraform.

Grafana usually pulls the variable's values from Prometheus itself. The variable type is Query, with a query like label_values(http_requests_total, service): every value of the service label on that metric. A new service shows up in the list with no changes to the dashboard.

If you let the variable select several values or All, Grafana substitutes them as a regular expression. Then the query needs the =~ operator instead of =: {service=~"$service"}.

Dashboard as code

A dashboard built by clicking around lives in one Grafana's database. You can export it to JSON (Export → Export as JSON) and put it in git. On startup, Grafana can pick up data sources and dashboards from files on its own: this is called provisioning. Data sources are described in YAML under /etc/grafana/provisioning/datasources/, dashboards are wired through YAML under /etc/grafana/provisioning/dashboards/, which points to a folder of JSON files.

apiVersion: 1
datasources:
  - name: Prometheus
    type: prometheus
    access: proxy
    url: http://prometheus.example.internal:9090

A data source set by a file can't be fixed in the UI when editable: false: Grafana reads the file at startup, so you edit the file and then restart Grafana.

Common mistakes

What you'll need for the tasks

Done reading?

Mark the lesson as read to move your track progress forward.

Go through it with an AI agent

The agent explains anything unclear in plain words, gives you 2 labs for this lesson and drills you on interview questions. $49 one-time, lifetime access.

Get access for $49

Tell the agent: use MCP izi, give me lesson observability-basics-04-grafana-dashboards