2 Alerting Rules and Subscription
This tour shows you how could we create alerting rules and we want to subscribe to a notification triggered by an alert. If you want to know how to send on-demand notification to a receiver, you could go to the first tour.
As mentioned previously, we will be using CortexMetrics as a provider. We need to register the provider and create a provider namespace in Siren first before creating any rule and subscription.
Provider is implemented as a plugin in Siren. You can learn more about Siren Plugin concepts here. We also welcome all contributions to add new provider plugins. Learn more about how to add a new provider plugin here.
Once an alert triggered, the subscription labels will be matched with alert's labels. If all subscription labels matched, receiver's subscripton will get the alert notification.
2.1 Register a Provider and Namespaces
Register a Provider
To create a new provider with CLI, we need to create a yaml
file that contains provider detail.
host: http://localhost:9009
urn: localhost-dev-cortex
name: dev-cortex
type: cortex
Once the file is ready, we can create the provider with Siren CLI.
- CLI
- HTTP
$ siren provider create --file provider.yaml
If succeed, you will got this message.
Provider created with id: 1 ✓
$ curl --request POST
--url http://localhost:8080/v1beta1/providers
--header 'content-type: application/json'
--data-raw '{
"host": "http://localhost:9009",
"urn": "localhost-dev-cortex",
"name": "dev-cortex",
"type": "cortex"
}'
The id
we got from the provider creation is important to create a namespace later.
Register Namespaces
For multi-tenant scenario, which CortexMetrics supports, we need to define namespaces in Siren. Assuming there are 2 tenants in Cortex, odpf
and non-odpf
, we need to create 2 namespaces. This could be done in similar way with how we created provider.
urn: odpf-ns
name: odpf-ns
provider:
id: 1
urn: non-odpf-ns
name: non-odpf-ns
provider:
id: 1
- CLI
- HTTP
$ siren namespace create --file ns1.yaml
$ curl --request POST
--url http://localhost:8080/v1beta1/namespaces
--header 'content-type: application/json'
--data-raw '{
"urn": "odpf-ns",
"name": "odpf-ns",
"provider": {
"id": 1
}
}'
- CLI
- HTTP
$ siren namespace create --file ns2.yaml
$ curl --request POST
--url http://localhost:8080/v1beta1/namespaces
--header 'content-type: application/json'
--data-raw '{
"urn": "non-odpf-ns",
"name": "non-odpf-ns",
"provider": {
"id": 2
}
}'
Verify Created Provider and Namespaces
To make sure all provider and namespaces are properly created, we could try query Siren with Siren CLI.
See what providers exist in Siren.
- CLI
- HTTP
$ siren provider list
Showing 1 of 1 providers
ID TYPE URN NAME
1 cortex localhost-dev-cortex dev-cortex
For details on a provider, try: siren provider view <id>
$ curl --request GET
--url http://localhost:8080/v1beta1/providers'
See what namespaces exist in Siren.
- CLI
- HTTP
$ siren namespace list
Showing 2 of 2 namespaces
ID URN NAME
1 odpf-ns odpf-ns
2 non-odpf-ns non-odpf-ns
For details on a namespace, try: siren namespace view <id>
$ curl --request GET
--url http://localhost:8080/v1beta1/namespaces'
2.2 Register a Receiver
Siren supports several types of receiver to send notification to. For this tour, let's pick the simplest receiver: file
. If the receiver is not added in Siren yet, you could add one using siren receiver create
. See receiver guide to explore more on how to work with siren receiver
command.
With file
receiver, all published notifications will be written to a file. Let's create a receivers file
using Siren CLI.
We welcome all contributions to add new type of receiver plugins. See Extend section to explore how to add a new type of receiver plugin to Siren
Prepare receiver detail and register the receiver with Siren CLI.
name: file-sink-2
type: file
labels:
key1: value1
key2: value2
configurations:
url: ./out-file-sink2.json
- CLI
- HTTP
$ siren receiver create --file receiver_2.yaml
Once done, you will get a message.
Receiver created with id: 2 ✓
$ curl --request POST
--url http://localhost:8080/v1beta1/receivers
--header 'content-type: application/json'
--data-raw '{
"name": "file-sink-2",
"type": "file",
"labels": {
"key1": "value1",
"key2": "value2"
},
"configurations": {
"url": "./out-file-sink2.json"
}
}'
2.3 Configuring Provider Alerting Rules
In this part, we will create alerting rules for our CortexMetrics monitoring provider. Rules in Siren relies on template for its abstraction. To create a rule, we need to create a template first.
Creating a Rule's Template
We will create a rule's template to monitor CPU usage.
apiVersion: v2
type: template
name: CPU
body:
- alert: CPUWarning
expr: avg by (host) (cpu_usage_user{cpu="cpu-total"}) > [[.warning]]
for: "[[.for]]"
labels:
severity: WARNING
annotations:
description: CPU has been above [[.warning]] for last [[.for]] {{ $labels.host }}
- alert: CPUCritical
expr: avg by (host) (cpu_usage_user{cpu="cpu-total"}) > [[.critical]]
for: "[[.for]]"
labels:
severity: CRITICAL
annotations:
description: CPU has been above [[.critical]] for last [[.for]] {{ $labels.host }}
variables:
- name: for
type: string
default: 10m
description: For eg 5m, 2h; Golang duration format
- name: warning
type: int
default: 80
- name: critical
type: int
default: 90
tags:
- systems
We named the template above as CPU
, the body in the template is the data that will be interpolated with variables. Notice that template body format is similar with Prometheus alerting rules. This is because Cortex uses the same rules as prometheus and Siren will translate the rendered rules to the Cortex alerting rules. Let's save the template above into a file called cpu_template.yaml
and upload our template to Siren using
- CLI
$ siren template upload cpu_template.yaml
You could verify the newly created template using this command.
- CLI
- HTTP
$ siren template list
Showing 1 of 1 templates
ID NAME TAGS
1 CPU systems
For details on a template, try: siren template view <name>
$ curl --request GET
--url http://localhost:8080/v1beta1/templates
Creating a Rule
Now we already have a CPU
template, we can create a rule based on that template. Let's prepare a rule and save it in a file called cpu_test.yaml
.
apiVersion: v2
type: rule
namespace: odpf
provider: localhost-dev-cortex
providerNamespace: odpf-ns
rules:
cpuGroup:
template: CPU
enabled: true
variables:
- name: for
value: 15m
- name: warning
value: 185
- name: critical
value: 195
We defined a rule based on CPU
template for namespace urn odpf-ns
and provider urn localhost-dev-cortex
. The rule group name is cpuGroup
and there are also some variables to be assign to the template when the template is rendered. Let's upload the rule with Siren CLI.
- CLI
$ siren rule upload cpu_test.yaml
If succeed, you will get this message.
Upserted Rule
ID: 4
You could verify the created rules by getting all registered rules in CortexMetrics with cURL.
- HTTP
curl --location --request GET 'http://localhost:9009/api/v1/rules' \
--header 'X-Scope-OrgId: odpf-ns'
The response body should be in yaml
format and like this.
odpf:
- name: cpuGroup
rules:
- alert: CPUWarning
expr: avg by (host) (cpu_usage_user{cpu="cpu-total"}) > 185
for: 15m
labels:
severity: WARNING
annotations:
description: CPU has been above 185 for last 15m {{ $labels.host }}
- alert: CPUCritical
expr: avg by (host) (cpu_usage_user{cpu="cpu-total"}) > 195
for: 15m
labels:
severity: CRITICAL
annotations:
description: CPU has been above 195 for last 15m {{ $labels.host }}
If there is a response like above, that means the rule that we created in Siren was already synchronized to the provider. Next, we can add a subscription to the alert and try to trigger an alert to verify whether we got a notification alert or not.
2.4 Subscribing to Alert Notifications
Notifications can be subscribed and routed to the defined receivers by adding a subscription. In this part, we will trigger an alert to CortexMetrics manually by calling CortexMetrics POST /alerts
API and expect CortexMetrics to trigger webhook-notification and calling Siren alerts hook API. On Siren side, we expect a notification is published everytime the hook API is being called.
If you are curious about how notification in Siren works, you can read the concepts here.
The first thing that we should do is knowing what would be the labels sent by CortexMetrics. The labels should be defined when we were defining rules. Assuming the labels sent by CortexMetrics are these:
severity: WARNING
team: odpf
service: some-service
environment: integration
resource_name: some-resource
We want to subscribe all notifications owned by odpf
team and has severity WARNING
regardless the service name and route the notification to file
with receiver id 2
(the one that we created in the previous part).
Prepare a subscription detail and create a new subscription with Siren CLI.
urn: subscribe-cpu-odpf-warning
namespace: 1
receivers:
- id: 1
- id: 2
match
team: odpf
severity: WARNING
- CLI
- HTTP
$ siren subscription create --file cpu_subs.yaml
$ curl --request POST
--url http://localhost:8080/v1beta1/subscriptions'
--header 'Content-Type: application/json'
--header 'Accept: application/json'
--data-raw '{
"urn": "subscribe-cpu-odpf-warning",
"namespace": 1,
"receivers": [
{
"id": 1
},
{
"id": 2
}
],
"match": {
"team": "odpf",
"severity": "WARNING"
}
}'
Once a subscription is created, let's manually trigger alert in CortexMetrics with this cURL. The way CortexMetrics monitor a specific metric and auto-trigger an alert are out of this tour
scope.
- HTTP
curl --location --request POST 'http://localhost:9009/api/prom/alertmanager/api/v1/alerts'
--header 'X-Scope-OrgId: odpf-ns'
--header 'Content-Type: application/json' \
--data-raw '[
{
"state": "firing",
"value": 1,
"labels": {
"severity": "WARNING",
"team": "odpf",
"service": "some-service",
"environment": "integration"
},
"annotations": {
"resource": "test_alert",
"metricName": "test_alert",
"metricValue": "1",
"template": "alert_test"
}
}
]'
If succeed, the response should be like this.
{"status":"success"}
Now, we need to expect CortexMetrics to send alerts notification to our Siren API /alerts/cortex/:providerId
. If that is the case, the alert should also be stored and published to the receivers in the matching subscriptions. You might want to wait for a CortexMetrics group_wait
(usually 30s) until alerts are triggered by Cortex Alertmanager.
Let's verify the alert is stored inside our DB.
- CLI
- HTTP
$ siren alert list --provider-id 1 --provider-type cortex --resource-name test_alert
The result would be something like this.
Showing 1 of 1 alerts
ID PROVIDER_ID RESOURCE_NAME METRIC_NAME METRIC_VALUE SEVERITY
1 1 test_alert test_alert 1 WARNING
For details on a alert, try: siren alert view <id>
$ curl --request GET
--url http://localhost:8080/v1beta1/alerts?providerId=1&providerType=cortex&resourceName=test_alert
We also expect notifications have been published to the receiver id 2
. You can check a new notification is already added in ./out-file-sink2.json
with this value.
{"environment":"integration","generator_url":"","groupKey":"{}:{severity=\"WARNING\"}","metricName":"test_alert","metricValue":"1","num_alerts_firing":1,"resource":"test_alert","routing_method":"subscribers","service":"some-service","severity":"WARNING","status":"firing","team":"odpf","template":"alert_test"}
What Next?
This is the end of alerting rules and subscription
tour. If you want to know how to send on-demand notification to a receiver, you could check the first tour.
Apart from the tour, we recommend completing the guides. You could also check out the remainder of the documentation in the reference and concepts sections for your specific areas of interest. We've aimed to provide as much documentation as we can for the various components of Siren to give you a full understanding of Siren's surface area. If you are interested to contribute, check out the contribution page.