Explorar el Código

Added Telegram Messenger notification destination

Mikhail Leonov hace 9 años
padre
commit
e32a653cb6

+ 2 - 0
pkg/metrics/metrics.go

@@ -47,6 +47,7 @@ var (
 	M_Alerting_Notification_Sent_PagerDuty Counter
 	M_Alerting_Notification_Sent_Victorops Counter
 	M_Alerting_Notification_Sent_OpsGenie  Counter
+	M_Alerting_Notification_Sent_Telegram  Counter
 	M_Aws_CloudWatch_GetMetricStatistics   Counter
 	M_Aws_CloudWatch_ListMetrics           Counter
 
@@ -114,6 +115,7 @@ func initMetricVars(settings *MetricSettings) {
 	M_Alerting_Notification_Sent_PagerDuty = RegCounter("alerting.notifications_sent", "type", "pagerduty")
 	M_Alerting_Notification_Sent_Victorops = RegCounter("alerting.notifications_sent", "type", "victorops")
 	M_Alerting_Notification_Sent_OpsGenie = RegCounter("alerting.notifications_sent", "type", "opsgenie")
+	M_Alerting_Notification_Sent_Telegram = RegCounter("alerting.notifications_sent", "type", "telegram")
 
 	M_Aws_CloudWatch_GetMetricStatistics = RegCounter("aws.cloudwatch.get_metric_statistics")
 	M_Aws_CloudWatch_ListMetrics = RegCounter("aws.cloudwatch.list_metrics")

+ 86 - 0
pkg/services/alerting/notifiers/telegram.go

@@ -0,0 +1,86 @@
+package notifiers
+
+import (
+	"fmt"
+
+	"github.com/grafana/grafana/pkg/bus"
+	"github.com/grafana/grafana/pkg/components/simplejson"
+	"github.com/grafana/grafana/pkg/log"
+	"github.com/grafana/grafana/pkg/metrics"
+	m "github.com/grafana/grafana/pkg/models"
+	"github.com/grafana/grafana/pkg/services/alerting"
+)
+
+var (
+	telegeramApiUrl string = "https://api.telegram.org/bot%s/%s"
+)
+
+func init() {
+	alerting.RegisterNotifier("telegram", NewTelegramNotifier)
+}
+
+type TelegramNotifier struct {
+	NotifierBase
+	BotToken string
+	ChatID   string
+	log      log.Logger
+}
+
+func NewTelegramNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
+	if model.Settings == nil {
+		return nil, alerting.ValidationError{Reason: "No Settings Supplied"}
+	}
+
+	botToken := model.Settings.Get("bottoken").MustString()
+	chatId := model.Settings.Get("chatid").MustString()
+
+	if botToken == "" {
+		return nil, alerting.ValidationError{Reason: "Could not find Bot Token in settings"}
+	}
+
+	if chatId == "" {
+		return nil, alerting.ValidationError{Reason: "Could not find Chat Id in settings"}
+	}
+
+	return &TelegramNotifier{
+		NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings),
+		BotToken:     botToken,
+		ChatID:       chatId,
+		log:          log.New("alerting.notifier.telegram"),
+	}, nil
+}
+
+func (this *TelegramNotifier) Notify(evalContext *alerting.EvalContext) error {
+	this.log.Info("Sending alert notification to", "bot_token", this.BotToken)
+	this.log.Info("Sending alert notification to", "chat_id", this.ChatID)
+	metrics.M_Alerting_Notification_Sent_Telegram.Inc(1)
+
+	bodyJSON := simplejson.New()
+
+	bodyJSON.Set("chat_id", this.ChatID)
+	bodyJSON.Set("parse_mode", "html")
+
+	message := fmt.Sprintf("%s\nState: %s\nMessage: %s\n", evalContext.GetNotificationTitle(), evalContext.Rule.Name, evalContext.Rule.Message)
+
+	ruleUrl, err := evalContext.GetRuleUrl()
+	if err == nil {
+		message = message + fmt.Sprintf("URL: %s\n", ruleUrl)
+	}
+	bodyJSON.Set("text", message)
+
+	url := fmt.Sprintf(telegeramApiUrl, this.BotToken, "sendMessage")
+	body, _ := bodyJSON.MarshalJSON()
+
+	cmd := &m.SendWebhookSync{
+		Url:        url,
+		Body:       string(body),
+		HttpMethod: "POST",
+	}
+
+	if err := bus.DispatchCtx(evalContext.Ctx, cmd); err != nil {
+		this.log.Error("Failed to send webhook", "error", err, "webhook", this.Name)
+		return err
+	}
+
+	return nil
+}

+ 55 - 0
pkg/services/alerting/notifiers/telegram_test.go

@@ -0,0 +1,55 @@
+package notifiers
+
+import (
+	"testing"
+
+	"github.com/grafana/grafana/pkg/components/simplejson"
+	m "github.com/grafana/grafana/pkg/models"
+	. "github.com/smartystreets/goconvey/convey"
+)
+
+func TestTelegramNotifier(t *testing.T) {
+	Convey("Telegram notifier tests", t, func() {
+
+		Convey("Parsing alert notification from settings", func() {
+			Convey("empty settings should return error", func() {
+				json := `{ }`
+
+				settingsJSON, _ := simplejson.NewJson([]byte(json))
+				model := &m.AlertNotification{
+					Name:     "telegram_testing",
+					Type:     "telegram",
+					Settings: settingsJSON,
+				}
+
+				_, err := NewTelegramNotifier(model)
+				So(err, ShouldNotBeNil)
+			})
+
+			Convey("settings should trigger incident", func() {
+				json := `
+				{
+          "bottoken": "abcdefgh0123456789",
+					"chatid": "-1234567890"
+				}`
+
+				settingsJSON, _ := simplejson.NewJson([]byte(json))
+				model := &m.AlertNotification{
+					Name:     "telegram_testing",
+					Type:     "telegram",
+					Settings: settingsJSON,
+				}
+
+				not, err := NewTelegramNotifier(model)
+				telegramNotifier := not.(*TelegramNotifier)
+
+				So(err, ShouldBeNil)
+				So(telegramNotifier.Name, ShouldEqual, "telegram_testing")
+				So(telegramNotifier.Type, ShouldEqual, "telegram")
+				So(telegramNotifier.BotToken, ShouldEqual, "abcdefgh0123456789")
+				So(telegramNotifier.ChatID, ShouldEqual, "-1234567890")
+			})
+
+		})
+	})
+}

+ 23 - 1
public/app/features/alerting/partials/notification_edit.html

@@ -19,7 +19,7 @@
       <div class="gf-form">
         <span class="gf-form-label width-12">Type</span>
         <div class="gf-form-select-wrapper width-15">
-          <select class="gf-form-input" ng-model="ctrl.model.type" ng-options="t for t in ['webhook', 'email', 'slack', 'pagerduty', 'victorops', 'opsgenie']" ng-change="ctrl.typeChanged(notification, $index)">
+          <select class="gf-form-input" ng-model="ctrl.model.type" ng-options="t for t in ['webhook', 'email', 'slack', 'pagerduty', 'victorops', 'opsgenie', 'telegram']" ng-change="ctrl.typeChanged(notification, $index)">
           </select>
         </div>
       </div>
@@ -139,6 +139,28 @@
       </div>
     </div>
 
+    <div class="gf-form-group" ng-if="ctrl.model.type === 'telegram'">
+      <h3 class="page-heading">Telegram API settings</h3>
+      <div class="gf-form">
+        <span class="gf-form-label width-14">BOT API Token</span>
+        <input type="text" required
+					class="gf-form-input"
+					ng-model="ctrl.model.settings.bottoken"
+					placeholder="Telegram BOT API Token"></input>
+      </div>
+      <div class="gf-form">
+        <span class="gf-form-label width-6">Chat ID</span>
+        <input type="text" required
+					class="gf-form-input"
+					ng-model="ctrl.model.settings.chatid"
+					data-placement="right">
+        </input>
+        <info-popover mode="right-absolute">
+					Integer Telegram Chat Identifier
+        </info-popover>
+      </div>
+    </div>
+
     <div class="gf-form-group">
       <div class="gf-form-inline">
         <div class="gf-form width-6">