From 99e99922b4476fcd0d85371bc566a6c644a23fe1 Mon Sep 17 00:00:00 2001 From: bergquist Date: Wed, 10 Aug 2016 17:27:39 +0200 Subject: [PATCH 1/4] feat(alerting): add support for uploading images to webdav. closes #5770 --- conf/defaults.ini | 13 ++- conf/sample.ini | 16 ++++ pkg/components/imguploader/imguploader.go | 94 +++++++++---------- .../imguploader/imguploader_test.go | 53 +++++++++++ pkg/components/imguploader/s3uploader.go | 53 +++++++++++ pkg/components/imguploader/webdavuploader.go | 51 ++++++++++ .../imguploader/webdavuploader_test.go | 18 ++++ pkg/services/alerting/notifier.go | 7 +- pkg/setting/setting.go | 8 +- 9 files changed, 255 insertions(+), 58 deletions(-) create mode 100644 pkg/components/imguploader/imguploader_test.go create mode 100644 pkg/components/imguploader/s3uploader.go create mode 100644 pkg/components/imguploader/webdavuploader.go create mode 100644 pkg/components/imguploader/webdavuploader_test.go diff --git a/conf/defaults.ini b/conf/defaults.ini index 11c9ca667c4..e1619b57006 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -383,8 +383,17 @@ interval_seconds = 60 [grafana_net] url = https://grafana.net -#################################### S3 Temp Store ########################## -[s3-temp-image-store] +#################################### External image storage ########################## +[external_image_storage] +# You can choose between (s3, webdav or internal) +provider = s3 + +[external_image_storage.s3] bucket_url = access_key = secret_key = + +[external_image_storage.webdav] +url = +username = +password = diff --git a/conf/sample.ini b/conf/sample.ini index 80ca033f035..ee333be85c0 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -312,3 +312,19 @@ enabled = true # Url used to to import dashboards directly from Grafana.net [grafana_net] url = https://grafana.net + +#################################### External image storage ########################## +[external_image_storage] +# Used for uploading images to public servers so they can be included in slack/email messages. +# you can choose between (s3, webdav or internal) +provider = s3 + +[external_image_storage.s3] +bucket_url = +access_key = +secret_key = + +[external_image_storage.webdav] +url = +username = +password = diff --git a/pkg/components/imguploader/imguploader.go b/pkg/components/imguploader/imguploader.go index 9d3a571d9ad..5b383e69f34 100644 --- a/pkg/components/imguploader/imguploader.go +++ b/pkg/components/imguploader/imguploader.go @@ -1,57 +1,57 @@ package imguploader import ( - "io/ioutil" - "net/http" + "fmt" - "github.com/grafana/grafana/pkg/util" - "github.com/kr/s3/s3util" + "github.com/grafana/grafana/pkg/setting" ) -type Uploader interface { +type ImageUploader interface { Upload(path string) (string, error) } -type S3Uploader struct { - bucket string - secretKey string - accessKey string -} - -func NewS3Uploader(bucket, accessKey, secretKey string) *S3Uploader { - return &S3Uploader{ - bucket: bucket, - accessKey: accessKey, - secretKey: secretKey, - } -} - -func (u *S3Uploader) Upload(path string) (string, error) { - - s3util.DefaultConfig.AccessKey = u.accessKey - s3util.DefaultConfig.SecretKey = u.secretKey - - header := make(http.Header) - header.Add("x-amz-acl", "public-read") - header.Add("Content-Type", "image/png") - - fullUrl := u.bucket + util.GetRandomString(20) + ".png" - writer, err := s3util.Create(fullUrl, header, nil) - if err != nil { - return "", err - } - - defer writer.Close() - - imgData, err := ioutil.ReadFile(path) - if err != nil { - return "", err - } - - _, err = writer.Write(imgData) - if err != nil { - return "", err - } - - return fullUrl, nil +func NewImageUploader() (ImageUploader, error) { + + switch setting.ImageUploadProvider { + case "s3": + s3sec, err := setting.Cfg.GetSection("external_image_storage.s3") + if err != nil { + return nil, err + } + + bucket := s3sec.Key("secret_key").String() + accessKey := s3sec.Key("access_key").String() + secretKey := s3sec.Key("secret_key").String() + + if bucket == "" { + return nil, fmt.Errorf("Could not find bucket setting for image.uploader.s3") + } + + if accessKey == "" { + return nil, fmt.Errorf("Could not find accessKey setting for image.uploader.s3") + } + + if secretKey == "" { + return nil, fmt.Errorf("Could not find secretKey setting for image.uploader.s3") + } + + return NewS3Uploader(bucket, accessKey, secretKey), nil + case "webdav": + webdavSec, err := setting.Cfg.GetSection("external_image_storage.webdav") + if err != nil { + return nil, err + } + + url := webdavSec.Key("url").String() + if url == "" { + return nil, fmt.Errorf("Could not find url key for image.uploader.webdav") + } + + username := webdavSec.Key("username").String() + password := webdavSec.Key("password").String() + + return NewWebdavImageUploader(url, username, password) + } + + return nil, fmt.Errorf("could not find specified provider") } diff --git a/pkg/components/imguploader/imguploader_test.go b/pkg/components/imguploader/imguploader_test.go new file mode 100644 index 00000000000..d12464dae69 --- /dev/null +++ b/pkg/components/imguploader/imguploader_test.go @@ -0,0 +1,53 @@ +package imguploader + +import ( + "reflect" + "testing" + + "github.com/grafana/grafana/pkg/setting" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestImageUploaderFactory(t *testing.T) { + Convey("Can create image uploader for ", t, func() { + Convey("S3ImageUploader", func() { + var err error + setting.NewConfigContext(&setting.CommandLineArgs{ + HomePath: "../../../", + }) + + setting.ImageUploadProvider = "s3" + + s3sec, err := setting.Cfg.GetSection("external_image_storage.s3") + s3sec.NewKey("bucket_url", "bucket_url") + s3sec.NewKey("access_key", "access_key") + s3sec.NewKey("secret_key", "secret_key") + + uploader, err := NewImageUploader() + + So(err, ShouldBeNil) + So(reflect.TypeOf(uploader), ShouldEqual, reflect.TypeOf(&S3Uploader{})) + }) + + Convey("Webdav uploader", func() { + var err error + + setting.NewConfigContext(&setting.CommandLineArgs{ + HomePath: "../../../", + }) + + setting.ImageUploadProvider = "webdav" + + webdavSec, err := setting.Cfg.GetSection("external_image_storage.webdav") + webdavSec.NewKey("url", "webdavUrl") + webdavSec.NewKey("username", "username") + webdavSec.NewKey("password", "password") + + uploader, err := NewImageUploader() + + So(err, ShouldBeNil) + So(reflect.TypeOf(uploader), ShouldEqual, reflect.TypeOf(&WebdavUploader{})) + }) + }) +} diff --git a/pkg/components/imguploader/s3uploader.go b/pkg/components/imguploader/s3uploader.go new file mode 100644 index 00000000000..af995d566c1 --- /dev/null +++ b/pkg/components/imguploader/s3uploader.go @@ -0,0 +1,53 @@ +package imguploader + +import ( + "io/ioutil" + "net/http" + + "github.com/grafana/grafana/pkg/util" + "github.com/kr/s3/s3util" +) + +type S3Uploader struct { + bucket string + secretKey string + accessKey string +} + +func NewS3Uploader(bucket, accessKey, secretKey string) *S3Uploader { + return &S3Uploader{ + bucket: bucket, + accessKey: accessKey, + secretKey: secretKey, + } +} + +func (u *S3Uploader) Upload(path string) (string, error) { + + s3util.DefaultConfig.AccessKey = u.accessKey + s3util.DefaultConfig.SecretKey = u.secretKey + + header := make(http.Header) + header.Add("x-amz-acl", "public-read") + header.Add("Content-Type", "image/png") + + fullUrl := u.bucket + util.GetRandomString(20) + ".png" + writer, err := s3util.Create(fullUrl, header, nil) + if err != nil { + return "", err + } + + defer writer.Close() + + imgData, err := ioutil.ReadFile(path) + if err != nil { + return "", err + } + + _, err = writer.Write(imgData) + if err != nil { + return "", err + } + + return fullUrl, nil +} diff --git a/pkg/components/imguploader/webdavuploader.go b/pkg/components/imguploader/webdavuploader.go new file mode 100644 index 00000000000..74444b1b123 --- /dev/null +++ b/pkg/components/imguploader/webdavuploader.go @@ -0,0 +1,51 @@ +package imguploader + +import ( + "bytes" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "path" + "time" + + "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/util" +) + +type WebdavUploader struct { + url string + username string + password string +} + +func (u *WebdavUploader) Upload(pa string) (string, error) { + log.Error2("Hej") + client := http.Client{Timeout: time.Duration(10 * time.Second)} + + url, _ := url.Parse(u.url) + url.Path = path.Join(url.Path, util.GetRandomString(20)+".png") + + imgData, err := ioutil.ReadFile(pa) + req, err := http.NewRequest("PUT", url.String(), bytes.NewReader(imgData)) + res, err := client.Do(req) + + if err != nil { + return "", err + } + + if res.StatusCode != http.StatusCreated { + body, _ := ioutil.ReadAll(res.Body) + return "", fmt.Errorf("Failed to upload image. Returned statuscode %v body %s", res.StatusCode, body) + } + + return url.String(), nil +} + +func NewWebdavImageUploader(url, username, passwrod string) (*WebdavUploader, error) { + return &WebdavUploader{ + url: url, + username: username, + password: passwrod, + }, nil +} diff --git a/pkg/components/imguploader/webdavuploader_test.go b/pkg/components/imguploader/webdavuploader_test.go new file mode 100644 index 00000000000..273cd1c2a86 --- /dev/null +++ b/pkg/components/imguploader/webdavuploader_test.go @@ -0,0 +1,18 @@ +package imguploader + +import ( + "testing" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestUploadToWebdav(t *testing.T) { + webdavUploader, _ := NewWebdavImageUploader("http://localhost:9998/dav/", "username", "password") + + SkipConvey("[Integration test] for external_image_store.webdav", t, func() { + path, err := webdavUploader.Upload("../../../public/img/logo_transparent_400x.png") + + So(err, ShouldBeNil) + So(path, ShouldNotEqual, "") + }) +} diff --git a/pkg/services/alerting/notifier.go b/pkg/services/alerting/notifier.go index 28a3a331dd0..c345594de2c 100644 --- a/pkg/services/alerting/notifier.go +++ b/pkg/services/alerting/notifier.go @@ -8,7 +8,6 @@ import ( "github.com/grafana/grafana/pkg/components/renderer" "github.com/grafana/grafana/pkg/log" m "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/setting" ) type RootNotifier struct { @@ -54,10 +53,8 @@ func (n *RootNotifier) Notify(context *EvalContext) { } func (n *RootNotifier) uploadImage(context *EvalContext) error { - uploader := imguploader.NewS3Uploader( - setting.S3TempImageStoreBucketUrl, - setting.S3TempImageStoreAccessKey, - setting.S3TempImageStoreSecretKey) + + uploader, _ := imguploader.NewImageUploader() imageUrl, err := context.GetImageUrl() if err != nil { diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index e1c8cdf1c7d..2dda02cfa6c 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -153,6 +153,8 @@ var ( S3TempImageStoreBucketUrl string S3TempImageStoreAccessKey string S3TempImageStoreSecretKey string + + ImageUploadProvider string ) type CommandLineArgs struct { @@ -539,10 +541,8 @@ func NewConfigContext(args *CommandLineArgs) error { GrafanaNetUrl = Cfg.Section("grafana.net").Key("url").MustString("https://grafana.net") - s3temp := Cfg.Section("s3-temp-image-store") - S3TempImageStoreBucketUrl = s3temp.Key("bucket_url").String() - S3TempImageStoreAccessKey = s3temp.Key("access_key").String() - S3TempImageStoreSecretKey = s3temp.Key("secret_key").String() + imageUploadingSection := Cfg.Section("external_image_storage") + ImageUploadProvider = imageUploadingSection.Key("provider").MustString("internal") return nil } From cb6fd4ca780e4efcef4a1534955e9c1c0ca8c4ee Mon Sep 17 00:00:00 2001 From: bergquist Date: Thu, 11 Aug 2016 16:55:08 +0200 Subject: [PATCH 2/4] test(alerting): fixes broken unit test --- pkg/services/alerting/rule_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/services/alerting/rule_test.go b/pkg/services/alerting/rule_test.go index 41c2f5ec6ce..91b31d6d07f 100644 --- a/pkg/services/alerting/rule_test.go +++ b/pkg/services/alerting/rule_test.go @@ -75,7 +75,7 @@ func TestAlertRuleModel(t *testing.T) { alertRule, err := NewRuleFromDBAlert(alert) So(err, ShouldBeNil) - So(alertRule.Conditions, ShouldHaveLength, 1) + So(len(alertRule.Conditions), ShouldEqual, 1) Convey("Can read notifications", func() { So(len(alertRule.Notifications), ShouldEqual, 2) From f07b2ac4463aff5525a3b69678dbd4bd4fb3377f Mon Sep 17 00:00:00 2001 From: bergquist Date: Thu, 11 Aug 2016 17:00:09 +0200 Subject: [PATCH 3/4] fix(metrics): hide none existing metrics settings --- pkg/metrics/graphite.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/metrics/graphite.go b/pkg/metrics/graphite.go index 2b3da3e490c..20b985e22ed 100644 --- a/pkg/metrics/graphite.go +++ b/pkg/metrics/graphite.go @@ -21,7 +21,7 @@ type GraphitePublisher struct { func CreateGraphitePublisher() (*GraphitePublisher, error) { graphiteSection, err := setting.Cfg.GetSection("metrics.graphite") if err != nil { - return nil, err + return nil, nil } publisher := &GraphitePublisher{} From 937726499f0a771d2744342152c7bccca5f711e4 Mon Sep 17 00:00:00 2001 From: bergquist Date: Thu, 11 Aug 2016 21:12:39 +0200 Subject: [PATCH 4/4] feat(alerting): add global usage metrics for alerting closes #5786 --- pkg/metrics/metrics.go | 59 ++++++++++++++-------- pkg/services/alerting/eval_handler.go | 7 ++- pkg/services/alerting/notifier.go | 1 + pkg/services/alerting/notifiers/email.go | 2 + pkg/services/alerting/notifiers/slack.go | 2 + pkg/services/alerting/notifiers/webhook.go | 2 + pkg/services/alerting/reader.go | 2 + pkg/services/alerting/result_handler.go | 15 ++++++ 8 files changed, 66 insertions(+), 24 deletions(-) diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go index 9982827d858..f084a955d57 100644 --- a/pkg/metrics/metrics.go +++ b/pkg/metrics/metrics.go @@ -9,29 +9,38 @@ func init() { } var ( - M_Instance_Start Counter - M_Page_Status_200 Counter - M_Page_Status_500 Counter - M_Page_Status_404 Counter - M_Api_Status_500 Counter - M_Api_Status_404 Counter - M_Api_User_SignUpStarted Counter - M_Api_User_SignUpCompleted Counter - M_Api_User_SignUpInvite Counter - M_Api_Dashboard_Save Timer - M_Api_Dashboard_Get Timer - M_Api_Dashboard_Search Timer - M_Api_Admin_User_Create Counter - M_Api_Login_Post Counter - M_Api_Login_OAuth Counter - M_Api_Org_Create Counter - M_Api_Dashboard_Snapshot_Create Counter - M_Api_Dashboard_Snapshot_External Counter - M_Api_Dashboard_Snapshot_Get Counter - M_Models_Dashboard_Insert Counter + M_Instance_Start Counter + M_Page_Status_200 Counter + M_Page_Status_500 Counter + M_Page_Status_404 Counter + M_Api_Status_500 Counter + M_Api_Status_404 Counter + M_Api_User_SignUpStarted Counter + M_Api_User_SignUpCompleted Counter + M_Api_User_SignUpInvite Counter + M_Api_Dashboard_Save Timer + M_Api_Dashboard_Get Timer + M_Api_Dashboard_Search Timer + M_Api_Admin_User_Create Counter + M_Api_Login_Post Counter + M_Api_Login_OAuth Counter + M_Api_Org_Create Counter + M_Api_Dashboard_Snapshot_Create Counter + M_Api_Dashboard_Snapshot_External Counter + M_Api_Dashboard_Snapshot_Get Counter + M_Models_Dashboard_Insert Counter + M_Alerting_Result_Critical Counter + M_Alerting_Result_Warning Counter + M_Alerting_Result_Info Counter + M_Alerting_Result_Ok Counter + M_Alerting_Active_Alerts Counter + M_Alerting_Notification_Sent_Slack Counter + M_Alerting_Notification_Sent_Email Counter + M_Alerting_Notification_Sent_Webhook Counter // Timers M_DataSource_ProxyReq_Timer Timer + M_Alerting_Exeuction_Time Timer ) func initMetricVars(settings *MetricSettings) { @@ -66,6 +75,16 @@ func initMetricVars(settings *MetricSettings) { M_Models_Dashboard_Insert = RegCounter("models.dashboard.insert") + M_Alerting_Result_Critical = RegCounter("alerting.result", "severity", "critical") + M_Alerting_Result_Warning = RegCounter("alerting.result", "severity", "warning") + M_Alerting_Result_Info = RegCounter("alerting.result", "severity", "info") + M_Alerting_Result_Ok = RegCounter("alerting.result", "severity", "ok") + M_Alerting_Active_Alerts = RegCounter("alerting.active_alerts") + M_Alerting_Notification_Sent_Slack = RegCounter("alerting.notifcations_sent", "type", "slack") + M_Alerting_Notification_Sent_Email = RegCounter("alerting.notifcations_sent", "type", "email") + M_Alerting_Notification_Sent_Webhook = RegCounter("alerting.notifcations_sent", "type", "webhook") + // Timers M_DataSource_ProxyReq_Timer = RegTimer("api.dataproxy.request.all") + M_Alerting_Exeuction_Time = RegTimer("alerting.execution_time") } diff --git a/pkg/services/alerting/eval_handler.go b/pkg/services/alerting/eval_handler.go index ae8a3ba2c51..3abcd978064 100644 --- a/pkg/services/alerting/eval_handler.go +++ b/pkg/services/alerting/eval_handler.go @@ -5,10 +5,7 @@ import ( "time" "github.com/grafana/grafana/pkg/log" -) - -var ( - descriptionFmt = "Actual value: %1.2f for %s. " + "github.com/grafana/grafana/pkg/metrics" ) type DefaultEvalHandler struct { @@ -55,5 +52,7 @@ func (e *DefaultEvalHandler) eval(context *EvalContext) { } context.EndTime = time.Now() + elapsedTime := context.EndTime.Sub(context.StartTime) + metrics.M_Alerting_Exeuction_Time.Update(elapsedTime) context.DoneChan <- true } diff --git a/pkg/services/alerting/notifier.go b/pkg/services/alerting/notifier.go index c345594de2c..826aede2d11 100644 --- a/pkg/services/alerting/notifier.go +++ b/pkg/services/alerting/notifier.go @@ -48,6 +48,7 @@ func (n *RootNotifier) Notify(context *EvalContext) { for _, notifier := range notifiers { n.log.Info("Sending notification", "firing", context.Firing, "type", notifier.GetType()) + go notifier.Notify(context) } } diff --git a/pkg/services/alerting/notifiers/email.go b/pkg/services/alerting/notifiers/email.go index 74b9c636a19..546c23c3d31 100644 --- a/pkg/services/alerting/notifiers/email.go +++ b/pkg/services/alerting/notifiers/email.go @@ -5,6 +5,7 @@ import ( "github.com/grafana/grafana/pkg/bus" "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" ) @@ -38,6 +39,7 @@ func NewEmailNotifier(model *m.AlertNotification) (alerting.Notifier, error) { func (this *EmailNotifier) Notify(context *alerting.EvalContext) { this.log.Info("Sending alert notification to", "addresses", this.Addresses) + metrics.M_Alerting_Notification_Sent_Email.Inc(1) ruleUrl, err := context.GetRuleUrl() if err != nil { diff --git a/pkg/services/alerting/notifiers/slack.go b/pkg/services/alerting/notifiers/slack.go index 0bc643212bd..e2c479b4425 100644 --- a/pkg/services/alerting/notifiers/slack.go +++ b/pkg/services/alerting/notifiers/slack.go @@ -6,6 +6,7 @@ import ( "github.com/grafana/grafana/pkg/bus" "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" ) @@ -38,6 +39,7 @@ type SlackNotifier struct { func (this *SlackNotifier) Notify(context *alerting.EvalContext) { this.log.Info("Executing slack notification", "ruleId", context.Rule.Id, "notification", this.Name) + metrics.M_Alerting_Notification_Sent_Slack.Inc(1) ruleUrl, err := context.GetRuleUrl() if err != nil { diff --git a/pkg/services/alerting/notifiers/webhook.go b/pkg/services/alerting/notifiers/webhook.go index fb475868f88..7da2ccfef30 100644 --- a/pkg/services/alerting/notifiers/webhook.go +++ b/pkg/services/alerting/notifiers/webhook.go @@ -4,6 +4,7 @@ import ( "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" ) @@ -40,6 +41,7 @@ type WebhookNotifier struct { func (this *WebhookNotifier) Notify(context *alerting.EvalContext) { this.log.Info("Sending webhook") + metrics.M_Alerting_Notification_Sent_Webhook.Inc(1) bodyJSON := simplejson.New() bodyJSON.Set("title", context.GetNotificationTitle()) diff --git a/pkg/services/alerting/reader.go b/pkg/services/alerting/reader.go index c15d8960621..68e7002be1a 100644 --- a/pkg/services/alerting/reader.go +++ b/pkg/services/alerting/reader.go @@ -6,6 +6,7 @@ import ( "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/metrics" m "github.com/grafana/grafana/pkg/models" ) @@ -58,6 +59,7 @@ func (arr *DefaultRuleReader) Fetch() []*Rule { } } + metrics.M_Alerting_Active_Alerts.Inc(int64(len(res))) return res } diff --git a/pkg/services/alerting/result_handler.go b/pkg/services/alerting/result_handler.go index af329e1545b..eeb4f57c1ec 100644 --- a/pkg/services/alerting/result_handler.go +++ b/pkg/services/alerting/result_handler.go @@ -5,6 +5,7 @@ import ( "github.com/grafana/grafana/pkg/bus" "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/annotations" ) @@ -37,6 +38,7 @@ func (handler *DefaultResultHandler) Handle(ctx *EvalContext) { ctx.Rule.State = m.AlertStateOK } + countSeverity(ctx.Rule.Severity) if ctx.Rule.State != oldState { handler.log.Info("New state change", "alertId", ctx.Rule.Id, "newState", ctx.Rule.State, "oldState", oldState) @@ -69,3 +71,16 @@ func (handler *DefaultResultHandler) Handle(ctx *EvalContext) { handler.notifier.Notify(ctx) } } + +func countSeverity(state m.AlertSeverityType) { + switch state { + case m.AlertSeverityOK: + metrics.M_Alerting_Result_Ok.Inc(1) + case m.AlertSeverityInfo: + metrics.M_Alerting_Result_Info.Inc(1) + case m.AlertSeverityWarning: + metrics.M_Alerting_Result_Warning.Inc(1) + case m.AlertSeverityCritical: + metrics.M_Alerting_Result_Critical.Inc(1) + } +}