Skip to content

Commit 832bb01

Browse files
alexander-akhmetovjdbaldrybrendamuir
authored
Alerting: Add MQTT notifications receiver (grafana#91487)
* Alerting: Add MQTT notifications receiver * Update alerting to 9daa6239cc41dc42bff0e916c8d0d27766caa8b9 (main) --------- Co-authored-by: Jack Baldry <[email protected]> Co-authored-by: brendamuir <[email protected]>
1 parent 9c73916 commit 832bb01

File tree

12 files changed

+324
-5
lines changed

12 files changed

+324
-5
lines changed

docs/sources/administration/provisioning/index.md

+12
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,18 @@ The following sections detail the supported settings and secure settings for eac
504504
| ----- | -------------- |
505505
| token | yes |
506506

507+
#### Alert notification `MQTT`
508+
509+
| Name | Secure setting |
510+
| ------------------ | -------------- |
511+
| brokerUrl | |
512+
| clientId | |
513+
| topic | |
514+
| messageFormat |
515+
| username | |
516+
| password | yes |
517+
| insecureSkipVerify | |
518+
507519
#### Alert notification `pagerduty`
508520

509521
| Name | Secure setting |

docs/sources/alerting/configure-notifications/manage-contact-points/_index.md

+6
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ refs:
7676
destination: /docs/grafana/<GRAFANA_VERSION>/alerting/set-up/configure-alertmanager/
7777
- pattern: /docs/grafana-cloud/
7878
destination: /docs/grafana-cloud/alerting-and-irm/alerting/set-up/configure-alertmanager/
79+
mqtt:
80+
- pattern: /docs/grafana/
81+
destination: /docs/grafana/<GRAFANA_VERSION>/alerting/configure-notifications/manage-contact-points/integrations/configure-mqtt/
82+
- pattern: /docs/grafana-cloud/
83+
destination: /docs/grafana-cloud/alerting-and-irm/alerting/configure-notifications/manage-contact-points/integrations/configure-mqtt/
7984
---
8085

8186
# Configure contact points
@@ -164,6 +169,7 @@ The following table lists the contact point integrations supported by Grafana.
164169
| Google Chat | `googlechat` |
165170
| [Grafana Oncall](ref:oncall) | `oncall` |
166171
| Kafka REST Proxy | `kafka` |
172+
| [MQTT](ref:mqtt) | `mqtt` |
167173
| Line | `line` |
168174
| [Microsoft Teams](ref:teams) | `teams` |
169175
| [Opsgenie](ref:opsgenie) | `opsgenie` |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
---
2+
canonical: https://grafana.com/docs/grafana/latest/alerting/configure-notifications/manage-contact-points/integrations/configure-mqtt/
3+
description: Configure the MQTT notifier integration for Alerting
4+
keywords:
5+
- grafana
6+
- alerting
7+
- guide
8+
- contact point
9+
- mqtt
10+
labels:
11+
products:
12+
- cloud
13+
- enterprise
14+
- oss
15+
menuTitle: MQTT notifier
16+
title: Configure the MQTT notifier for Alerting
17+
weight: 80
18+
---
19+
20+
# Configure the MQTT notifier for Alerting
21+
22+
Use the Grafana Alerting - MQTT integration to send notifications to an MQTT broker when your alerts are firing.
23+
24+
## Procedure
25+
26+
To configure the MQTT integration for Alerting, complete the following steps.
27+
28+
1. In the left-side menu, click **Alerts & IRM** and then **Alerting**.
29+
1. On the **Contact Points** tab, click **+ Add contact point**.
30+
1. Enter a descriptive name for the contact point.
31+
1. From the Integration list, select **MQTT**.
32+
1. Enter your broker URL in the **Broker URL** field. Supports `tcp`, `ssl`, `mqtt`, `mqtts`, `ws`, `wss` schemes. For example: `tcp://127.0.0.1:1883`.
33+
1. Enter the MQTT topic name in the **Topic** field.
34+
1. In **Optional MQTT settings**, specify additional settings for the MQTT integration if needed.
35+
1. Click **Test** to check that your integration works.
36+
A test alert notification should be sent to the MQTT broker.
37+
1. Click **Save** contact point.
38+
39+
The integration sends data in JSON format by default. You can change that using **Message format** field in the **Optional MQTT settings** section. There are two supported formats:
40+
41+
- **JSON**: Sends the alert notification in JSON format.
42+
- **Text**: Sends the rendered alert notification message in plain text format.
43+
44+
## MQTT JSON payload
45+
46+
If the JSON message format is selected in **Optional MQTT settings**, the payload is sent in the following structure.
47+
48+
```json
49+
{
50+
"receiver": "My MQTT integration",
51+
"status": "firing",
52+
"orgId": 1,
53+
"alerts": [
54+
{
55+
"status": "firing",
56+
"labels": {
57+
"alertname": "High memory usage",
58+
"team": "blue",
59+
"zone": "us-1"
60+
},
61+
"annotations": {
62+
"description": "The system has high memory usage",
63+
"runbook_url": "https://myrunbook.com/runbook/1234",
64+
"summary": "This alert was triggered for zone us-1"
65+
},
66+
"startsAt": "2021-10-12T09:51:03.157076+02:00",
67+
"endsAt": "0001-01-01T00:00:00Z",
68+
"generatorURL": "https://play.grafana.org/alerting/1afz29v7z/edit",
69+
"fingerprint": "c6eadffa33fcdf37",
70+
"silenceURL": "https://play.grafana.org/alerting/silence/new?alertmanager=grafana&matchers=alertname%3DT2%2Cteam%3Dblue%2Czone%3Dus-1",
71+
"dashboardURL": "",
72+
"panelURL": "",
73+
"values": {
74+
"B": 44.23943737541908,
75+
"C": 1
76+
}
77+
},
78+
{
79+
"status": "firing",
80+
"labels": {
81+
"alertname": "High CPU usage",
82+
"team": "blue",
83+
"zone": "eu-1"
84+
},
85+
"annotations": {
86+
"description": "The system has high CPU usage",
87+
"runbook_url": "https://myrunbook.com/runbook/1234",
88+
"summary": "This alert was triggered for zone eu-1"
89+
},
90+
"startsAt": "2021-10-12T09:56:03.157076+02:00",
91+
"endsAt": "0001-01-01T00:00:00Z",
92+
"generatorURL": "https://play.grafana.org/alerting/d1rdpdv7k/edit",
93+
"fingerprint": "bc97ff14869b13e3",
94+
"silenceURL": "https://play.grafana.org/alerting/silence/new?alertmanager=grafana&matchers=alertname%3DT1%2Cteam%3Dblue%2Czone%3Deu-1",
95+
"dashboardURL": "",
96+
"panelURL": "",
97+
"values": {
98+
"B": 44.23943737541908,
99+
"C": 1
100+
}
101+
}
102+
],
103+
"groupLabels": {},
104+
"commonLabels": {
105+
"team": "blue"
106+
},
107+
"commonAnnotations": {},
108+
"externalURL": "https://play.grafana.org/",
109+
"version": "1",
110+
"groupKey": "{}:{}",
111+
"message": "**Firing**\n\nLabels:\n - alertname = T2\n - team = blue\n - zone = us-1\nAnnotations:\n - description = This is the alert rule checking the second system\n - runbook_url = https://myrunbook.com\n - summary = This is my summary\nSource: https://play.grafana.org/alerting/1afz29v7z/edit\nSilence: https://play.grafana.org/alerting/silence/new?alertmanager=grafana&matchers=alertname%3DT2%2Cteam%3Dblue%2Czone%3Dus-1\n\nLabels:\n - alertname = T1\n - team = blue\n - zone = eu-1\nAnnotations:\nSource: https://play.grafana.org/alerting/d1rdpdv7k/edit\nSilence: https://play.grafana.org/alerting/silence/new?alertmanager=grafana&matchers=alertname%3DT1%2Cteam%3Dblue%2Czone%3Deu-1\n"
112+
}
113+
```
114+
115+
### Payload fields
116+
117+
Each notification payload contains the following fields.
118+
119+
| Key | Type | Description |
120+
| ----------------- | ------------------------------------------- | ------------------------------------------------------------------------------- |
121+
| receiver | string | Name of the contact point |
122+
| status | string | Current status of the alert, `firing` or `resolved` |
123+
| orgId | number | ID of the organization related to the payload |
124+
| alerts | array of [alert instances](#alert-instance) | Alerts that are triggering |
125+
| groupLabels | object | Labels that are used for grouping, map of string keys to string values |
126+
| commonLabels | object | Labels that all alarms have in common, map of string keys to string values |
127+
| commonAnnotations | object | Annotations that all alarms have in common, map of string keys to string values |
128+
| externalURL | string | External URL to the Grafana instance sending this webhook |
129+
| version | string | Version of the payload |
130+
| groupKey | string | Key that is used for grouping |
131+
| message | string | Rendered message of the alerts |
132+
133+
### Alert instance
134+
135+
Each alert instance in the `alerts` array has the following fields.
136+
137+
| Key | Type | Description |
138+
| ------------ | ------ | ---------------------------------------------------------------------------------- |
139+
| status | string | Current status of the alert, `firing` or `resolved` |
140+
| labels | object | Labels that are part of this alert, map of string keys to string values |
141+
| annotations | object | Annotations that are part of this alert, map of string keys to string values |
142+
| startsAt | string | Start time of the alert |
143+
| endsAt | string | End time of the alert, default value when not resolved is `0001-01-01T00:00:00Z` |
144+
| values | object | Values that triggered the current status |
145+
| generatorURL | string | URL of the alert rule in the Grafana UI |
146+
| fingerprint | string | The labels fingerprint, alarms with the same labels will have the same fingerprint |
147+
| silenceURL | string | URL to silence the alert rule in the Grafana UI |
148+
| dashboardURL | string | **Deprecated. It will be removed in a future release.** |
149+
| panelURL | string | **Deprecated. It will be removed in a future release.** |
150+
| imageURL | string | URL of a screenshot of a panel assigned to the rule that created this notification |
151+
152+
{{< admonition type="note" >}}
153+
Alert rules are not coupled to dashboards anymore. The fields related to dashboards `dashboardId` and `panelId` have been removed.
154+
{{< /admonition >}}

docs/sources/alerting/configure-notifications/template-notifications/images-in-notifications.md

+1
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ Grafana supports a wide range of contact points with varied support for images i
9999
| Google Chat | No | Yes |
100100
| Kafka | No | No |
101101
| Line | No | No |
102+
| MQTT | No | No |
102103
| Microsoft Teams | No | Yes |
103104
| Opsgenie | No | Yes |
104105
| Pagerduty | No | Yes |

docs/sources/alerting/set-up/provision-alerting-resources/file-provisioning/index.md

+25
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,31 @@ settings:
343343

344344
{{< /collapse >}}
345345

346+
{{< collapse title="MQTT" >}}
347+
348+
#### MQTT
349+
350+
```yaml
351+
type: mqtt
352+
settings:
353+
# <string, required>
354+
brokerUrl: tcp://127.0.0.1:1883
355+
# <string>
356+
clientId: grafana
357+
# <string, required>
358+
topic: grafana/alerts
359+
# <string>
360+
messageFormat: json
361+
# <string>
362+
username: grafana
363+
# <string>
364+
password: password1
365+
# <bool>
366+
insecureSkipVerify: false
367+
```
368+
369+
{{< /collapse >}}
370+
346371
{{< collapse title="Microsoft Teams" >}}
347372

348373
#### Microsoft Teams

go.mod

+2-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ require (
7474
github.com/googleapis/gax-go/v2 v2.13.0 // @grafana/grafana-backend-group
7575
github.com/gorilla/mux v1.8.1 // @grafana/grafana-backend-group
7676
github.com/gorilla/websocket v1.5.0 // @grafana/grafana-app-platform-squad
77-
github.com/grafana/alerting v0.0.0-20240812131556-611a23ff0f7f // @grafana/alerting-backend
77+
github.com/grafana/alerting v0.0.0-20240822131459-9daa6239cc41 // @grafana/alerting-backend
7878
github.com/grafana/authlib v0.0.0-20240814074258-eae7d47f01db // @grafana/identity-access-team
7979
github.com/grafana/authlib/claims v0.0.0-20240814074258-eae7d47f01db // @grafana/identity-access-team
8080
github.com/grafana/codejen v0.0.3 // @grafana/dataviz-squad
@@ -479,6 +479,7 @@ require (
479479

480480
require (
481481
cloud.google.com/go/longrunning v0.5.12 // indirect
482+
github.com/at-wat/mqtt-go v0.19.4 // indirect
482483
github.com/grafana/grafana/pkg/semconv v0.0.0-20240808213237-f4d2e064f435 // indirect
483484
github.com/hairyhenderson/go-which v0.2.0 // indirect
484485
github.com/iancoleman/orderedmap v0.3.0 // indirect

go.sum

+4-2
Original file line numberDiff line numberDiff line change
@@ -1542,6 +1542,8 @@ github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6l
15421542
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
15431543
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
15441544
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
1545+
github.com/at-wat/mqtt-go v0.19.4 h1:R2cbCU7O5PHQ38unbe1Y51ncG3KsFEJV6QeipDoqdLQ=
1546+
github.com/at-wat/mqtt-go v0.19.4/go.mod h1:AsiWc9kqVOhqq7LzUeWT/AkKUBfx3Sw5cEe8lc06fqA=
15451547
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
15461548
github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
15471549
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
@@ -2244,8 +2246,8 @@ github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY
22442246
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
22452247
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
22462248
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
2247-
github.com/grafana/alerting v0.0.0-20240812131556-611a23ff0f7f h1:c8QAFXkilBiF29xc7oKO2IkbGE3bp9NIKgiNLazdooY=
2248-
github.com/grafana/alerting v0.0.0-20240812131556-611a23ff0f7f/go.mod h1:DLj8frbtCaITljC2jc0L85JQViPF3mPfOSiYhm1osso=
2249+
github.com/grafana/alerting v0.0.0-20240822131459-9daa6239cc41 h1:p+UsX43BoDH5YlG6xUd9xDS3M4sWouy8VJ+ODv5S6uE=
2250+
github.com/grafana/alerting v0.0.0-20240822131459-9daa6239cc41/go.mod h1:GMLi6d09Xqo96fCVUjNk//rcjP5NKEdjOzfWIffD5r4=
22492251
github.com/grafana/authlib v0.0.0-20240814074258-eae7d47f01db h1:z++X4DdoX+aNlZNT1ZY4cykiFay4+f077pa0AG48SGg=
22502252
github.com/grafana/authlib v0.0.0-20240814074258-eae7d47f01db/go.mod h1:ptt910z9KFfpVSIbSbXvTRR7tS19mxD7EtmVbbJi/WE=
22512253
github.com/grafana/authlib/claims v0.0.0-20240814074258-eae7d47f01db h1:mDk0bwRV6rDrLSmKXftcPf9kLA9uH6EvxJvzpPW9bso=

go.work.sum

+3
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,9 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7
715715
github.com/grafana/authlib v0.0.0-20240730122259-a0d13672efb1/go.mod h1:YA9We4kTafu7mlMnUh3In6Q2wpg8fYN3ycgCKOK1TB8=
716716
github.com/grafana/authlib/claims v0.0.0-20240809101159-74eaccc31a06/go.mod h1:r+F8H6awwjNQt/KPZ2GNwjk8TvsJ7/gxzkXN26GlL/A=
717717
github.com/grafana/gomemcache v0.0.0-20240229205252-cd6a66d6fb56/go.mod h1:PGk3RjYHpxMM8HFPhKKo+vve3DdlPUELZLSDEFehPuU=
718+
github.com/grafana/grafana-plugin-sdk-go v0.235.0/go.mod h1:6n9LbrjGL3xAATntYVNcIi90G9BVHRJjzHKz5FXVfWw=
719+
github.com/grafana/prometheus-alertmanager v0.25.1-0.20240422145632-c33c6b5b6e6b h1:HCbWyVL6vi7gxyO76gQksSPH203oBJ1MJ3JcG1OQlsg=
720+
github.com/grafana/prometheus-alertmanager v0.25.1-0.20240422145632-c33c6b5b6e6b/go.mod h1:01sXtHoRwI8W324IPAzuxDFOmALqYLCOhvSC2fUHWXc=
718721
github.com/grafana/pyroscope-go/godeltaprof v0.1.6/go.mod h1:Tk376Nbldo4Cha9RgiU7ik8WKFkNpfds98aUzS8omLE=
719722
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
720723
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM=

pkg/services/ngalert/api/compat_contact_points.go

+13-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func ContactPointToContactPointExport(cp definitions.ContactPoint) (notify.APIRe
5151
len(cp.Pagerduty) + len(cp.OnCall) + len(cp.Pushover) + len(cp.Sensugo) +
5252
len(cp.Sns) + len(cp.Slack) + len(cp.Teams) + len(cp.Telegram) +
5353
len(cp.Threema) + len(cp.Victorops) + len(cp.Webhook) + len(cp.Wecom) +
54-
len(cp.Webex)
54+
len(cp.Webex) + len(cp.Mqtt)
5555

5656
integration := make([]*notify.GrafanaIntegrationConfig, 0, contactPointsLength)
5757

@@ -105,6 +105,13 @@ func ContactPointToContactPointExport(cp definitions.ContactPoint) (notify.APIRe
105105
}
106106
integration = append(integration, el)
107107
}
108+
for _, i := range cp.Mqtt {
109+
el, err := marshallIntegration(j, "mqtt", i, i.DisableResolveMessage)
110+
if err != nil {
111+
errs = append(errs, err)
112+
}
113+
integration = append(integration, el)
114+
}
108115
for _, i := range cp.Opsgenie {
109116
el, err := marshallIntegration(j, "opsgenie", i, i.DisableResolveMessage)
110117
if err != nil {
@@ -274,6 +281,11 @@ func parseIntegration(json jsoniter.API, result *definitions.ContactPoint, recei
274281
if err = json.Unmarshal(data, &integration); err == nil {
275282
result.Line = append(result.Line, integration)
276283
}
284+
case "mqtt":
285+
integration := definitions.MqttIntegration{DisableResolveMessage: disable}
286+
if err = json.Unmarshal(data, &integration); err == nil {
287+
result.Mqtt = append(result.Mqtt, integration)
288+
}
277289
case "opsgenie":
278290
integration := definitions.OpsgenieIntegration{DisableResolveMessage: disable}
279291
if err = json.Unmarshal(data, &integration); err == nil {

pkg/services/ngalert/api/tooling/definitions/contact_points.go

+14
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,19 @@ type LineIntegration struct {
8585
Description *string `json:"description,omitempty" yaml:"description,omitempty" hcl:"description"`
8686
}
8787

88+
type MqttIntegration struct {
89+
DisableResolveMessage *bool `json:"-" yaml:"-" hcl:"disable_resolve_message"`
90+
91+
BrokerURL *string `json:"brokerUrl,omitempty" yaml:"brokerUrl,omitempty" hcl:"broker_url"`
92+
ClientID *string `json:"clientId,omitempty" yaml:"clientId,omitempty" hcl:"client_id"`
93+
Topic *string `json:"topic,omitempty" yaml:"topic,omitempty" hcl:"topic"`
94+
Message *string `json:"message,omitempty" yaml:"message,omitempty" hcl:"message"`
95+
MessageFormat *string `json:"messageFormat,omitempty" yaml:"messageFormat,omitempty" hcl:"message_format"`
96+
Username *string `json:"username,omitempty" yaml:"username,omitempty" hcl:"username"`
97+
Password *Secret `json:"password,omitempty" yaml:"password,omitempty" hcl:"password"`
98+
InsecureSkipVerify *bool `json:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty" hcl:"insecure_skip_verify"`
99+
}
100+
88101
type OnCallIntegration struct {
89102
DisableResolveMessage *bool `json:"-" yaml:"-" hcl:"disable_resolve_message"`
90103

@@ -299,6 +312,7 @@ type ContactPoint struct {
299312
Googlechat []GooglechatIntegration `json:"googlechat" yaml:"googlechat" hcl:"googlechat,block"`
300313
Kafka []KafkaIntegration `json:"kafka" yaml:"kafka" hcl:"kafka,block"`
301314
Line []LineIntegration `json:"line" yaml:"line" hcl:"line,block"`
315+
Mqtt []MqttIntegration `json:"mqtt" yaml:"mqtt" hcl:"mqtt,block"`
302316
Opsgenie []OpsgenieIntegration `json:"opsgenie" yaml:"opsgenie" hcl:"opsgenie,block"`
303317
Pagerduty []PagerdutyIntegration `json:"pagerduty" yaml:"pagerduty" hcl:"pagerduty,block"`
304318
OnCall []OnCallIntegration `json:"oncall" yaml:"oncall" hcl:"oncall,block"`

0 commit comments

Comments
 (0)