Есть три рабочих окружения — Dev, Stage, Production.
Есть пачка алертов с разными уровнями важности — info, warning и critical, например:
... - name: SSLexpiry.rules rules: - alert: SSLCertExpiring30days expr: probe_ssl_earliest_cert_expiry{job="blackbox"} - time() < 86400 * 30 for: 10m labels: severity: info annotations: summary: "SSL certificate warning" description: "SSL certificate for the {{ $labels.instance }} will expire within 30 days!" ...
Алерты отправляются в Slack и в OpsGenie.
Задача: в зависимости от окружения и уровня важности — слать либо в только в Slack, либо в Slack + OpsGenie.
OpsGenie, в свою очередь, в зависимости от уровня важности:
- для warning — оптравляет либо только письмо на почту + сообщение в приложение на телефоне
- для алертов уровня critical — письмо на почту + сообщение в приложение + звонок на телефон от бота
Т.е. выглядит всё это так:
- Dev
- любые сообщения, независимо от уровня важности — шлём только в Slack
- Staging:
- info — только в Slack
- warning и critical — в Slack и OpsGenie, но для OpsGenie ставим уровень warning (P3)
- Production
- info — только в Slack
- warning и critical — в Slack и OpsGenie, но для OpsGenie ставим уровень critical (P1)
Для разбивки сообщений между Slack и OpsGenie используется три ресивера, при этом в warning и critical ресиверах — для OpsGenie устанавливаются уровни P3 и P1 соответсвенно:
... receivers: - name: 'default' slack_configs: - send_resolved: true title_link: 'https://monitor.example.com/prometheus/alerts' title: '{{ if eq .Status "firing" }}:confused:{{ else }}:dancing_panda:{{ end }} [{{ .Status | toUpper }}] {{ .CommonAnnotations.summary }}' text: "{{ range .Alerts }}*Priority*: `{{ .Labels.severity | toUpper }}`\nMonitoring host: {{ .Labels.monitor }}\n{{ .Annotations.description }}\n{{ end }}" - name: 'warning' slack_configs: - send_resolved: true title_link: 'https://monitor.example.com/prometheus/alerts' title: '{{ if eq .Status "firing" }}:disappointed_relieved:{{ else }}:dancing_panda:{{ end }} [{{ .Status | toUpper }}] {{ .CommonAnnotations.summary }}' text: "{{ range .Alerts }}*Priority*: `{{ .Labels.severity | toUpper }}`\nMonitoring host: {{ .Labels.monitor }}\n{{ .Annotations.description }}\n{{ end }}" opsgenie_configs: - priority: P3 - name: 'critical' slack_configs: - send_resolved: true title_link: 'https://monitor.example.com/prometheus/alerts' title: '{{ if eq .Status "firing" }}:scream:{{ else }}:dancing_panda:{{ end }} [{{ .Status | toUpper }}] {{ .CommonAnnotations.summary }}' text: "{{ range .Alerts }}*Priority*: `{{ .Labels.severity | toUpper }}`\nMonitoring host: {{ .Labels.monitor }}\n{{ .Annotations.description }}\n{{ end }}" opsgenie_configs: - priority: P1
И собственно «маршрутизация» алертов выполняется в блоке route
:
... route: group_by: ['alertname', 'cluster', 'job', 'env'] repeat_interval: 24h group_interval: 5m # capture All Dev + All INFO receiver: 'default' routes: # capture All WARN to the 'warning' with P3 - match: severity: warning receiver: warning routes: # forward Dev WARN to the 'default' - match_re: env: .*(-dev).* receiver: default # capture All CRIT to the 'critical' with P1 - match: severity: critical receiver: critical routes: # forward Stage CRIT to the 'warning' - match_re: env: .*(-stage).* receiver: warning # forward Dev CRIT to the 'default' - match_re: env: .*(-dev).* receiver: default ...
Тут задаём дефолтный роут ‘default
‘ — все алерты, не попавшие под действия правил ниже — будут отправлены через него в ресивер default
, который выполняет отправку только в Slack.
Далее, описываем дополнительные маршруты:
- в
match
ловим алерты по тегуseverity: warning
- во вложенном роуте с помощью
match_re
проверяем значение тегаenv
— если в нём содержится «-dev» — то отправляем сообщение в ресиверdefault
- все остальные алерты с уровнем warning «возвращаются выше» — и отправляются в
receiver: warning
Аналогично поступаем на следующем уровне — ловим алерты с severity: critical
, и проверяем их:
- если
env: .*(-stage).*
— шлём вwarning
- если
env: .*(-dev).*
— вdefault
- все остальные (остаёся env == production и severity == critical) — отправляем в ресивер
critical
Таким же образом можно писать любые условия по тегам, и использовать любое количество вложенных проверок для выбора дальнейшего маршрута алерта.