Your first route
The quickstart left you with one route, “Everything”, that sends every event to one connection. This page adds a second route that matches only some events, counts repeats instead of sending them again, collects events into one message, and is closed by a resolved event.
You need the instance from the Quickstart: a source key, a connection and the “Everything” route. The example uses a Webhook connection, so the messages shown below are the JSON bodies ramzes posts to it.
Each step can be done in the web UI or with the admin API. For the API, create a token under Settings, API tokens, and set three variables in your shell:
KEY='<source key>' # from the quickstart, starts with rz_src_TOKEN='<API token>' # starts with rz_tok_CONN='<connection id>' # see belowList the connections to find the id:
curl -s http://localhost:7269/api/connections -H "Authorization: Bearer $TOKEN"The route
Section titled “The route”The route should match failed payments in production above a certain amount:
| Condition | Value | Meaning |
|---|---|---|
| Topic | payments.* |
* matches any run of characters |
| Minimum severity | error |
error and critical |
| Label | env equals prod |
The event must carry this label with this value |
| Expression | payload.amount > 100 |
The event must also pass this test |
Every condition that is set must hold. And it should make less noise than one message per event:
| Noise control | Value | Effect |
|---|---|---|
| Dedup | 10 minutes | An event with the same key as a notification opened in the last 10 minutes is counted, not sent again |
| Grouping | by label service, wait 30 seconds |
Events with the same service are collected for 30 seconds and sent as one message |
1. Create the route
Section titled “1. Create the route”- Open Routes and press New route.
- Name:
Failed payments in production. - Under Which events: set Topic to
payments.*and Minimum severity toerror. Press Add label condition, typeenvas the label key, keep equals, and typeprodas the value. Typepayload.amount > 100into Expression. - Under Send to: choose your connection.
- Under Noise control: tick Count repeats of the same event instead of sending them again
and set For this long after the first one to 10 minutes. Tick Collect events and send
them as one message, type
serviceinto Labels to group by and set Wait before sending to 30 seconds. - Tick Skip the routes below when this one matches.
- Press Create route.
curl -s -X POST http://localhost:7269/api/routes \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Failed payments in production", "stop": true, "match": { "topic": "payments.*", "min_severity": "error", "labels": [{"op": "equals", "key": "env", "value": "prod"}], "expr": "payload.amount > 100" }, "targets": [{"connection_id": "'"$CONN"'"}], "shaping": { "dedup": {"window_s": 600}, "group": {"by": ["service"], "wait_s": 30} } }'The answer is 201 with the stored route, including its id.
2. Move it above “Everything”
Section titled “2. Move it above “Everything””A new route is added after the existing ones, so “Everything” is still first. Routes are checked from the top, and every route that matches sends. With the new route below “Everything”, a failed payment would be sent twice: at once by “Everything”, and again by the new route.
Put the new route first. Because it stops evaluation when it matches, “Everything” then only gets the events the new route did not match.
On the Routes page, press the up arrow on the new route’s row.
List the routes to get both ids, then send every id in the new order:
curl -s http://localhost:7269/api/routes -H "Authorization: Bearer $TOKEN"
curl -s -X POST http://localhost:7269/api/routes/reorder \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"ids": ["<id of the new route>", "<id of Everything>"]}'The answer is 204. The list must contain every route id exactly once.
3. Try it before sending anything
Section titled “3. Try it before sending anything”The Try an event panel on the Routes page shows what the routes would do with one event, without storing or sending it. Choose An event I write here and paste:
{ "topic": "payments.failed", "title": "Payment 7 failed", "severity": "error", "labels": {"env": "prod", "service": "checkout"}, "payload": {"amount": 250}, "dedup_key": "payment-7"}The new route shows matched with the target outcome “opens a group”, and two steps under it:
- dedup: “first event with this key in the window”
- group: “opens a group; it is sent after 30 s”
“Everything” shows as skipped, because an earlier route stopped the evaluation. Change amount to
40 and the new route no longer matches; “Everything” matches instead and would send.
The same test over the API is POST /api/routes/test with the event under "event".
4. Send the same failure twice
Section titled “4. Send the same failure twice”curl -X POST http://localhost:7269/v1/events \ -H "Authorization: Bearer $KEY" \ -H "Content-Type: application/json" \ -d '{"topic": "payments.failed", "title": "Payment 7 failed", "severity": "error", "labels": {"env": "prod", "service": "checkout"}, "payload": {"amount": 250}, "dedup_key": "payment-7"}'Run it twice within 30 seconds. Both requests answer 202, and nothing arrives at the connection
yet:
- The first event opens a notification that is collecting. On the Notifications page it is under Waiting.
- The second event has the same
dedup_key, so it is counted on that notification as a duplicate.
Thirty seconds after the first event, one message goes out. The Webhook connection receives:
{ "title": "Payment 7 failed (2 times)", "body": null, "severity": "error", "status": "firing", "topic": "payments.failed", "labels": {"env": "prod", "service": "checkout"}, "link": null, "ack_link": null, "dedup_key": "payment-7", "event_ids": ["01a136a8-abe9-7601-8ffe-11857f1b6b34", "01a136a8-abfa-76bd-829f-73890d3884a0"], "sent_at": 1791918416790}link and ack_link are null because the instance has no public address yet. Set one under
Settings and messages link back to ramzes and carry a link that acknowledges the notification.
See Escalation and acknowledgement.
Open either event from the Feed to see its journey: which route it matched, whether it opened the notification or was counted as a duplicate, and the delivery with the status the service answered.
5. Acknowledge it
Section titled “5. Acknowledge it”Acknowledging says someone is on it. It stops reminders and escalation for that notification.
Open Notifications, choose Sent, and press Acknowledge on the row.
curl -s "http://localhost:7269/api/notifications?state=sent" \ -H "Authorization: Bearer $TOKEN"
curl -s -X POST http://localhost:7269/api/notifications/<notification id>/acknowledge \ -H "Authorization: Bearer $TOKEN"The answer is 204. A second call answers 409 with “this notification is already acknowledged
or over”.
The notification moves to Acknowledged and records who did it: your email address from the UI, or “API token” from the API.
6. Resolve it
Section titled “6. Resolve it”Send an event with the same dedup_key and "status": "resolved":
curl -X POST http://localhost:7269/v1/events \ -H "Authorization: Bearer $KEY" \ -H "Content-Type: application/json" \ -d '{"topic": "payments.failed", "title": "Payment 7 went through", "severity": "error", "status": "resolved", "labels": {"env": "prod", "service": "checkout"}, "payload": {"amount": 250}, "dedup_key": "payment-7"}'The route matches, finds the open notification with that key, and closes it. Because a message had
been sent for it, the connection is told. The Webhook connection receives the same message again
with "status": "resolved":
{ "title": "Payment 7 failed (2 times)", "severity": "error", "status": "resolved", "topic": "payments.failed", "dedup_key": "payment-7"}(The other fields are as before.) The notification is now under Resolved. Later events with the
key payment-7 open a new notification.
Three details worth knowing:
- A resolved event closes a notification only when the keys match. Give the firing and the resolved
event the same
dedup_key. - A resolved event that is less severe than the route’s minimum still closes what the route opened.
It does nothing else on that route and does not stop evaluation, so routes below it see the event
too. In this example a resolved event sent with severity
infowould close the notification and also be sent by “Everything”. - To close without telling the target, untick Tell the target when it is resolved on the route
(
"notify_resolved": falseinshaping).
Where to go from here
Section titled “Where to go from here”- Routes and Noise control explain the rules used here in full.
- Routes and the tester covers the page you used.
- Templates change the wording of the message.
- Escalation and acknowledgement adds “tell someone else if nobody acknowledges”.