Alerts¶
Multi-channel alerting system with throttling, config-driven defaults, and deep defense hard limits.
TL;DR¶
import asyncio
from kstlib.alerts import AlertManager, AlertLevel
from kstlib.alerts.channels import SlackChannel, EmailChannel
from kstlib.alerts.models import AlertMessage
from kstlib.alerts.throttle import AlertThrottle
# Create channels
slack = SlackChannel(
webhook_url="https://hooks.slack.com/services/T.../B.../xxx"
)
email = EmailChannel(
transport=smtp_transport,
sender="alerts@example.com",
recipients=["oncall@example.com", "backup@example.com"],
)
# Setup manager with level filtering
manager = AlertManager()
manager.add_channel(slack, min_level=AlertLevel.WARNING)
manager.add_channel(email, min_level=AlertLevel.CRITICAL)
# Send alert
alert = AlertMessage(
title="Database Connection Lost",
body="Primary database unreachable for 30 seconds",
level=AlertLevel.CRITICAL,
)
results = asyncio.run(manager.send(alert))
Key Features¶
Multi-channel delivery: Slack, Email (via kstlib.mail transports)
Level filtering: INFO, WARNING, CRITICAL per channel
Rate limiting:
AlertThrottleprevents alert floodingConfig-driven: Settings from
kstlib.conf.ymlwith kwargs overrideDeep defense: Hard limits prevent misconfiguration
Async support: All operations are async-first
Configuration¶
Settings are read from kstlib.conf.yml under the alerts section:
alerts:
# Throttle settings (anti-spam)
throttle:
rate: 10 # Max alerts per period
per: 60.0 # Period in seconds
burst: 5 # Initial burst capacity
# Channel defaults
channels:
timeout: 30.0 # HTTP timeout (seconds)
max_retries: 2 # Retry attempts
# Environment presets
presets:
dev:
throttle:
rate: 100 # More lenient for dev
per: 60.0
burst: 20
prod:
throttle:
rate: 10 # Strict for production
per: 60.0
burst: 3
Hard Limits (Deep Defense)¶
These cannot be exceeded even with explicit kwargs:
Parameter |
Min |
Max |
Notes |
|---|---|---|---|
|
1 |
1000 |
Alerts per period |
|
1.0 |
86400.0 |
Period duration (1 day max) |
|
1.0 |
120.0 |
HTTP timeout |
|
0 |
5 |
Retry attempts |
Quick Start¶
AlertThrottle¶
Rate limiting for alert delivery. Config-driven with optional overrides:
from kstlib.alerts.throttle import AlertThrottle
# Uses kstlib.conf.yml defaults
throttle = AlertThrottle()
# Override specific values
throttle = AlertThrottle(rate=5, per=30.0)
# Non-blocking check
if throttle.try_acquire():
await channel.send(alert)
else:
log.warning("Alert throttled")
# Blocking with timeout
try:
throttle.acquire(timeout=5.0)
await channel.send(alert)
except AlertThrottledError as e:
log.warning(f"Throttled, retry after {e.retry_after}s")
# Async context manager
async with throttle:
await channel.send(alert)
SlackChannel¶
Send alerts to Slack via incoming webhooks:
from kstlib.alerts.channels import SlackChannel
# Direct webhook URL
channel = SlackChannel(
webhook_url="https://hooks.slack.com/services/T.../B.../xxx",
username="kstlib-alerts",
icon_emoji=":bell:",
timeout=10.0, # Optional, uses config default
)
# From config with credential resolver (SOPS support)
channel = SlackChannel.from_config(
config={"credentials": "slack_webhook"},
credential_resolver=resolver,
)
result = await channel.send(alert)
if result.success:
print("Alert sent!")
EmailChannel¶
Send alerts via email using kstlib.mail transports:
from kstlib.alerts.channels import EmailChannel
from kstlib.mail.transports import SMTPTransport, ResendTransport
# With SMTP
smtp = SMTPTransport(host="smtp.example.com", port=587)
channel = EmailChannel(
transport=smtp,
sender="alerts@example.com",
recipients=["oncall@example.com", "backup@example.com"],
subject_prefix="[PROD ALERT]",
)
# With Resend (async)
resend = ResendTransport(api_key="re_xxx")
channel = EmailChannel(
transport=resend,
sender="alerts@example.com",
recipients=["team@example.com"],
)
AlertManager¶
Orchestrate multi-channel delivery with level filtering:
from kstlib.alerts import AlertManager, AlertLevel
from kstlib.alerts.throttle import AlertThrottle
manager = AlertManager()
# Add channels with level filtering
manager.add_channel(slack, min_level=AlertLevel.INFO)
manager.add_channel(email, min_level=AlertLevel.CRITICAL)
# Add throttle per channel
throttle = AlertThrottle(rate=10, per=60.0)
manager.add_channel(pagerduty, min_level=AlertLevel.CRITICAL, throttle=throttle)
# Send alert - delivered to all matching channels concurrently
alert = AlertMessage(
title="High CPU Usage",
body="Server cpu-01 at 95% for 5 minutes",
level=AlertLevel.WARNING,
)
results = await manager.send(alert)
# Check results
for result in results:
if result.success:
print(f"{result.channel}: OK")
else:
print(f"{result.channel}: FAILED - {result.error}")
Alert Levels¶
Three severity levels for filtering:
from kstlib.alerts.models import AlertLevel
AlertLevel.INFO # Informational, non-urgent
AlertLevel.WARNING # Attention needed, not critical
AlertLevel.CRITICAL # Immediate action required
Statistics¶
Track delivery metrics:
manager = AlertManager()
# ... send alerts ...
stats = manager.stats
print(f"Sent: {stats.total_sent}")
print(f"Failed: {stats.total_failed}")
print(f"Throttled: {stats.total_throttled}")
# Per-channel breakdown
for channel, channel_stats in stats.by_channel.items():
print(f"{channel}: {channel_stats}")
Examples¶
See examples/alerts/ for complete working examples:
Example |
Description |
|---|---|
|
Basic email alerts |
|
Slack webhook alerts |
|
Multi-channel with level filtering |
See Also¶
Alerts Subsystem - API Reference
Alerts Exceptions - Exception Catalog
Mail - Mail transports for EmailChannel