Skip to main content
RunBook Academy

← All checklists in Observability

Quarterlyalert-review

Alert Quality Review

20 items ·11 critical ·8 warn ·1 info

Run this at least quarterly, on a calendar slot that is not negotiable, and treat the deferral of the review as a finding in its own right. Quarterly is the floor rather than the target: the course lesson on the alert quality review argues for monthly, on the grounds that bad alerts accumulate faster than a quarterly cadence can remove them. If your page volume is growing, run it monthly and shorten the windows in the commands below to match.

This is the outcome review. The Alerting Readiness checklist asks whether the chain can deliver; the Alert Review checklist asks whether each rule is a correct statement about a system that exists. This one asks a question neither of those can: given everything that happened last quarter, is the alerting stack earning the attention it costs.

Where the evidence comes from

Alertmanager is not the history. It holds the alerts that are currently active plus a short notification log, so a quarter-long audit reads either the ALERTS series that Prometheus generates for every firing rule, or a copy of the notification stream shipped somewhere that retains it. Establish which of those you have as the first item; every ranking below is only as long as that window.

Two of the most important numbers — pages actually delivered, and what a human did next — are not in the observability stack at all. They live in the paging system and the incident record. If those two cannot be joined to an alert name, the action rate cannot be computed, and that gap is the finding.

Where an item names a path or a Prometheus address, substitute the ones your estate uses. The 30d windows assume Prometheus retention covers the review period; widen or narrow them to match.

What this review produces

A pull request against the rule files, not a document. Each rule that fired gets one of three dispositions — keep, redesign, delete — and the disposition is the diff. The most suspicious possible outcome of an audit is an empty diff.

Sign-off

  • Reviewer: ________________ Date: ___________
  • On-call lead: _____________ Date: ___________
  • Platform owner: ___________ Date: ___________

Critical11 items

  1. amtool alert query --output=json | jq -r '[.[] | .startsAt] | min'
  2. curl -s -G http://prometheus:9090/api/v1/query --data-urlencode 'query=topk(20, sum by (alertname) (count_over_time(ALERTS{alertstate="firing"}[30d])))' | jq -r '.data.result[] | "\(.value[1]) \(.metric.alertname)"'
  3. comm -23 <(curl -s http://prometheus:9090/api/v1/rules | jq -r '.data.groups[].rules[] | select(.type=="alerting") | .name' | sort -u) <(curl -s -G http://prometheus:9090/api/v1/query --data-urlencode 'query=count by (alertname) (count_over_time(ALERTS[30d]))' | jq -r '.data.result[].metric.alertname' | sort -u)
  4. amtool silence query --output=json | jq -r '.[] | "\(.endsAt) \(.createdBy) \(.comment)"'
  5. curl -s -G http://prometheus:9090/api/v1/query --data-urlencode 'query=count_over_time(ALERTS{alertname=~".*Canary.*|Watchdog", alertstate="firing"}[30d])' | jq -r '.data.result[] | "\(.metric.alertname) \(.value[1])"'
  6. curl -s -G http://prometheus:9090/api/v1/query --data-urlencode 'query=increase(alertmanager_notifications_failed_total[30d])' | jq -r '.data.result[] | "\(.metric.integration) \(.metric.reason) \(.value[1])"'
  7. RULES_REPO=/srv/observability; git -C "$RULES_REPO" log --since='3 months ago' --oneline -- prometheus/rules/

Warning8 items

  1. grep -nE 'group_by|group_wait|group_interval' /etc/alertmanager/alertmanager.yml
  2. grep -n repeat_interval /etc/alertmanager/alertmanager.yml
  3. RULES_REPO=/srv/observability; PREV_TAG=alert-review-2026-Q2; git -C "$RULES_REPO" diff --stat "$PREV_TAG" -- prometheus/rules/

Info1 item