StackPractices
beginner By Mathias Paulenko

Monitoring and Alerting Policy Template

A policy template that defines how alerts are configured, routed, escalated, and reviewed across services and infrastructure.

Overview

A Monitoring and Alerting Policy defines how an organization detects problems, notifies the right people, and escalates when issues aren’t resolved quickly. Without a clear policy, teams drift into one of two failure modes: alert fatigue from paging on noise, or missed incidents because nobody owned the signal. This template gives you a structured framework for severity levels, thresholds, routing rules, escalation paths, and the review cadence that keeps the whole thing honest.

A typical trigger for writing this policy: the on-call rotation just burned out because P2 pages fired all night on alerts nobody could act on. Writing the rules down — who gets paged, for what, and when it escalates — is the fix. If you need the monitoring platform itself rather than the policy layer, the Complete Guide to Observability with the Grafana Stack covers the tooling side.

When to Use

  • Setting up a new observability platform or monitoring stack.
  • Onboarding a new service or team into the alerting system.
  • Reviewing alert quality after a period of noise or missed incidents.
  • Defining on-call responsibilities and escalation paths.
  • Preparing for an audit of operational maturity or incident response.

When not to use it: a two-person team running one service doesn’t need a formal routing matrix — a shared Slack channel and a paging rotation will do. The policy earns its keep once two or three teams share infrastructure and “who responds” stops being obvious.

Prerequisites

  • A monitoring and observability platform such as Prometheus, Datadog, Grafana, New Relic, or PagerDuty.
  • A list of critical services and infrastructure components.
  • Defined on-call rotations and escalation contacts.
  • A communication channel for alerts, such as Slack, Microsoft Teams, or email.
  • An incident response process that alerts will trigger.

The Policy Template

The six tables below are the template body. Copy them into your internal docs, replace the example values, and fill in your own teams, channels, and thresholds. The prose after each table explains the reasoning so the policy survives contact with reviewers.

1. Alert Severity Levels

SeverityResponse TimeExampleNotification Channel
P1 - CriticalImmediate (5 min)Service down, data loss, revenue impactPage on-call + executive notification
P2 - High15 minutesDegraded performance, failed backupsPage on-call + Slack alert
P3 - Medium1 hourHigh error rate, resource pressureSlack or email to owning team
P4 - LowNext business dayCapacity warning, non-urgent driftEmail or dashboard notice
P5 - InformationalNoneUsage metrics, trend dataDashboard only

The important line is between P2 and P3: P1 and P2 interrupt a human, everything below doesn’t. Keep that line strict. If you find yourself paging on P3 events, either they’re miscategorized or your thresholds are too tight — the scorecard below helps you catch that.

2. Alert Categories

CategoryPurposeExamples
AvailabilityDetect service unreachabilityHTTP 5xx, connection timeout, health check failure
PerformanceDetect latency and throughput issuesp99 latency > 500ms, queue depth high
CapacityDetect resource exhaustionCPU > 85%, disk > 80%, memory pressure
Error rateDetect unusual failure ratesError rate > 1% for 5 minutes
SecurityDetect suspicious activityFailed logins, rate limit hits, blocked traffic
BusinessDetect revenue or workflow impactFailed payments, order drop, signup failure
Data healthDetect pipeline or data quality issuesStale data, missing partitions, sync lag

Categories matter for routing more than for dashboards. An availability alert and a business alert often need different responders even when they fire on the same service, so label every rule with its category and let the routing layer sort it out.

3. Alert Routing Matrix

TeamPrimary HoursOn-Call HoursChannelsEscalation Path
Platform team08:00 - 18:00 UTC24/7PagerDuty, #platform-alertsManager, then VP Engineering
Application team08:00 - 18:00 UTC24/7PagerDuty, #app-alertsTeam lead, then Engineering manager
Security team24/724/7PagerDuty, #security-alertsSecurity lead, then CISO
Database team08:00 - 18:00 UTC24/7PagerDuty, #db-alertsDBA lead, then Platform manager
Business operationsBusiness hoursNoneEmail, SlackOperations manager

Route to the team that can fix the problem, not to a central queue that re-dispatches. Every hop between the alert and the responder adds minutes you can’t afford on a P1. The escalation path column pairs naturally with an escalation policy template if you need the full on-call contract.

4. Alert Threshold Guidelines

SignalWarning ThresholdCritical ThresholdEvaluation Window
HTTP error rate> 1% for 5 min> 5% for 2 minRolling 5 min
Response latency p99> 500ms for 10 min> 1s for 5 minRolling 10 min
CPU utilization> 70% for 10 min> 90% for 5 minRolling 5 min
Disk utilization> 75% for 1 hour> 90% for 15 minRolling 15 min
Memory utilization> 80% for 10 min> 95% for 5 minRolling 5 min
Queue depth> 1000 for 10 min> 5000 for 5 minRolling 5 min
Failed backupN/AAny failed backupPer job run
SSL certificate expiry< 30 days< 7 daysDaily check

Treat these numbers as starting points, not gospel. Pull your last 90 days of metrics, look at where real incidents started, and set the warning threshold just below that line. Thresholds copied from a template without historical data are how you end up paging on noise — and the quarterly calibration row in the maintenance table exists to fix exactly that.

5. Escalation Rules

SeverityInitial AlertNo AcknowledgmentStill UnresolvedFinal Escalation
P1Page on-call immediately5 min15 minExecutive notification + war room
P2Page on-call15 min30 minManager page
P3Slack to owning team1 hour4 hoursManager notification
P4Email or dashboardNext business dayN/AWeekly review

Escalation timers are a contract with your on-call engineers: a page that isn’t acknowledged gets a louder page, not silence. If people routinely ignore the first notification, that’s a signal about alert quality, not about the engineers.

6. Alert Review and Maintenance

ActivityFrequencyOwnerOutput
Alert quality reviewWeeklyOn-call engineerTop noisy alerts, tuning actions
Alert runbook reviewMonthlySRE teamUpdated runbooks for each alert
Threshold calibrationQuarterlyObservability teamThreshold adjustments with evidence
On-call retroAfter major incidentIncident commanderAlert improvements, follow-up tasks
Policy reviewAnnuallyEngineering leadershipUpdated policy document

The weekly quality review is the most valuable row in this table. Fifteen minutes of “which alerts fired, which were actionable” catches alert fatigue before it becomes a staffing problem. Post-incident reviews pair well with a postmortem incident review template when the incident is big enough to document.

How the Policy Works in Practice

An alert follows a predictable lifecycle: a metric crosses a threshold, the rule fires, the routing layer hands it to the owning team, someone acknowledges it, and the escalation timer runs in the background in case they don’t. The review loop at the end is what keeps the system calibrated — every noisy alert that survives a review becomes tomorrow’s missed page.

Alert lifecycle — a metric crossing a threshold fires a rule, gets routed to the owning team by severity, is acknowledged or escalates, and feeds a weekly review that tunes or removes noisy alerts

Two design choices carry most of the weight. First, severity drives both the channel and the clock: paging channels exist only for P1/P2, and escalation timers shrink as severity rises. Second, every alert carries a runbook link, so the responder’s first action is documented rather than improvised.

Prometheus Alert Rules Example

Here’s how the policy’s severity labels and thresholds translate into real Prometheus rules — each alert carries severity and team labels that the routing config below keys on:

groups:
  - name: api_alerts
    interval: 30s
    rules:
      - alert: HighErrorRate
        expr: |
          sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
          / sum(rate(http_requests_total[5m])) by (service) > 0.05
        for: 2m
        labels:
          severity: P1
          team: platform
        annotations:
          summary: "{{ $labels.service }} error rate > 5%"
          description: "{{ $labels.service }} has {{ $value | humanizePercentage }} error rate for 2 minutes"
          runbook: "https://runbooks.example.com/high-error-rate"

      - alert: HighLatencyP99
        expr: |
          histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[10m])) by (le, service)) > 1
        for: 5m
        labels:
          severity: P2
          team: platform
        annotations:
          summary: "{{ $labels.service }} p99 latency > 1s"
          runbook: "https://runbooks.example.com/high-latency"

      - alert: DiskSpaceLow
        expr: |
          (node_filesystem_avail_bytes{mountpoint="/"}
          / node_filesystem_size_bytes{mountpoint="/"}) * 100 < 10
        for: 15m
        labels:
          severity: P2
          team: infrastructure
        annotations:
          summary: "Disk space < 10% on {{ $labels.instance }}"
          runbook: "https://runbooks.example.com/disk-space"

Alertmanager Routing Configuration

The routing tree mirrors the policy’s severity table: P1/P2 go to PagerDuty with aggressive repeat intervals, P3 goes to Slack, P4 to email. Everything else falls through to the default receiver.

route:
  receiver: default
  group_by: ["alertname", "service", "severity"]
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  routes:
    - matchers:
        - severity = "P1"
      receiver: pagerduty-critical
      group_wait: 0s
      repeat_interval: 30m
    - matchers:
        - severity = "P2"
      receiver: pagerduty-warning
      group_wait: 30s
      repeat_interval: 2h
    - matchers:
        - severity = "P3"
      receiver: slack-alerts
      group_wait: 5m
    - matchers:
        - severity = "P4"
      receiver: email-alerts
      group_wait: 1h

receivers:
  - name: pagerduty-critical
    pagerduty_configs:
      - service_key: "P1_KEY"
  - name: pagerduty-warning
    pagerduty_configs:
      - service_key: "P2_KEY"
  - name: slack-alerts
    slack_configs:
      - channel: "#alerts"
        api_url: "SLACK_WEBHOOK_URL"
  - name: email-alerts
    email_configs:
      - to: "team@example.com"
  - name: default
    slack_configs:
      - channel: "#alerts"

group_wait and repeat_interval encode the escalation contract in config: P1 alerts group instantly and re-notify every 30 minutes until acknowledged, while P4 batches hourly. Tune these before you tune thresholds — grouping is usually the cheapest way to cut page volume.

Alert Quality Scorecard

Review each alert quarterly using this scorecard — six criteria, 1–5 points each, 30 points maximum:

CriterionScore (1-5)Notes
Actionable: Does the alert trigger a clear response?
Accuracy: Is the false-positive rate below 5%?
Timely: Does the alert fire before user impact?
Routed: Does it reach the team that can fix it?
Documented: Is there a runbook linked?
Unique: Is this alert redundant with another?

Score interpretation: 18 or more means the alert is healthy. Between 12 and 17, put it on a 30-day improvement plan with a named owner — usually that means tightening the threshold, fixing the routing, or writing the missing runbook. Below 12, delete it; an alert that isn’t actionable, accurate, or routed is training your team to ignore pages.

How to Roll Out This Policy

Adopting the template works best as a staged rollout rather than a big-bang rewrite:

  1. Inventory — list every existing alert, its severity claim, and where it routes. Most teams discover orphan alerts going to dead channels at this step.
  2. Draft severities — map existing alerts to the P1–P5 table. Expect most “critical” alerts to land at P3; that’s normal, not a problem.
  3. Wire routing — configure the routing matrix in your tooling (the Alertmanager config above covers the Prometheus stack) and test each path with a synthetic alert.
  4. Pilot on one team — run the policy with a single team for two weeks. Track pages per shift and false-positive rate.
  5. Review and widen — tune thresholds from the pilot data, then roll out to the remaining teams and start the weekly quality review.

The two-week pilot matters more than the document. A policy that survives contact with real alerts earns trust; one that pages at 3 a.m. for a capacity warning gets routed around within a month.

One last ownership note: assign the document itself an owner — usually the SRE or platform lead — and keep it in version control next to the alert configs it describes. Changes to thresholds or routing should go through the same pull-request review as the config changes that implement them. A policy that lives in a wiki nobody watches is indistinguishable from no policy at all.

Variants

  • Cloud-native alerting policy: Uses Prometheus Alertmanager, Grafana OnCall, or PagerDuty for container and serverless environments.
  • Enterprise IT monitoring policy: Focuses on infrastructure, network, and service desk integration.
  • Security alerting policy: Emphasizes SIEM rules, threat detection, and incident response triggers.
  • Business operations alerting: Tracks KPIs, revenue, and customer-facing metrics with business-hour notifications.
  • Developer self-service alerting: Allows teams to define their own alert rules within guardrails.
  • Multi-cloud alerting policy: Uses cloud-agnostic tools (Grafana, Datadog) to unify alerts across AWS, GCP, and Azure.
  • Cost alerting policy: Monitors cloud spend with budget thresholds and anomaly detection on cost metrics.
  • Compliance alerting policy: Tracks audit log gaps, failed access reviews, and policy violations for regulated environments.

What Works

  • Alert on symptoms that affect users, not just internal metrics.
  • Use multi-window or multi-burn-rate thresholds to reduce false positives.
  • Require every alert to have an associated runbook or troubleshooting link.
  • Route alerts to the team that can fix the problem, not a central queue.
  • Keep alert messages concise and include context such as severity, service, and impact.
  • Review noisy alerts weekly and tune or delete them.
  • Test escalation paths during regular drills.
  • Document alert thresholds and the rationale for changes.
  • Use alert grouping to batch related alerts into a single notification during incidents.
  • Implement alert suppression for known maintenance windows and deployments.

Common Mistakes

  • Alerting on every metric threshold without considering user impact.
  • Sending all alerts to a single channel with no routing.
  • Using the same severity for every alert.
  • Not requiring acknowledgment or tracking resolution time.
  • Ignoring alerts that fire repeatedly without action.
  • Missing escalation paths for severe incidents.
  • Failing to review and retire stale alerts after system changes.
  • Setting thresholds based on gut feeling instead of historical data.
  • Not including service name and environment in alert labels, making triage harder.
  • Alerting on absolute values instead of rates or ratios, causing false positives during traffic spikes.

Troubleshooting

  • Alert storm during a deploy: suppress alerts for the affected services during the window, or tighten group_by so 50 related alerts collapse into one notification.
  • Threshold flapping (fires, resolves, fires again): widen the evaluation window or add a second condition — a for clause alone won’t stop a metric oscillating around the line.
  • Pages for alerts nobody can act on: score them with the scorecard above; anything below 12 gets deleted, not silenced.
  • Alert fires but there’s no runbook: the annotation was skipped. Make the runbook link a required field in code review for new alert rules.
  • A silence left active after maintenance: expired silences are easy to forget; review active silences in the weekly alert review so yesterday’s maintenance doesn’t mute today’s incident.
  • Same alert routed to three channels: deduplicate receivers in the routing config, or accept it — but page duplication is a fast path to alert fatigue.

Further Reading

Frequently Asked Questions

What is alert fatigue and how do we avoid it?

Alert fatigue happens when on-call engineers receive too many low-value alerts. Avoid it by tuning thresholds, grouping related alerts, suppressing known issues, and regularly deleting alerts that don't lead to action.

Should every alert page someone?

No. Only P1 and P2 alerts should page the on-call engineer. Lower-severity alerts should use Slack, email, or dashboard notifications to avoid disrupting response time for critical issues.

How do we know if our thresholds are right?

Track the ratio of useful alerts to total alerts, measure mean time to acknowledge and resolve, and review false-positive rates. If an alert fires frequently without action, it's a candidate for tuning or removal.

What is multi-window alerting and why should I use it?

Multi-window alerting evaluates a condition over both a short and a long time window before firing — for example, error rate above 5% on both 1m and 5m windows. It prevents alerts from firing on transient spikes while still catching sustained issues. Prometheus supports this with the for clause and two expressions.

How do we handle alerts during planned maintenance?

Use alert suppression or silencing in your alerting tool. In Alertmanager, create a silence with start and end times and matchers for the affected services, and document the window in an incident channel so on-call engineers know why alerts are quiet. Never disable alerts globally; suppress only the specific rules affected, and review active silences weekly.

Should we use SLO-based alerting instead of threshold-based alerting?

SLO-based alerting (error budget burn rate) fits user-facing services because it measures user impact directly. Threshold-based alerting is simpler and works well for infrastructure metrics like CPU, disk, and memory. Use SLO-based alerting for critical user journeys and thresholds for infrastructure health — the SLO template covers the document side.

How many alerts should an on-call engineer receive per shift?

A healthy on-call shift has 0–2 pages (P1/P2) and 5–15 Slack or email alerts (P3/P4). If an engineer receives more than 5 pages per shift, the alerting policy needs immediate tuning. Track alert volume per shift and review it in the weekly on-call retro.

Do we need a NOC (L0) before the engineering team?

For 24/7 services with high alert volume, a NOC or first-line SRE rotation filters repeat alerts and runs known runbooks before escalating to engineering — it cuts pages to the engineering team. For small teams, the on-call engineer (L1) does this filtering directly. Either way, the top 10 most frequent alerts should have runbooks the first line can execute.

How do we prevent alert fatigue during incidents?

During active incidents, suppress dependent alerts that fire as a consequence of the root cause, and use alert grouping to bundle related alerts into one notification. Designate an incident commander who triages incoming alerts and assigns ownership. After the incident, review all suppressed alerts to confirm they were silenced correctly, and note which alerts were downstream symptoms versus the root cause in the runbook.