integrations: Add an incoming webhook for Grafana.

Tweaked by tabbott to use formatted suggested in one of the various
duplicate PRs for this issue, showing the rule name clearly.

Fixes #12951.
This commit is contained in:
Jenny Ghose
2020-04-15 00:06:49 -04:00
committed by Tim Abbott
parent a0c2121958
commit 180c16c80e
10 changed files with 181 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -325,6 +325,7 @@ WEBHOOK_INTEGRATIONS: List[WebhookIntegration] = [
WebhookIntegration('gocd', ['continuous-integration'], display_name='GoCD'), WebhookIntegration('gocd', ['continuous-integration'], display_name='GoCD'),
WebhookIntegration('gogs', ['version-control'], stream_name='commits'), WebhookIntegration('gogs', ['version-control'], stream_name='commits'),
WebhookIntegration('gosquared', ['marketing'], display_name='GoSquared'), WebhookIntegration('gosquared', ['marketing'], display_name='GoSquared'),
WebhookIntegration('grafana', ['monitoring'], display_name='Grafana'),
WebhookIntegration('greenhouse', ['hr'], display_name='Greenhouse'), WebhookIntegration('greenhouse', ['hr'], display_name='Greenhouse'),
WebhookIntegration('groove', ['customer-support'], display_name='Groove'), WebhookIntegration('groove', ['customer-support'], display_name='Groove'),
WebhookIntegration('harbor', ['deployment', 'productivity'], display_name='Harbor'), WebhookIntegration('harbor', ['deployment', 'productivity'], display_name='Harbor'),

View File

View File

@@ -0,0 +1,23 @@
See your Grafana dashboard alerts in Zulip!
1. {!create-stream.md!}
1. {!create-bot-construct-url-indented.md!}
1. In Grafana, go to **Alerting**. Click on **Notification channels**.
Configure **Edit Notification Channel** as appropriate for your
alert notification. Set the name. Under **Type**, choose **webhook**.
In **Webhook Settings**, set **URL** to the URL constructed above.
Under **HTTP method**, choose **POST**. Click Save.
1. Create an alert. Within your new alert rule, scroll down
to the **Notifications** section. Click on the button next to **Send to**
and select the webhook notification channel you just made. You can also
choose to write a message, which will be included in the Zulip notifications.
1. Return to **Notification channels**. You may now click **Send Test** and
you will see a Grafana test alert notification in Zulip.
{!congrats.md!}
![](/static/images/integrations/grafana/001.png)

View File

@@ -0,0 +1,25 @@
{
"dashboardId": 1,
"evalMatches": [
{
"value": 100,
"metric": "High value",
"tags": null
},
{
"value": 200,
"metric": "Higher Value",
"tags": null
}
],
"imageUrl": "https://grafana.com/assets/img/blog/mixed_styles.png",
"message": "Someone is testing the alert notification within grafana.",
"orgId": 0,
"panelId": 1,
"ruleId": 0,
"ruleName": "Test rule",
"ruleUrl": "http://localhost:3000/",
"state": "alerting",
"tags": {},
"title": "[Alerting] Test notification"
}

View File

@@ -0,0 +1,13 @@
{
"dashboardId": 2,
"evalMatches": [],
"message": "The panel has no data.",
"orgId": 1,
"panelId": 6,
"ruleId": 3,
"ruleName": "No Data alert",
"ruleUrl": "http://localhost:3000/d/GG2qhR3Wz/alerttest?fullscreen&edit&tab=alert&panelId=6&orgId=1",
"state": "alerting",
"tags": {},
"title": "[Alerting] No Data alert"
}

View File

@@ -0,0 +1,18 @@
{
"dashboardId": 2,
"evalMatches": [
{
"value": 21.573108436586445,
"metric": "A-series",
"tags": {}
}
],
"orgId": 1,
"panelId": 8,
"ruleId": 4,
"ruleName": "No Message alert",
"ruleUrl": "http://localhost:3000/d/GG2qhR3Wz/alerttest?fullscreen&edit&tab=alert&panelId=8&orgId=1",
"state": "alerting",
"tags": {},
"title": "[Alerting] No Message alert"
}

View File

@@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
from zerver.lib.test_classes import WebhookTestCase
class GrafanaHookTests(WebhookTestCase):
STREAM_NAME = 'grafana'
URL_TEMPLATE = "/api/v1/external/grafana?&api_key={api_key}&stream={stream}"
FIXTURE_DIR_NAME = 'grafana'
# Note: Include a test function per each distinct message condition your integration supports
def test_alert(self) -> None:
expected_topic = "[Alerting] Test notification"
expected_message = """
[Test rule](http://localhost:3000/)
Someone is testing the alert notification within grafana.
**High value:** 100
**Higher Value:** 200
[Click to view visualization](https://grafana.com/assets/img/blog/mixed_styles.png)
""".strip()
# use fixture named helloworld_hello
self.send_and_test_stream_message('alert', expected_topic, expected_message,
content_type="application/x-www-form-urlencoded")
def test_no_data_alert(self) -> None:
expected_topic = "[Alerting] No Data alert"
expected_message = """
[No Data alert](http://localhost:3000/d/GG2qhR3Wz/alerttest?fullscreen&edit&tab=alert&panelId=6&orgId=1)
The panel has no data.
""".strip()
# use fixture named helloworld_hello
self.send_and_test_stream_message('no_data_alert', expected_topic, expected_message,
content_type="application/x-www-form-urlencoded")
def test_no_message_alert(self) -> None:
expected_topic = "[Alerting] No Message alert"
expected_message = """
[No Message alert](http://localhost:3000/d/GG2qhR3Wz/alerttest?fullscreen&edit&tab=alert&panelId=8&orgId=1)
**A-series:** 21.573108436586445
""".strip()
# use fixture named helloworld_hello
self.send_and_test_stream_message('no_message_alert', expected_topic, expected_message,
content_type="application/x-www-form-urlencoded")
def get_body(self, fixture_name: str) -> str:
return self.webhook_fixture_data("grafana", fixture_name, file_type="json")

View File

@@ -0,0 +1,47 @@
from typing import Any, Dict
from django.http import HttpRequest, HttpResponse
from zerver.decorator import api_key_only_webhook_view
from zerver.lib.webhooks.common import check_send_webhook_message
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_success
from zerver.models import UserProfile
GRAFANA_TOPIC_TEMPLATE = u'{alert_title}'
GRAFANA_MESSAGE_TEMPLATE = u'[{rule_name}]({rule_url})\n\n{alert_message}{eval_matches}'
@api_key_only_webhook_view('Grafana')
@has_request_variables
def api_grafana_webhook(
request: HttpRequest, user_profile: UserProfile,
payload: Dict[str, Any]=REQ(argument_type='body')
) -> HttpResponse:
topic = GRAFANA_TOPIC_TEMPLATE.format(alert_title=payload['title'])
eval_matches_text = ''
eval_matches = payload.get('evalMatches')
if eval_matches is not None:
for match in eval_matches:
eval_matches_text += '**{}:** {}\n'.format(match['metric'], match['value'])
message_text = ''
if payload.get('message') is not None:
message_text = payload['message'] + "\n\n"
body = GRAFANA_MESSAGE_TEMPLATE.format(alert_message=message_text,
rule_name=payload['ruleName'],
rule_url=payload['ruleUrl'],
eval_matches=eval_matches_text)
if payload.get('imageUrl') is not None:
body += "\n[Click to view visualization]({visualization})".format(visualization=payload['imageUrl'])
body = body.strip()
# send the message
check_send_webhook_message(request, user_profile, topic, body)
return json_success()