Metrics are useful only if you act on them. The simplest action: when a metric crosses a threshold, alert someone. The simplest someone: yourself.
import os
results = ["ok", "err", "ok", "err", "err"]
error_count = sum(1 for r in results if r == "err")
if error_count > 2:
# Self-send a Gmail alert.
toolset.execute_action(Action.GMAIL_SEND_EMAIL, {
"recipient_email": os.environ.get("USER_EMAIL", "you@example.com"),
"subject": f"alert: {error_count} errors",
"body": "threshold crossed",
})
print("alerted")
else:
print("under threshold")With 3 errors > 2, this fires the alert. With 1 error, it skips.
Why self-send via Gmail?
Gmail (or a Calendar event whose summary holds the alert text) is a real notification you'll actually see in your own inbox or calendar. The pattern — "on metric crossing, fire a notification" — works the same regardless of channel. In your own production system, you'd swap the action for whatever notification channel you watch (a chat tool, a paging service, SMS).
Why a threshold instead of alerting on every error?
Alerting on every individual error creates alert fatigue — too many pings, you stop reading them. Thresholds ("more than 2 errors", "latency over 1 second", "error rate above 5%") filter the signal. Alert when the situation is bad enough to warrant attention.
# 1. Run work, collect outcomes
results = run_batch()
error_count = sum(1 for r in results if r.failed)
# 2. Compare to threshold
if error_count > THRESHOLD:
# 3. Notify
send_alert(f"{error_count} errors in last batch")Three pieces: collect outcomes, compare to threshold, notify on crossing.
A static threshold (> 2, > 100ms, > 5%) is the simplest. More sophisticated:
For a lesson: a static count threshold is plenty. Production systems graduate to sliding-window and anomaly when needed.
In supported apps for this track, the alert channel options are:
| Channel | Action | Use when |
|---|---|---|
| Email self-send | Action.GMAIL_SEND_EMAIL to your own address | One-off alerts, low frequency |
| Calendar event | Action.GOOGLECALENDAR_CREATE_EVENT with summary in subject | Time-based pings; anything you want to see in a calendar view |
| Sheets append | Action.GOOGLESHEETS_SHEET_APPEND_GOOGLE_SHEET_ROW | Audit trail; alerts you'd want to query later |
The chat-tool / paging-service alerts you'd see in a real production setup follow the same pattern — the only thing that changes is the action call.
info/warn/error so you can filter what gets actively paged vs just loggedFor this lesson: simple count threshold is enough. The real production layer is week-by-week refinement.
A common antipattern:
# wrong — one alert per error
for item in items:
try:
process(item)
except Exception as e:
send_alert(f"failed: {item}") # 50 errors = 50 alertsBetter:
# right — one alert per batch
failures = []
for item in items:
try:
process(item)
except Exception as e:
failures.append((item, e))
if len(failures) > 0:
send_alert(f"{len(failures)} failures in batch")The summary alert is more useful than 50 individual ones — you immediately see the count and severity.
Metrics are useful only if you act on them. The simplest action: when a metric crosses a threshold, alert someone. The simplest someone: yourself.
import os
results = ["ok", "err", "ok", "err", "err"]
error_count = sum(1 for r in results if r == "err")
if error_count > 2:
# Self-send a Gmail alert.
toolset.execute_action(Action.GMAIL_SEND_EMAIL, {
"recipient_email": os.environ.get("USER_EMAIL", "you@example.com"),
"subject": f"alert: {error_count} errors",
"body": "threshold crossed",
})
print("alerted")
else:
print("under threshold")With 3 errors > 2, this fires the alert. With 1 error, it skips.
Why self-send via Gmail?
Gmail (or a Calendar event whose summary holds the alert text) is a real notification you'll actually see in your own inbox or calendar. The pattern — "on metric crossing, fire a notification" — works the same regardless of channel. In your own production system, you'd swap the action for whatever notification channel you watch (a chat tool, a paging service, SMS).
Why a threshold instead of alerting on every error?
Alerting on every individual error creates alert fatigue — too many pings, you stop reading them. Thresholds ("more than 2 errors", "latency over 1 second", "error rate above 5%") filter the signal. Alert when the situation is bad enough to warrant attention.
# 1. Run work, collect outcomes
results = run_batch()
error_count = sum(1 for r in results if r.failed)
# 2. Compare to threshold
if error_count > THRESHOLD:
# 3. Notify
send_alert(f"{error_count} errors in last batch")Three pieces: collect outcomes, compare to threshold, notify on crossing.
A static threshold (> 2, > 100ms, > 5%) is the simplest. More sophisticated:
For a lesson: a static count threshold is plenty. Production systems graduate to sliding-window and anomaly when needed.
In supported apps for this track, the alert channel options are:
| Channel | Action | Use when |
|---|---|---|
| Email self-send | Action.GMAIL_SEND_EMAIL to your own address | One-off alerts, low frequency |
| Calendar event | Action.GOOGLECALENDAR_CREATE_EVENT with summary in subject | Time-based pings; anything you want to see in a calendar view |
| Sheets append | Action.GOOGLESHEETS_SHEET_APPEND_GOOGLE_SHEET_ROW | Audit trail; alerts you'd want to query later |
The chat-tool / paging-service alerts you'd see in a real production setup follow the same pattern — the only thing that changes is the action call.
info/warn/error so you can filter what gets actively paged vs just loggedFor this lesson: simple count threshold is enough. The real production layer is week-by-week refinement.
A common antipattern:
# wrong — one alert per error
for item in items:
try:
process(item)
except Exception as e:
send_alert(f"failed: {item}") # 50 errors = 50 alertsBetter:
# right — one alert per batch
failures = []
for item in items:
try:
process(item)
except Exception as e:
failures.append((item, e))
if len(failures) > 0:
send_alert(f"{len(failures)} failures in batch")The summary alert is more useful than 50 individual ones — you immediately see the count and severity.
Create a free account to get started. Paid plans unlock all tracks.