Alerting from the console
Declare rules, signed webhooks and summaries in the console's values, tune the built-in rules and verify the signature.
GuideOperationsSince version 1.3.0
On this page
Operations guide: configure, deploy and observe the gateway. What the feature does, product side: product guide; calling it: developer guide.
The console evaluates its rules every 15 s, in both modes, and notifies through a signed webhook. Nothing is typed into the console: rules, webhooks and summaries are declared in the chart's values, read again without a restart; an invalid version is refused and said on the Alerts screen, the previous one keeps applying.
Steps
Declare rules, webhooks and summaries
Write the rules, webhooks and summaries in the console's values:
values.yaml
# The console's values alerts: rules: # closed kinds: error_rate, p95, breaker_open, slo_burn, new_error_code - { name: reports-5xx, kind: error_rate, upstream: reports, threshold: 5%, for: 1m, notify: [ops] } - { name: orders-p95, kind: p95, operation: createOrder, threshold: 300ms, for: 2m } webhooks: # https required (allowHttp lifts it); secretFile: whsec_<base64>, one secret per line - { name: ops, url: "https://hooks.example/flexway", secretFile: /etc/flexway-console-alerts/ops } - { name: chat, urlFile: /etc/flexway-console-alerts/chat-url, secretFile: /etc/flexway-console-alerts/chat, allowPrivate: true } summaries: - { name: weekly, every: weekly, at: "07:00", weekday: monday, webhook: chat } # UTC existingSecret: console-alerts # secrets and URLs carrying a token, mounted at /etc/flexway-console-alerts slos: - { operation: createOrder, availability: 99.9%, latency: { p95: 300ms, target: 99% }, window: 30d } - { name: orders-api, upstream: orders-svc, availability: 99.5% } # a group: see SLO objectives on groups of operationsPut the secrets and the URLs carrying a token in the
Secretnamed byexistingSecret.Deploy the values: the console reads the file again without a restart.
Tune the built-in rules
Tune a built-in rule rather than silence it - a few cases:
values.yaml
alerts:
builtins:
# Tighten: a small publication traffic fires too early; 5 % refused, from 100 publications.
- { name: broker-backpressure, threshold: 5%, minRequests: 100 }
# Delay: a broker failing over in less than 3 min is not an incident.
- { name: broker-unavailable, for: 3m }
# Sooner: an open breaker already fires at once; a degraded gateway, after 30 s.
- { name: gateway-degraded, for: 30s }With the native Kafka proxy (since 1.6.0), the kafka-proxy-refusals rule counts closed causes and
accepts excludeCauses (Native Kafka clients: a virtual cluster per tenant):
values.yaml
alerts:
builtins:
- { name: kafka-proxy-refusals, threshold: 10%, excludeCauses: [quota] } # do not fire on a quota reachedWith the MQTT device listener (since 1.7.0), five more rules - device-connections-refused,
sparkplug-node-offline, mqtt-listener-saturation, device-throttled and sparkplug-sequence-gaps, the last two
disabled by default; the threshold of the two Sparkplug rules is a count, not a ratio
(Console: the Devices screen).
Verify the signature on the receiving side
The body: {"type": "flexway.alert.firing", "timestamp": ..., "data": {"rule", "kind", "state", "since", "target", "value", "unit", "threshold", "subjects"}} (flexway.alert.resolved, flexway.summary.daily,
flexway.summary.weekly) - never a tenant. Verify the signature (Standard
Webhooks) before anything else:
import base64, hashlib, hmac, time
def verify(secret: str, headers, body: bytes) -> bool:
key = base64.b64decode(secret.removeprefix("whsec_"))
msg_id, ts = headers["webhook-id"], headers["webhook-timestamp"]
if abs(time.time() - int(ts)) > 300: # replay: 5 minutes of tolerance
return False
mac = hmac.new(key, f"{msg_id}.{ts}.".encode() + body, hashlib.sha256).digest()
want = base64.b64encode(mac).decode()
# two signatures during a rotation, separated by a space: one must match
return any(hmac.compare_digest(sig.removeprefix("v1,"), want)
for sig in headers["webhook-signature"].split())Rotate a secret
- Put the new secret on the file's second line on the console's side.
- Deploy it on the receiving side.
- Remove the old one - the console signs with both meanwhile.
Verify
- The Diagnostics -> Alerts screen (admins) lists each rule, its state (
ok, pending, firing, resolved, unknown), its value against the threshold, its curve over 6 h and each webhook's deliveries (result, status, cause). - A refused file is said there, with its cause; the previous version keeps applying.
GET /api/alertsgives the built-in rules' values in force and where they come from (tuning).
Good to know
| Topic | What to know |
|---|---|
| Built-in rules | Always on: breaker-open (an open breaker), upstream-degraded and gateway-degraded (1 min), new-error-code (a code never seen on the operation in 7 days - it reads flexway_errors_total), slo-burn (as soon as an objective is declared, an operation's or a group's), replica-silent (a gateway replica without a report for 2 min and no stop announced), broker-unavailable (a broker's breaker open or more than half its publications failing, 1 min), broker-backpressure (more than 1 % of 503 overloaded, 5 min), webhook-dead-letter (a delivery in the dead letter over 15 min) |
| Judgement | error_rate = share of 5xx over 1 min, from 20 answers; p95 over 5 min. Silent metrics: no state changes, nothing is sent nor withdrawn, the screen says unknown. A target missing from the configuration makes the rule invalid, never notified |
| Who sends | Every replica evaluates; one notifies, the holder of the chart's Lease. The webhook-id is the same from one replica to another: deduplicate on it (at least once) |
| Webhook | https, the address checked when the connection is made: loopback, link-local (169.254.169.254) and multicast always refused, a private network only with allowPrivate: true (an internal target); no redirection followed; 5 s timeout; retries 5 s, 30 s, 2 min, 10 min, 30 min, then an abandon shown on the screen; a 4xx (but 408, 429) is a final refusal |
| Silence | Alerts screen, 24 h at most, a reason required: it suspends a rule's notifications, never its evaluation; when it ends, what still fires is notified |
| Summaries | daily or weekly at a UTC hour: requests against the previous period, 5xx and 4xx shares, new codes, each SLO's budget, the five largest changes, alerts - never a tenant's name |
| SLOs | Availability (non-5xx answers) and latency (share of the minutes whose p95 holds the target) over the window; remaining budget, burn rate over 1 h, 6 h, 3 days; slo-burn fires above 14.4 over 1 h and 5 min, or 6 over 6 h and 30 min. On an operation or, since 1.6.0, a group of operations - an upstream, a tag, a list, every one (SLO objectives on groups of operations). Traffic's Objectives (SLO) tab, the Operation panel, the global objective on the Overview; "Create an alert" on the charts and the objectives writes the YAML to paste in these values |
| Tuning the built-in rules | alerts.builtins: the name of a built-in rule, for (0 to 1 h) on every one; threshold (a ratio) and minRequests only on broker-unavailable (half, 20) and broker-backpressure (1 %, 20); excludeCauses only on a rule counting closed causes (the native Kafka proxy's rules, since 1.6.0). An unknown name, a rule tuned twice or a knob the rule does not carry refuses the file, as the rest does; without the key, the defaults. The Alerts screen shows the tuned threshold |
Available since 1.3.0; tuning of the built-in rules in 1.6.0.