Observability Alerts: Best Practices

Observability

Use the decision tree below to classify any new alert. Every alert must have a severity tier (Critical or Warning) assigned before merging.

Alerts are one of the easiest observability tools to get wrong. Too few alerts and incidents go unnoticed. Too many noisy alerts and on-call engineers stop trusting the system. This guide focuses on the middle ground: alerts that reflect real user impact, page at the right severity, and help the responder act quickly.

Quick Definitions

  • Critical alert: a page-worthy issue that needs immediate action because user impact is already happening or imminent
  • Warning alert: an early signal that something is drifting and should be investigated before it becomes critical
  • SLO: Service Level Objective, a target such as availability or latency that defines acceptable service behaviour
  • Error budget: the amount of failure allowed before the SLO is considered breached
  • Composite alert: an alert that combines multiple conditions, so a page is triggered only when signals correlate

Alert Decision Tree

The tree maps alert type (Application / Infra / Database / SQS) to severity based on impact thresholds:

Note- This is just a sensible default, you need to customise the threshold based on your context. DO NOT FOLLOW THE THRESHOLDS AS IS.

Observability alerts decision tree showing Application, Infra, Database and SQS tiers with critical and warning thresholds

Why These Thresholds?

Thresholds are derived from two principles:

  1. Signal the symptoms users feel. A 5% error rate means 1 in 20 requests fails, users notice 1% is noise in healthy distributed systems.
  2. Give time to act before SLO burn. If your 30-day SLO error budget allows 0.1% errors, a 5% error rate burns 50× your budget, every minute counts.

Always tune thresholds to your traffic. A threshold that generates > 5 pages/week is miscalibrated, tighten the window or raise the percentage.

Key takeaway: good alert thresholds are based on impact and actionability, not round numbers chosen in isolation.

Application Monitoring

Application alerts should reflect what users are experiencing first: failed requests, slow responses, and unusual traffic changes.

MetricGuidelineWhy
LatencyAlert on sudden spikes or gradual increases in average response timeUser experience degrades; SLO breach risk
Error ratesThreshold: 5% of requests in error1-in-20 failure rate is user-visible
Error CodeBased on 4XX or 5XX5XX = our fault (critical); 4XX = client errors (warning)
ThroughputAlert on sudden spikes and unexpected dropsTraffic anomalies indicate upstream incidents or abuse
Apdex scoreAlert if Apdex falls below 0.7 for 10 minutesApdex < 0.7 means majority of users are experiencing degraded response

Apdex formula:

Apdex = (Satisfied + Tolerating / 2) / Total samples
Where:
Satisfied = requests <= threshold (e.g. 300ms)
Tolerating = requests <= 4× threshold (e.g. 1200ms)
Frustrated = requests > 4× threshold

Key takeaway: Application alerts are strongest when they focus on symptoms users feel directly.

Infra Alerts

Infrastructure alerts matter, but they are usually supporting signals rather than the primary page trigger.

MetricCritical thresholdWarning thresholdWhy
CPU usage>90% for 10 min>80% for 10 minSustained high CPU leads to request queuing and latency spikes
Memory usage>90% for 10 min>80% for 10 minOOM kills cause pod restarts and dropped in-flight requests
Disk space<10% free<20% freeDisk full causes process crashes; write failures are silent and dangerous
Network throughputSudden spike/drop > 50% baselineTraffic anomaly signals upstream incident or DDoS

Key takeaway: infra alerts are most useful when they support or explain a user-visible symptom instead of paging on harmless fluctuations.

Database Alerts

Database issues amplify quickly because one slow query or an exhausted pool can affect every request path that depends on it.

MetricGuidelineWhy
Query performanceAlert on queries > 1 second (P95)Slow queries cascade into connection pool exhaustion
Connection pool utilizationAlert at >80% connections usedSaturation causes request queuing; >90% = imminent failure
Replication lagAlert if lag > 30 secondsReads from replica become stale; affects consistency guarantees
Index usageAlert on full table scans on tables > 10k rowsSeq scans are O(n); at scale they block other queries
CPU UtilizationAlert >80% for 10 minDatabase CPU contention affects all queries
Memory utilizationAlert >90% for 10 minShared buffer eviction causes dramatic query slowdowns

Real-World Scenario

A service may still appear healthy at the application layer until connection pool usage starts climbing and slow query latency rises at the same time. By the time requests begin failing, the root cause was already visible at the database layer.

Key takeaway: Database alerts should catch saturation early enough to avoid turning localised slowness into full request failure.

SQS / Queue Alerts

Queue alerts are about backlog health. A growing queue is not always an outage, but it is often the earliest sign that producers and consumers are no longer balanced.

MetricGuideline
ApproximateAgeOfOldestMessage > 30 minMessages are accumulating. Consumer is falling behind
ApproximateNumberOfMessages spikeProducer surge or consumer crash
DLQ message count > 0Failed messages need investigation( likely a bug or schema mismatch)

Key takeaway: watch both message age and queue depth, because one tells you how long work is waiting and the other tells you how much work is piling up.


Composite Alerts (Alert on Correlation, Not Individual Metrics)

A single metric spike may be a blip. Page when multiple signals align:

Tip

Pattern: High error rate + latency spike + throughput drop together = likely outage.
High error rate alone = investigate before paging (could be a bad deploy to one pod).

Configure Datadog monitors with AND conditions or use composite alerts to reduce false positives.

Key takeaway: correlated signals produce far better pages than isolated metric spikes.

Alert Fatigue => How to Measure and Fix

Alert quality deteriorates over time. Track these metrics monthly:

MetricHealthyAction needed
Pages per on-call shift< 5> 10: review and raise thresholds
% alerts acknowledged without action< 20%> 40%: alert is noisy, recalibrate
% alerts leading to incident> 60%< 30%: alerts are too sensitive
Mean time to acknowledge< 5 min (P1)> 15 min: page routing is wrong

Key takeaway: if most alerts do not lead to action, the alerting system is training engineers to ignore it.

Configuring Alerts in Datadog

The exact tooling can vary, but every alert definition should make the same things obvious: what is being measured, what threshold matters, who is paged, and where the runbook lives.

Example: 5% error rate alert for a service:

# Datadog monitor (terraform resource style)
name: "[APP] High Error Rate - my-service"
type: metric alert
query: >
sum(last_5m):
sum:trace.http.request.errors{service:my-service}.as_rate()
/
sum:trace.http.request.hits{service:my-service}.as_rate()
> 0.05
message: |
Error rate > 5% for 5 minutes on my-service.
Runbook: https://wiki.example.com/runbooks/my-service/high-error-rate
@pagerduty-my-service-critical
thresholds:
critical: 0.05
warning: 0.02
notify_no_data: false
evaluation_delay: 60

Maintenance Windows and Suppression

Suppression should be intentional and time-bound. The goal is to avoid false positives during known events, not to hide problems permanently.

Always suppress alerts during:

  • Planned deployments (configure a @deploy downtime in Datadog for 15 min)
  • Known maintenance windows
  • Load tests (suppress only in non-prod environments)

Danger: ANTI-PATTERN

Never mute an alert without an expiry time.

“Just muting this for now” becomes a permanently silenced alert that lets the next real incident go undetected for hours.

Key takeaway: every suppression should have a reason, a scope, and an expiry.


Metrics Reference

Application Metrics

MetricMandatory
Throughput
Apdex
Latency => 90th, 95th percentile
Overall Error Rate
4XX Errors
5XX Errors
Custom ErrorsOptional
External Call latency 95th percentile
External call 4XX, 5XX error
End-to-end distributed tracing
Automatic deployment tracking
Code hotspots & thread-level insightsOptional

Database Metrics

Metric
Number of connections
Cache hit ratio
Proportion of index scans over total scans
Throughput =>Fetch, insert, update, delete
Deadlocks
Replication delay in bytes
CPU utilization
Locks
Dead rows, shared buffers

Infra Metrics

Metric
Node status
Current pods
Available pods
CPU Utilization
Memory usage
Network usage

Alert → Runbook Link (Required)

Every P1/Critical alert must link to a runbook. The runbook answers:

  1. What does this alert mean?
  2. How do I verify the issue?
  3. What are the immediate mitigation steps?
  4. When do I escalate?

Danger: ANTI-PATTERN

Alerting on every single 5XX individually with threshold = 1.

This creates alert fatigue, on-call engineers start ignoring pages because they’re too frequent. Aggregate over a time window and set a meaningful percentage threshold instead.

Danger: ANTI-PATTERN

Setting thresholds without baselining first.

Don’t set “CPU > 80%” without knowing your service normally runs at 60%. Set thresholds relative to your P95 baseline, not arbitrary round numbers.

Final Takeaways

  • Alert on user-visible symptoms first, then use infra and database signals as supporting evidence.
  • Assign severity based on impact and urgency, not habit.
  • Use composite alerts and alert-fatigue metrics to keep pages meaningful.
  • Tie every critical alert to a runbook so responders know what to do next.
  • Review thresholds regularly as traffic patterns and service behaviour change.
Balaji G
Written by
Balaji G

Leave a Reply

Discover more from 2G

Subscribe now to keep reading and get access to the full archive.

Continue reading