The metrics that actually matter

Notification systems generate a lot of possible metrics. Most of them don't predict incidents. The handful that do are the ones worth building dashboards and alerts around first.

Queue depth

A rising, unconsumed backlog on any channel's queue means workers can't keep up - either add capacity or something downstream is stuck.

Delivery success/failure rate, per channel

Tracked separately for SMS, email, and push - a drop in one channel's success rate almost always means that specific provider is degraded, not your whole system.

Latency per provider

p50/p95/p99 response time per provider call - a creeping p99 is often the earliest warning sign of an outage, well before the failure rate itself moves.

Structured logging: what to always include

Free-text logs ("Failed to send SMS") are close to useless for debugging a specific customer's complaint at scale. Every log line tied to a notification should carry the same structured fields, so you can filter and correlate across the whole pipeline instantly.

logger.info('notification_attempt', {
  notification_id: notif.id,
  idempotency_key: notif.idempotencyKey,
  channel: notif.channel,
  provider: 'twilio',
  attempt_count: notif.attemptCount,
  status: 'failed',
  failure_reason: err.code,       // e.g. 'rate_limited', 'invalid_number'
  provider_response_time_ms: elapsed,
  correlation_id: request.correlationId, // ties back to the originating business event
});

The field people forget: correlation_id. Without it, tracing "why didn't this specific payment confirmation arrive" back through the outbox row, the queue message, the retry attempts, and the final provider call requires manually cross-referencing timestamps - with it, it's one query.

Alerting thresholds that don't cry wolf

SignalAlert conditionWhat it usually means
Queue depthSustained growth over 10+ min, not a single spikeWorker capacity too low, or a downstream dependency is stuck
Per-channel failure rate>5% over a 5-minute rolling windowProvider degradation on that specific channel
DLQ depthAny sustained growth (not zero-tolerance, but non-flat)An integration is failing every retry attempt - needs investigation, not just replay
Circuit breaker state changeAny transition to "open"A provider is degraded enough that the breaker tripped - immediate, not delayed, alert
p99 provider latency>2x the 7-day baselineEarly warning of an outage, often before failure rate moves at all

Dashboards worth building first

1

Per-channel health board - queue depth, success rate, and p95 latency for SMS, email, and push, side by side.

2

DLQ inspector - current depth, growth rate, and a breakdown of failure reasons for whatever's sitting in it right now.

3

Circuit breaker status board - current state (closed/open/half-open) per provider, with a timeline of recent transitions.

Key takeaways

  • Queue depth, per-channel success/failure rate, and provider latency are the three metrics worth alerting on first - most others are noise until those three are solid.
  • Structured logs need a shared schema across every service in the pipeline - especially a correlation_id that survives from the originating event through to the provider call.
  • Alert on sustained trends, not single spikes - a 30-second blip in queue depth is normal; 10 minutes of continuous growth is not.
  • A circuit breaker opening should be an immediate alert, not a metric you check later - it means the system already decided a provider is unhealthy.
  • Build the per-channel health dashboard first - it's the one that turns "customers are complaining" into "we already saw this an hour ago."
If the only way you currently find out a notification channel is degraded is a support ticket, that gap is usually a one-sprint fix once the right three metrics are wired up.