Dashboard design: RED, USE, golden signals

Grafana · Advanced · 10 min

Most dashboards fail not for lack of data but because nobody can answer "is it broken, and where?" from them in thirty seconds.

Good dashboards answer a question for an audience. Three well-known frameworks tell you which panels belong on them:

  • RED for request-driven services: Rate (requests per second), Errors (failed requests per second or error ratio), Duration (latency distribution, p50/p95/p99 or a heatmap). One row of RED per service, split by endpoint below.
  • USE for resources (CPU, memory, disk, network, queues): Utilization (how busy), Saturation (how much queued or over capacity), Errors.
  • The four golden signals from Google's SRE book: latency, traffic, errors and saturation, which is RED plus saturation.

Organise dashboards as a hierarchy with links between the levels: an overview with one stat row per service (traffic, error ratio, p95, with thresholds), a per-service dashboard with the RED rows and dependencies, and detail dashboards per instance, pod or database. Data links and tag-based dashboard links let you drill down without losing the time range.

Layout conventions:

  • Top-left is the most important thing; summary stats first, time series below, tables and logs last.
  • Same unit, colour and Y-axis scale for the same quantity everywhere; green/yellow/red thresholds only where they mean something, taken from your SLOs.
  • Short titles, a description on every non-obvious panel (shown on hover), and legend names that fit.
  • One dashboard per audience and purpose; a wall screen, an on-call view and a capacity planning dashboard are different dashboards.

Finally, use variables for environment and service so you maintain one dashboard, and keep it in version control.

Example

# Service overview row (per $service), RED
# Rate (req/s)
sum(rate(http_requests_total{service="$service"}[$__rate_interval]))
# Error ratio (percentunit, thresholds at SLO: orange 0.1%, red 1%)
sum(rate(http_requests_total{service="$service", status=~"5.."}[$__rate_interval]))
  / sum(rate(http_requests_total{service="$service"}[$__rate_interval]))
# Duration p95 (seconds)
histogram_quantile(0.95, sum by (le) (
  rate(http_request_duration_seconds_bucket{service="$service"}[$__rate_interval])))

# Resource row, USE (CPU)
# Utilization
1 - avg(rate(node_cpu_seconds_total{mode="idle", instance=~"$instance"}[$__rate_interval]))
# Saturation (run queue per core)
node_load1{instance=~"$instance"} / count without (cpu, mode) (node_cpu_seconds_total{mode="idle", instance=~"$instance"})

Remember

  • RED for services, USE for resources, golden signals = RED + saturation
  • Build a drill-down hierarchy: overview, service, instance, linked with time range preserved
  • Consistent units, colours and thresholds tied to SLOs

Watch out for

  • A dashboard that is a dump of every metric the exporter has, instead of the handful that answer "is it healthy?".

Check yourself

  1. Which three panels make up a RED row for an HTTP service?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: grafana.com/docs/grafana/latest/dashboards/build-dashboards/best-practices/