Skip to main content
Cloud DevOps Solutions
Get a quote Talk to an engineer

Monitoring & Observability

Linking Runbooks from Prometheus Alert Annotations

We write short runbooks for each paging alert and link them through a runbook_url annotation, so the notification itself carries the procedure. A CI check fails any paging rule without a valid link, which keeps the pairing from decaying over time.

Key takeaways

  • A paging alert without a runbook forces the on-call engineer to improvise at their worst moment.
  • The link lives in the alert rule annotations and appears in the page, chat message and Grafana.
  • Runbooks are short, tested and owned; they start from real incidents, not theory.
  • CI checks stop new alerts shipping without a runbook and catch dead links.
  • Some alerts need no runbook because they should not exist; deleting them is a valid outcome.

The 3am problem

An alert fires at 03:12: “HighErrorRate on payments-api”. The engineer is half awake. They open a laptop, find the dashboard, scan the panels, and then ask: is this normal, what usually fixes it, who knows this service? Five or ten minutes disappear before any action, and they are the most expensive minutes of the incident.

A runbook link in the alert removes most of that. It is a small piece of the monitoring and observability service with an outsized effect on response time, because it travels with the page. It is also where monitoring meets operations, which is why the same idea appears in our wider Managed DevOps runbooks work.

What good looks like

  • Every paging alert links to a runbook. No exceptions without a recorded reason.
  • The link is in the notification itself, not three clicks away.
  • The runbook matches the alert. Same name, same symptoms, same dashboard.
  • Short and tested. A second engineer has followed it successfully.
  • Owned. A named team reviews it.
  • Enforced by automation, not memory.

The annotation standard

We agree a small, consistent set of annotations across every rule:

AnnotationPurpose
summaryOne line: what is wrong, in plain words
descriptionA few lines with the affected labels and values, templated
impactWhat customers or systems feel
dashboard_urlThe relevant Grafana dashboard, pre-filtered
runbook_urlThe procedure to follow

A rule following this standard:

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: payments-alerts
  namespace: monitoring
spec:
  groups:
    - name: payments
      rules:
        - alert: PaymentsHighErrorRatio
          expr: |
            sum(rate(http_server_requests_total{service="payments-api",status=~"5.."}[5m]))
            /
            sum(rate(http_server_requests_total{service="payments-api"}[5m])) > 0.02
          for: 10m
          labels:
            severity: critical
            team: payments
          annotations:
            summary: "Payments API 5xx ratio above 2% for 10 minutes"
            description: "Error ratio is {{ $value | humanizePercentage }} on {{ $labels.service }}."
            impact: "Customers cannot complete payments."
            dashboard_url: "https://grafana.example.com/d/payments/payments-api"
            runbook_url: "https://github.com/your-org/runbooks/blob/main/payments/high-error-ratio.md"

The description uses Prometheus template functions, and $value is the evaluated expression result. The example URLs are placeholders for your own domains.

Annotations are only useful if the receiver shows them. In Alertmanager templates we include them in Slack text and in the details block of paging integrations, as shown in alert routing. Grafana’s own alert view also shows annotations, and many incident tools surface a runbook field. A quick test: fire a test alert and check whether you can reach the procedure in one tap from a phone lock screen notification.

Writing the runbooks

Start from the history

We pull the last months of firing alerts and the incident notes behind them. The questions we ask: what did the person check first, what finally fixed it, and what did they wish they had known? Those answers are the runbook. The template mirrors the one we use elsewhere: symptoms, impact, quick checks, actions, verification and escalation.

A compact example

# PaymentsHighErrorRatio

Owner: payments team. Last reviewed: 2026-09-20.

## Quick checks (two minutes)
1. Did a deploy land recently? `kubectl rollout history deploy/payments-api -n production`
2. Is the payment provider degraded? Check their status page.
3. Are database connections near the limit? See the "DB connections" panel.

## Actions
1. Recent deploy and errors began after it: `kubectl rollout undo deploy/payments-api -n production`
2. Provider outage: enable the fallback queue flag, then notify support.
3. Otherwise escalate to the payments developer on call.

## Verify
Error ratio under 1% for 10 minutes.

Kill the alert instead

Sometimes writing the runbook exposes that no meaningful action exists. “Wait and see if it resolves” is not a procedure. These alerts should be deleted, converted to a dashboard panel, or turned into a non-paging warning. Cutting noise this way is one of the most valuable by-products of the exercise, and it links back to the Alertmanager severity model.

Enforcing it in CI

Humans forget; pipelines do not. A simple check using yq and promtool can fail a pull request that adds a critical rule without a runbook:

# fail if any critical alert lacks a runbook_url
missing=$(yq -r '
  .spec.groups[].rules[]
  | select(.labels.severity == "critical" and (.annotations.runbook_url // "") == "")
  | .alert' rules/*.yaml)

if [ -n "$missing" ]; then
  echo "Critical alerts without runbook_url:"; echo "$missing"; exit 1
fi

promtool check rules rules/*.yaml

Adjust the file paths and extraction expression to match how your rules are stored, since a PrometheusRule wraps rule groups under spec, while a plain rule file does not. A weekly job that requests every runbook_url and reports non-200 responses catches dead links.

Decisions and trade-offs

Where to host. Git-rendered Markdown is durable and reviewable. A wiki is friendlier to edit but may share fate with your infrastructure. We often keep source in Git and mirror elsewhere. If you use a developer portal such as Backstage, the runbook can be surfaced there too.

One runbook per alert or per component. Per alert is precise. Per component reduces duplication when several alerts share a cause. We use per alert for paging rules and allow shared sub-procedures through links.

Automation. A runbook step that is safe and repetitive can become a script or pipeline job. The document should still explain when to use it. See how this builds on on-call schedule integration.

Failure modes

  • Placeholders left in: “TODO: add steps”.
  • Links to private spaces that on-call cannot open.
  • Pinned commit URLs that show an old version.
  • Runbooks nobody tested, assuming access the engineer does not have.
  • Copy-paste runbooks whose commands target the wrong environment.

Delivery and handover

You receive the annotation standard, runbooks for your paging alerts, the template, CI checks, and a review schedule. Ownership is assigned to named teams, and we show your developers how to add one when they add a new alert.

How to tell it is working

Measure the share of paging alerts with a valid runbook link (target all), time from acknowledgement to the first correct action, and the number of pages resolved by someone seeing the service for the first time. If a new on-call engineer can handle a routine alert on their first shift, it is working. To get your runbooks wired in, contact us.

References

How we deliver it

  1. 01

    Inventory paging alerts

    We list every alert that pages or can page, with its history of firing and what was done about it.

  2. 02

    Set the annotation standard

    A convention for summary, description, impact, dashboard_url and runbook_url on every rule.

  3. 03

    Write runbooks from incidents

    Each runbook is drafted from past firing events and the knowledge of the engineers who fixed them.

  4. 04

    Wire links into notifications

    Alertmanager templates and Grafana show the link prominently in every receiver.

  5. 05

    Enforce in CI

    A lint step checks that paging rules have the annotations and that links resolve.

  6. 06

    Review and prune

    Runbooks are updated after incidents, and alerts without actionable steps are tuned or deleted.

Tools and technologies

PrometheusPrometheusRuleAlertmanagerpromtoolGitMarkdownGitHub ActionsGrafanaSlackBackstagePagerDutyOpsgenie

Frequently asked questions

What is a runbook_url annotation?
It is a conventional annotation on a Prometheus alert rule holding a link to the procedure for handling that alert. Prometheus does not interpret it, but Alertmanager templates, paging tools and Grafana can show it in notifications. The kube-prometheus-stack default rules use the same convention.
What should an alert runbook contain?
What the alert means, the likely impact, quick diagnostic checks with exact commands, ordered remediation steps, how to verify recovery, rollback or safety warnings, and who to escalate to. Keep it short enough to read under stress. Background and design reasoning belong in a separate document.
Where should runbooks be stored?
Store them as Markdown in Git near the rules and code, reviewed through pull requests, and publish to a wiki if people prefer reading there. Make sure on-call can open them when your main systems are down, so avoid hosting them only on the infrastructure that is failing.
Do all alerts need a runbook?
Every alert that pages a human should have one. Warnings sent to a channel benefit from at least a description of what to check. An alert whose only runbook is 'ignore it' should be removed or downgraded, which is itself a worthwhile outcome of writing runbooks.
How do we stop runbook links going stale?
Add a CI check that fails when a paging alert has no runbook_url, and optionally a scheduled job that requests each link and reports failures. Assign owners, review runbooks after incidents, and use stable URLs, for example permalinks to main branch files rather than pinned commits.

Talk to an engineer about runbook_url alert annotations

Book a free 30-minute call. We review your current setup and tell you honestly whether and how we can help.

Written by Saddique Khan, DevOps / SRE / Cloud Consultant Engineer. Last updated 2026-10-08.