Telemetry — Alerts
Overview
The alerts subsystem is a registry of named monitoring rules (AIAlertOptions) that the AIObservabilityWorker evaluates on a periodic interval. Each rule defines which metric to watch, how to detect a problem (threshold comparison or anomaly scoring), and where to route the notification.
Rules are registered imperatively at startup. The registry is a simple in-memory array — there is no persistence. It is intentionally lightweight so that alert definitions can live alongside the code they monitor.
Key Concepts
- Threshold mode — compares the current metric value against a fixed
thresholdusing anoperator. Simple and predictable. - Anomaly mode — passes the metric value through
RollingAnomalyDetectorand fires when the z-score exceedssensitivity. Adapts to the metric's natural baseline automatically. - Registry functions —
registerAIAlert,listAIAlerts, andresetAIAlertsmanage the in-memory rule store. RegisteredAIAlert— the wrapper stored in the registry. Contains the rule options plus metadata about the decorated method (target,methodName).
API Reference
registerAIAlert(rule: RegisteredAIAlert): void
Adds a rule to the global registry. The worker reads the registry on every evaluation cycle, so rules registered after the worker has started are picked up on the next tick.
import { registerAIAlert } from '@tagna/udiot/telemetry';
registerAIAlert({
target: 'OrdersService',
methodName: 'processOrder',
options: {
name: 'High error rate',
metric: 'orders.error_rate',
mode: 'threshold',
operator: '>',
threshold: 5,
severity: 'critical',
},
});
listAIAlerts(): RegisteredAIAlert[]
Returns a shallow copy of all registered rules. Safe to iterate without locking.
resetAIAlerts(): void
Empties the registry. Call in afterEach / afterAll in tests to prevent rule bleed between test cases.
AIAlertOptions
All fields are optional to allow incremental configuration.
| Field | Type | Description |
|---|---|---|
name |
string |
Human-readable alert name shown in notifications |
description |
string |
Remediation guidance or alert description |
mode |
'threshold' | 'anomaly' |
Detection strategy. If omitted, the worker infers from the presence of threshold vs sensitivity. |
metric |
string |
Name of the metric to evaluate (must match a key in MetricSnapshot) |
threshold |
number |
Fixed comparison value for threshold mode |
operator |
AlertOperator |
Comparison operator. Defaults to '>'. |
condition |
string |
Optional DSL string, e.g. "error_rate > 5". Parsed as a fallback if metric/threshold/operator are absent. |
windowMs |
number |
Informational: suggested evaluation window in ms (not enforced by the registry itself) |
windowSize |
number |
Rolling window size (in data points) forwarded to the anomaly detector |
minSamples |
number |
Minimum samples before the anomaly detector fires, forwarded to the detector |
sensitivity |
number |
Z-score threshold forwarded to the anomaly detector |
severity |
'info' | 'warning' | 'critical' |
Severity level used in notifications and summarizer recommendations |
channel |
string |
Notification channel hint (e.g., 'notify_team', 'page_oncall') |
playbookUrl |
string |
URL to a remediation runbook |
metadata |
Record<string, unknown> |
Arbitrary key/value data for downstream processors |
AlertOperator
type AlertOperator = '>' | '>=' | '<' | '<=' | '==' | '!=';
| Operator | Meaning |
|---|---|
'>' |
Value is greater than threshold |
'>=' |
Value is greater than or equal to threshold |
'<' |
Value is less than threshold |
'<=' |
Value is less than or equal to threshold |
'==' |
Value equals threshold |
'!=' |
Value does not equal threshold |
RegisteredAIAlert
interface RegisteredAIAlert {
target: string; // class or module name
methodName: string; // method or function name
options: AIAlertOptions;
}
target and methodName are used by notifiers to identify the origin of the alert in log output and Slack messages.
Basic Usage
Threshold alert: error rate above 5%
import { registerAIAlert } from '@tagna/udiot/telemetry';
import { getMetricsRegistry } from '@tagna/udiot/telemetry';
// Register the rule at startup
registerAIAlert({
target: 'HttpServer',
methodName: 'requestHandler',
options: {
name: 'Error rate too high',
description: 'HTTP 5xx error rate exceeded 5%. Check recent deployments.',
mode: 'threshold',
metric: 'http.error_rate',
operator: '>',
threshold: 5,
severity: 'critical',
playbookUrl: 'https://wiki.internal/runbooks/high-error-rate',
},
});
// Somewhere in your request handler, update the metric
const registry = getMetricsRegistry();
function recordRequest(isError: boolean) {
registry.increment('http.requests.total');
if (isError) {
registry.gauge('http.error_rate', computeErrorRate());
}
}
Anomaly alert: response time deviation
registerAIAlert({
target: 'PaymentsService',
methodName: 'chargeCard',
options: {
name: 'Response time anomaly',
description: 'Payment processing time has deviated significantly from baseline.',
mode: 'anomaly',
metric: 'payments.response_ms',
sensitivity: 2.5, // z-score threshold
windowSize: 60, // last 60 samples form the baseline
minSamples: 10, // require 10 samples before firing
severity: 'warning',
channel: 'notify_team',
},
});
Using the condition DSL string
The worker can parse simple "metric operator threshold" strings as a fallback when metric, operator, and threshold are not set individually:
registerAIAlert({
target: 'QueueWorker',
methodName: 'processJob',
options: {
condition: 'queue.depth > 1000',
severity: 'warning',
},
});
Percentage signs are stripped before parsing, so "error_rate > 5%" is equivalent to "error_rate > 5".
Common Patterns
Centralized rule file — define all alert rules in a single alerts.ts module and import it in your application entry point. This keeps monitoring rules discoverable and co-located.
Per-environment thresholds — read threshold from environment variables so production and staging have different sensitivity levels without code changes.
Testing alert rules — call resetAIAlerts() before each test, register the rule under test, construct an AIObservabilityWorker with a custom metricsProvider, call worker.evaluate(), and assert the notification in the onAlert callback.
Integration Notes
Alert rules are evaluated by AIObservabilityWorker (see ai-observability.md). The registry is passive — registering a rule has no effect until a worker reads it. You can register rules before or after creating the worker; the worker reads listAIAlerts() on every evaluation cycle.
Pitfalls
- If both
metric(direct) andcondition(DSL) are set,metrictakes precedence. - If
modeis omitted and the alert has athreshold, the worker defaults to threshold mode. If it hassensitivitybut nothreshold, the worker infers anomaly mode. Setmodeexplicitly to avoid ambiguity. resetAIAlerts()mutates the module-level array in place. It affects all workers sharing the same process, so use it only in test environments.