mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat(alerting): removed severity
This commit is contained in:
parent
6375418d8c
commit
b0c7e61ef8
@ -49,7 +49,6 @@ func GetAlerts(c *middleware.Context) Response {
|
|||||||
Name: alert.Name,
|
Name: alert.Name,
|
||||||
Message: alert.Message,
|
Message: alert.Message,
|
||||||
State: alert.State,
|
State: alert.State,
|
||||||
Severity: alert.Severity,
|
|
||||||
EvalDate: alert.EvalDate,
|
EvalDate: alert.EvalDate,
|
||||||
NewStateDate: alert.NewStateDate,
|
NewStateDate: alert.NewStateDate,
|
||||||
ExecutionError: alert.ExecutionError,
|
ExecutionError: alert.ExecutionError,
|
||||||
@ -219,7 +218,6 @@ func NotificationTest(c *middleware.Context, dto dtos.NotificationTestCommand) R
|
|||||||
cmd := &alerting.NotificationTestCommand{
|
cmd := &alerting.NotificationTestCommand{
|
||||||
Name: dto.Name,
|
Name: dto.Name,
|
||||||
Type: dto.Type,
|
Type: dto.Type,
|
||||||
Severity: dto.Severity,
|
|
||||||
Settings: dto.Settings,
|
Settings: dto.Settings,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,17 +8,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type AlertRule struct {
|
type AlertRule struct {
|
||||||
Id int64 `json:"id"`
|
Id int64 `json:"id"`
|
||||||
DashboardId int64 `json:"dashboardId"`
|
DashboardId int64 `json:"dashboardId"`
|
||||||
PanelId int64 `json:"panelId"`
|
PanelId int64 `json:"panelId"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
State m.AlertStateType `json:"state"`
|
State m.AlertStateType `json:"state"`
|
||||||
Severity m.AlertSeverityType `json:"severity"`
|
NewStateDate time.Time `json:"newStateDate"`
|
||||||
NewStateDate time.Time `json:"newStateDate"`
|
EvalDate time.Time `json:"evalDate"`
|
||||||
EvalDate time.Time `json:"evalDate"`
|
ExecutionError string `json:"executionError"`
|
||||||
ExecutionError string `json:"executionError"`
|
DashbboardUri string `json:"dashboardUri"`
|
||||||
DashbboardUri string `json:"dashboardUri"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type AlertNotification struct {
|
type AlertNotification struct {
|
||||||
@ -58,5 +57,4 @@ type NotificationTestCommand struct {
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Settings *simplejson.Json `json:"settings"`
|
Settings *simplejson.Json `json:"settings"`
|
||||||
Severity string `json:"severity"`
|
|
||||||
}
|
}
|
||||||
|
@ -9,43 +9,42 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
M_Instance_Start Counter
|
M_Instance_Start Counter
|
||||||
M_Page_Status_200 Counter
|
M_Page_Status_200 Counter
|
||||||
M_Page_Status_500 Counter
|
M_Page_Status_500 Counter
|
||||||
M_Page_Status_404 Counter
|
M_Page_Status_404 Counter
|
||||||
M_Page_Status_Unknown Counter
|
M_Page_Status_Unknown Counter
|
||||||
M_Api_Status_200 Counter
|
M_Api_Status_200 Counter
|
||||||
M_Api_Status_404 Counter
|
M_Api_Status_404 Counter
|
||||||
M_Api_Status_500 Counter
|
M_Api_Status_500 Counter
|
||||||
M_Api_Status_Unknown Counter
|
M_Api_Status_Unknown Counter
|
||||||
M_Proxy_Status_200 Counter
|
M_Proxy_Status_200 Counter
|
||||||
M_Proxy_Status_404 Counter
|
M_Proxy_Status_404 Counter
|
||||||
M_Proxy_Status_500 Counter
|
M_Proxy_Status_500 Counter
|
||||||
M_Proxy_Status_Unknown Counter
|
M_Proxy_Status_Unknown Counter
|
||||||
M_Api_User_SignUpStarted Counter
|
M_Api_User_SignUpStarted Counter
|
||||||
M_Api_User_SignUpCompleted Counter
|
M_Api_User_SignUpCompleted Counter
|
||||||
M_Api_User_SignUpInvite Counter
|
M_Api_User_SignUpInvite Counter
|
||||||
M_Api_Dashboard_Save Timer
|
M_Api_Dashboard_Save Timer
|
||||||
M_Api_Dashboard_Get Timer
|
M_Api_Dashboard_Get Timer
|
||||||
M_Api_Dashboard_Search Timer
|
M_Api_Dashboard_Search Timer
|
||||||
M_Api_Admin_User_Create Counter
|
M_Api_Admin_User_Create Counter
|
||||||
M_Api_Login_Post Counter
|
M_Api_Login_Post Counter
|
||||||
M_Api_Login_OAuth Counter
|
M_Api_Login_OAuth Counter
|
||||||
M_Api_Org_Create Counter
|
M_Api_Org_Create Counter
|
||||||
M_Api_Dashboard_Snapshot_Create Counter
|
M_Api_Dashboard_Snapshot_Create Counter
|
||||||
M_Api_Dashboard_Snapshot_External Counter
|
M_Api_Dashboard_Snapshot_External Counter
|
||||||
M_Api_Dashboard_Snapshot_Get Counter
|
M_Api_Dashboard_Snapshot_Get Counter
|
||||||
M_Models_Dashboard_Insert Counter
|
M_Models_Dashboard_Insert Counter
|
||||||
M_Alerting_Result_State_Critical Counter
|
M_Alerting_Result_State_Alerting Counter
|
||||||
M_Alerting_Result_State_Warning Counter
|
M_Alerting_Result_State_Ok Counter
|
||||||
M_Alerting_Result_State_Ok Counter
|
M_Alerting_Result_State_Paused Counter
|
||||||
M_Alerting_Result_State_Paused Counter
|
M_Alerting_Result_State_NoData Counter
|
||||||
M_Alerting_Result_State_Unknown Counter
|
M_Alerting_Result_State_ExecError Counter
|
||||||
M_Alerting_Result_State_ExecutionError Counter
|
M_Alerting_Active_Alerts Counter
|
||||||
M_Alerting_Active_Alerts Counter
|
M_Alerting_Notification_Sent_Slack Counter
|
||||||
M_Alerting_Notification_Sent_Slack Counter
|
M_Alerting_Notification_Sent_Email Counter
|
||||||
M_Alerting_Notification_Sent_Email Counter
|
M_Alerting_Notification_Sent_Webhook Counter
|
||||||
M_Alerting_Notification_Sent_Webhook Counter
|
|
||||||
|
|
||||||
// Timers
|
// Timers
|
||||||
M_DataSource_ProxyReq_Timer Timer
|
M_DataSource_ProxyReq_Timer Timer
|
||||||
@ -92,12 +91,11 @@ func initMetricVars(settings *MetricSettings) {
|
|||||||
|
|
||||||
M_Models_Dashboard_Insert = RegCounter("models.dashboard.insert")
|
M_Models_Dashboard_Insert = RegCounter("models.dashboard.insert")
|
||||||
|
|
||||||
M_Alerting_Result_State_Critical = RegCounter("alerting.result", "state", "critical")
|
M_Alerting_Result_State_Alerting = RegCounter("alerting.result", "state", "alerting")
|
||||||
M_Alerting_Result_State_Warning = RegCounter("alerting.result", "state", "warning")
|
|
||||||
M_Alerting_Result_State_Ok = RegCounter("alerting.result", "state", "ok")
|
M_Alerting_Result_State_Ok = RegCounter("alerting.result", "state", "ok")
|
||||||
M_Alerting_Result_State_Paused = RegCounter("alerting.result", "state", "paused")
|
M_Alerting_Result_State_Paused = RegCounter("alerting.result", "state", "paused")
|
||||||
M_Alerting_Result_State_Unknown = RegCounter("alerting.result", "state", "unknown")
|
M_Alerting_Result_State_NoData = RegCounter("alerting.result", "state", "no_data")
|
||||||
M_Alerting_Result_State_ExecutionError = RegCounter("alerting.result", "state", "execution_error")
|
M_Alerting_Result_State_ExecError = RegCounter("alerting.result", "state", "exec_error")
|
||||||
|
|
||||||
M_Alerting_Active_Alerts = RegCounter("alerting.active_alerts")
|
M_Alerting_Active_Alerts = RegCounter("alerting.active_alerts")
|
||||||
M_Alerting_Notification_Sent_Slack = RegCounter("alerting.notifications_sent", "type", "slack")
|
M_Alerting_Notification_Sent_Slack = RegCounter("alerting.notifications_sent", "type", "slack")
|
||||||
|
@ -10,27 +10,15 @@ type AlertStateType string
|
|||||||
type AlertSeverityType string
|
type AlertSeverityType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AlertStateUnknown AlertStateType = "unknown"
|
AlertStateNoData AlertStateType = "no_data"
|
||||||
AlertStateExeuctionError AlertStateType = "execution_error"
|
AlertStateExecError AlertStateType = "execution_error"
|
||||||
AlertStatePaused AlertStateType = "paused"
|
AlertStatePaused AlertStateType = "paused"
|
||||||
AlertStateCritical AlertStateType = "critical"
|
AlertStateAlerting AlertStateType = "alerting"
|
||||||
AlertStateWarning AlertStateType = "warning"
|
AlertStateOK AlertStateType = "ok"
|
||||||
AlertStateOK AlertStateType = "ok"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s AlertStateType) IsValid() bool {
|
func (s AlertStateType) IsValid() bool {
|
||||||
return s == AlertStateOK || s == AlertStateUnknown || s == AlertStateExeuctionError || s == AlertStatePaused || s == AlertStateCritical || s == AlertStateWarning
|
return s == AlertStateOK || s == AlertStateNoData || s == AlertStateExecError || s == AlertStatePaused
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
AlertSeverityCritical AlertSeverityType = "critical"
|
|
||||||
AlertSeverityWarning AlertSeverityType = "warning"
|
|
||||||
AlertSeverityInfo AlertSeverityType = "info"
|
|
||||||
AlertSeverityOK AlertSeverityType = "ok"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s AlertSeverityType) IsValid() bool {
|
|
||||||
return s == AlertSeverityCritical || s == AlertSeverityInfo || s == AlertSeverityWarning
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Alert struct {
|
type Alert struct {
|
||||||
@ -41,7 +29,7 @@ type Alert struct {
|
|||||||
PanelId int64
|
PanelId int64
|
||||||
Name string
|
Name string
|
||||||
Message string
|
Message string
|
||||||
Severity AlertSeverityType
|
Severity string
|
||||||
State AlertStateType
|
State AlertStateType
|
||||||
Handler int64
|
Handler int64
|
||||||
Silenced bool
|
Silenced bool
|
||||||
|
@ -43,25 +43,20 @@ func (c *EvalContext) GetStateModel() *StateDescription {
|
|||||||
Color: "#36a64f",
|
Color: "#36a64f",
|
||||||
Text: "OK",
|
Text: "OK",
|
||||||
}
|
}
|
||||||
case m.AlertStateUnknown:
|
case m.AlertStateNoData:
|
||||||
return &StateDescription{
|
return &StateDescription{
|
||||||
Color: "#888888",
|
Color: "#888888",
|
||||||
Text: "UNKNOWN",
|
Text: "No Data",
|
||||||
}
|
}
|
||||||
case m.AlertStateExeuctionError:
|
case m.AlertStateExecError:
|
||||||
return &StateDescription{
|
return &StateDescription{
|
||||||
Color: "#000",
|
Color: "#000",
|
||||||
Text: "EXECUTION_ERROR",
|
Text: "Execution Error",
|
||||||
}
|
}
|
||||||
case m.AlertStateWarning:
|
case m.AlertStateAlerting:
|
||||||
return &StateDescription{
|
|
||||||
Color: "#fd821b",
|
|
||||||
Text: "WARNING",
|
|
||||||
}
|
|
||||||
case m.AlertStateCritical:
|
|
||||||
return &StateDescription{
|
return &StateDescription{
|
||||||
Color: "#D63232",
|
Color: "#D63232",
|
||||||
Text: "CRITICAL",
|
Text: "Alerting",
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
panic("Unknown rule state " + c.Rule.State)
|
panic("Unknown rule state " + c.Rule.State)
|
||||||
|
@ -88,14 +88,9 @@ func (e *DashAlertExtractor) GetAlerts() ([]*m.Alert, error) {
|
|||||||
Name: jsonAlert.Get("name").MustString(),
|
Name: jsonAlert.Get("name").MustString(),
|
||||||
Handler: jsonAlert.Get("handler").MustInt64(),
|
Handler: jsonAlert.Get("handler").MustInt64(),
|
||||||
Message: jsonAlert.Get("message").MustString(),
|
Message: jsonAlert.Get("message").MustString(),
|
||||||
Severity: m.AlertSeverityType(jsonAlert.Get("severity").MustString()),
|
|
||||||
Frequency: getTimeDurationStringToSeconds(jsonAlert.Get("frequency").MustString()),
|
Frequency: getTimeDurationStringToSeconds(jsonAlert.Get("frequency").MustString()),
|
||||||
}
|
}
|
||||||
|
|
||||||
if !alert.Severity.IsValid() {
|
|
||||||
return nil, ValidationError{Reason: "Invalid alert Severity"}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, condition := range jsonAlert.Get("conditions").MustArray() {
|
for _, condition := range jsonAlert.Get("conditions").MustArray() {
|
||||||
jsonCondition := simplejson.NewFromAny(condition)
|
jsonCondition := simplejson.NewFromAny(condition)
|
||||||
|
|
||||||
|
@ -2,8 +2,6 @@ package alerting
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/models"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type EvalHandler interface {
|
type EvalHandler interface {
|
||||||
@ -19,7 +17,7 @@ type Notifier interface {
|
|||||||
Notify(alertResult *EvalContext)
|
Notify(alertResult *EvalContext)
|
||||||
GetType() string
|
GetType() string
|
||||||
NeedsImage() bool
|
NeedsImage() bool
|
||||||
MatchSeverity(result models.AlertSeverityType) bool
|
PassesFilter(rule *Rule) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Condition interface {
|
type Condition interface {
|
||||||
|
@ -28,7 +28,7 @@ func (n *RootNotifier) NeedsImage() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *RootNotifier) MatchSeverity(result m.AlertSeverityType) bool {
|
func (n *RootNotifier) PassesFilter(rule *Rule) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,7 +130,7 @@ func shouldUseNotification(notifier Notifier, context *EvalContext) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return notifier.MatchSeverity(context.Rule.Severity)
|
return notifier.PassesFilter(context.Rule)
|
||||||
}
|
}
|
||||||
|
|
||||||
type NotifierFactory func(notification *m.AlertNotification) (Notifier, error)
|
type NotifierFactory func(notification *m.AlertNotification) (Notifier, error)
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ func (fn *FakeNotifier) NeedsImage() bool {
|
|||||||
|
|
||||||
func (fn *FakeNotifier) Notify(alertResult *EvalContext) {}
|
func (fn *FakeNotifier) Notify(alertResult *EvalContext) {}
|
||||||
|
|
||||||
func (fn *FakeNotifier) MatchSeverity(result models.AlertSeverityType) bool {
|
func (fn *FakeNotifier) PassesFilter(rule *Rule) bool {
|
||||||
return fn.FakeMatchResult
|
return fn.FakeMatchResult
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +35,7 @@ func TestAlertNotificationExtraction(t *testing.T) {
|
|||||||
ctx := &EvalContext{
|
ctx := &EvalContext{
|
||||||
Firing: false,
|
Firing: false,
|
||||||
Rule: &Rule{
|
Rule: &Rule{
|
||||||
Severity: models.AlertSeverityCritical,
|
State: m.AlertStateAlerting,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
notifier := &FakeNotifier{FakeMatchResult: false}
|
notifier := &FakeNotifier{FakeMatchResult: false}
|
||||||
@ -42,12 +43,12 @@ func TestAlertNotificationExtraction(t *testing.T) {
|
|||||||
So(shouldUseNotification(notifier, ctx), ShouldBeTrue)
|
So(shouldUseNotification(notifier, ctx), ShouldBeTrue)
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("exeuction error cannot be ignored", func() {
|
Convey("execution error cannot be ignored", func() {
|
||||||
ctx := &EvalContext{
|
ctx := &EvalContext{
|
||||||
Firing: true,
|
Firing: true,
|
||||||
Error: fmt.Errorf("I used to be a programmer just like you"),
|
Error: fmt.Errorf("I used to be a programmer just like you"),
|
||||||
Rule: &Rule{
|
Rule: &Rule{
|
||||||
Severity: models.AlertSeverityCritical,
|
State: m.AlertStateOK,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
notifier := &FakeNotifier{FakeMatchResult: false}
|
notifier := &FakeNotifier{FakeMatchResult: false}
|
||||||
@ -59,7 +60,7 @@ func TestAlertNotificationExtraction(t *testing.T) {
|
|||||||
ctx := &EvalContext{
|
ctx := &EvalContext{
|
||||||
Firing: true,
|
Firing: true,
|
||||||
Rule: &Rule{
|
Rule: &Rule{
|
||||||
Severity: models.AlertSeverityCritical,
|
State: models.AlertStateAlerting,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
notifier := &FakeNotifier{FakeMatchResult: true}
|
notifier := &FakeNotifier{FakeMatchResult: true}
|
||||||
@ -70,9 +71,7 @@ func TestAlertNotificationExtraction(t *testing.T) {
|
|||||||
Convey("firing alert that dont match", func() {
|
Convey("firing alert that dont match", func() {
|
||||||
ctx := &EvalContext{
|
ctx := &EvalContext{
|
||||||
Firing: true,
|
Firing: true,
|
||||||
Rule: &Rule{
|
Rule: &Rule{State: m.AlertStateOK},
|
||||||
Severity: models.AlertSeverityCritical,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
notifier := &FakeNotifier{FakeMatchResult: false}
|
notifier := &FakeNotifier{FakeMatchResult: false}
|
||||||
|
|
||||||
|
@ -2,33 +2,21 @@ package notifiers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/services/alerting"
|
||||||
)
|
)
|
||||||
|
|
||||||
type NotifierBase struct {
|
type NotifierBase struct {
|
||||||
Name string
|
Name string
|
||||||
Type string
|
Type string
|
||||||
SeverityFilter models.AlertSeverityType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNotifierBase(name, notifierType string, model *simplejson.Json) NotifierBase {
|
func NewNotifierBase(name, notifierType string, model *simplejson.Json) NotifierBase {
|
||||||
base := NotifierBase{Name: name, Type: notifierType}
|
base := NotifierBase{Name: name, Type: notifierType}
|
||||||
|
|
||||||
severityFilter := models.AlertSeverityType(model.Get("severityFilter").MustString(""))
|
|
||||||
|
|
||||||
if severityFilter == models.AlertSeverityCritical || severityFilter == models.AlertSeverityWarning {
|
|
||||||
base.SeverityFilter = severityFilter
|
|
||||||
}
|
|
||||||
|
|
||||||
return base
|
return base
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NotifierBase) MatchSeverity(result models.AlertSeverityType) bool {
|
func (n *NotifierBase) PassesFilter(rule *alerting.Rule) bool {
|
||||||
if !n.SeverityFilter.IsValid() {
|
return true
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return n.SeverityFilter == result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NotifierBase) GetType() string {
|
func (n *NotifierBase) GetType() string {
|
||||||
|
@ -3,34 +3,32 @@ package notifiers
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
|
||||||
m "github.com/grafana/grafana/pkg/models"
|
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBaseNotifier(t *testing.T) {
|
func TestBaseNotifier(t *testing.T) {
|
||||||
Convey("Parsing base notification severity", t, func() {
|
// Convey("Parsing base notification state", t, func() {
|
||||||
|
//
|
||||||
Convey("matches", func() {
|
// Convey("matches", func() {
|
||||||
json := `
|
// json := `
|
||||||
{
|
// {
|
||||||
"severityFilter": "critical"
|
// "states": "critical"
|
||||||
}`
|
// }`
|
||||||
|
//
|
||||||
settingsJSON, _ := simplejson.NewJson([]byte(json))
|
// settingsJSON, _ := simplejson.NewJson([]byte(json))
|
||||||
not := NewNotifierBase("ops", "email", settingsJSON)
|
// not := NewNotifierBase("ops", "email", settingsJSON)
|
||||||
So(not.MatchSeverity(m.AlertSeverityCritical), ShouldBeTrue)
|
// So(not.MatchSeverity(m.AlertSeverityCritical), ShouldBeTrue)
|
||||||
})
|
// })
|
||||||
|
//
|
||||||
Convey("does not match", func() {
|
// Convey("does not match", func() {
|
||||||
json := `
|
// json := `
|
||||||
{
|
// {
|
||||||
"severityFilter": "critical"
|
// "severityFilter": "critical"
|
||||||
}`
|
// }`
|
||||||
|
//
|
||||||
settingsJSON, _ := simplejson.NewJson([]byte(json))
|
// settingsJSON, _ := simplejson.NewJson([]byte(json))
|
||||||
not := NewNotifierBase("ops", "email", settingsJSON)
|
// not := NewNotifierBase("ops", "email", settingsJSON)
|
||||||
So(not.MatchSeverity(m.AlertSeverityWarning), ShouldBeFalse)
|
// So(not.MatchSeverity(m.AlertSeverityWarning), ShouldBeFalse)
|
||||||
})
|
// })
|
||||||
})
|
// })
|
||||||
}
|
}
|
||||||
|
@ -47,16 +47,15 @@ func (this *EmailNotifier) Notify(context *alerting.EvalContext) {
|
|||||||
|
|
||||||
cmd := &m.SendEmailCommand{
|
cmd := &m.SendEmailCommand{
|
||||||
Data: map[string]interface{}{
|
Data: map[string]interface{}{
|
||||||
"Title": context.GetNotificationTitle(),
|
"Title": context.GetNotificationTitle(),
|
||||||
"State": context.Rule.State,
|
"State": context.Rule.State,
|
||||||
"Name": context.Rule.Name,
|
"Name": context.Rule.Name,
|
||||||
"Severity": context.Rule.Severity,
|
"StateModel": context.GetStateModel(),
|
||||||
"SeverityColor": context.GetStateModel().Color,
|
"Message": context.Rule.Message,
|
||||||
"Message": context.Rule.Message,
|
"RuleUrl": ruleUrl,
|
||||||
"RuleUrl": ruleUrl,
|
"ImageLink": context.ImagePublicUrl,
|
||||||
"ImageLink": context.ImagePublicUrl,
|
"AlertPageUrl": setting.AppUrl + "alerting",
|
||||||
"AlertPageUrl": setting.AppUrl + "alerting",
|
"EvalMatches": context.EvalMatches,
|
||||||
"EvalMatches": context.EvalMatches,
|
|
||||||
},
|
},
|
||||||
To: this.Addresses,
|
To: this.Addresses,
|
||||||
Template: "alert_notification.html",
|
Template: "alert_notification.html",
|
||||||
|
@ -45,7 +45,6 @@ func (this *WebhookNotifier) Notify(context *alerting.EvalContext) {
|
|||||||
bodyJSON.Set("ruleId", context.Rule.Id)
|
bodyJSON.Set("ruleId", context.Rule.Id)
|
||||||
bodyJSON.Set("ruleName", context.Rule.Name)
|
bodyJSON.Set("ruleName", context.Rule.Name)
|
||||||
bodyJSON.Set("state", context.Rule.State)
|
bodyJSON.Set("state", context.Rule.State)
|
||||||
bodyJSON.Set("severity", context.Rule.Severity)
|
|
||||||
bodyJSON.Set("evalMatches", context.EvalMatches)
|
bodyJSON.Set("evalMatches", context.EvalMatches)
|
||||||
|
|
||||||
ruleUrl, err := context.GetRuleUrl()
|
ruleUrl, err := context.GetRuleUrl()
|
||||||
|
@ -34,11 +34,11 @@ func (handler *DefaultResultHandler) Handle(ctx *EvalContext) {
|
|||||||
annotationData := simplejson.New()
|
annotationData := simplejson.New()
|
||||||
if ctx.Error != nil {
|
if ctx.Error != nil {
|
||||||
handler.log.Error("Alert Rule Result Error", "ruleId", ctx.Rule.Id, "error", ctx.Error)
|
handler.log.Error("Alert Rule Result Error", "ruleId", ctx.Rule.Id, "error", ctx.Error)
|
||||||
ctx.Rule.State = m.AlertStateExeuctionError
|
ctx.Rule.State = m.AlertStateExecError
|
||||||
exeuctionError = ctx.Error.Error()
|
exeuctionError = ctx.Error.Error()
|
||||||
annotationData.Set("errorMessage", exeuctionError)
|
annotationData.Set("errorMessage", exeuctionError)
|
||||||
} else if ctx.Firing {
|
} else if ctx.Firing {
|
||||||
ctx.Rule.State = m.AlertStateType(ctx.Rule.Severity)
|
ctx.Rule.State = m.AlertStateAlerting
|
||||||
annotationData = simplejson.NewFromAny(ctx.EvalMatches)
|
annotationData = simplejson.NewFromAny(ctx.EvalMatches)
|
||||||
} else {
|
} else {
|
||||||
// handle no data case
|
// handle no data case
|
||||||
@ -90,17 +90,15 @@ func (handler *DefaultResultHandler) Handle(ctx *EvalContext) {
|
|||||||
|
|
||||||
func countStateResult(state m.AlertStateType) {
|
func countStateResult(state m.AlertStateType) {
|
||||||
switch state {
|
switch state {
|
||||||
case m.AlertStateCritical:
|
case m.AlertStateAlerting:
|
||||||
metrics.M_Alerting_Result_State_Critical.Inc(1)
|
metrics.M_Alerting_Result_State_Alerting.Inc(1)
|
||||||
case m.AlertStateWarning:
|
|
||||||
metrics.M_Alerting_Result_State_Warning.Inc(1)
|
|
||||||
case m.AlertStateOK:
|
case m.AlertStateOK:
|
||||||
metrics.M_Alerting_Result_State_Ok.Inc(1)
|
metrics.M_Alerting_Result_State_Ok.Inc(1)
|
||||||
case m.AlertStatePaused:
|
case m.AlertStatePaused:
|
||||||
metrics.M_Alerting_Result_State_Paused.Inc(1)
|
metrics.M_Alerting_Result_State_Paused.Inc(1)
|
||||||
case m.AlertStateUnknown:
|
case m.AlertStateNoData:
|
||||||
metrics.M_Alerting_Result_State_Unknown.Inc(1)
|
metrics.M_Alerting_Result_State_NoData.Inc(1)
|
||||||
case m.AlertStateExeuctionError:
|
case m.AlertStateExecError:
|
||||||
metrics.M_Alerting_Result_State_ExecutionError.Inc(1)
|
metrics.M_Alerting_Result_State_ExecError.Inc(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ type Rule struct {
|
|||||||
Message string
|
Message string
|
||||||
NoDataState m.AlertStateType
|
NoDataState m.AlertStateType
|
||||||
State m.AlertStateType
|
State m.AlertStateType
|
||||||
Severity m.AlertSeverityType
|
|
||||||
Conditions []Condition
|
Conditions []Condition
|
||||||
Notifications []int64
|
Notifications []int64
|
||||||
}
|
}
|
||||||
@ -66,9 +65,8 @@ func NewRuleFromDBAlert(ruleDef *m.Alert) (*Rule, error) {
|
|||||||
model.Name = ruleDef.Name
|
model.Name = ruleDef.Name
|
||||||
model.Message = ruleDef.Message
|
model.Message = ruleDef.Message
|
||||||
model.Frequency = ruleDef.Frequency
|
model.Frequency = ruleDef.Frequency
|
||||||
model.Severity = ruleDef.Severity
|
|
||||||
model.State = ruleDef.State
|
model.State = ruleDef.State
|
||||||
model.NoDataState = m.AlertStateType(ruleDef.Settings.Get("noDataState").MustString("unknown"))
|
model.NoDataState = m.AlertStateType(ruleDef.Settings.Get("noDataState").MustString("no_data"))
|
||||||
|
|
||||||
for _, v := range ruleDef.Settings.Get("notifications").MustArray() {
|
for _, v := range ruleDef.Settings.Get("notifications").MustArray() {
|
||||||
jsonModel := simplejson.NewFromAny(v)
|
jsonModel := simplejson.NewFromAny(v)
|
||||||
|
@ -4,11 +4,11 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
"github.com/grafana/grafana/pkg/log"
|
"github.com/grafana/grafana/pkg/log"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
type NotificationTestCommand struct {
|
type NotificationTestCommand struct {
|
||||||
Severity string
|
State m.AlertStateType
|
||||||
Name string
|
Name string
|
||||||
Type string
|
Type string
|
||||||
Settings *simplejson.Json
|
Settings *simplejson.Json
|
||||||
@ -22,7 +22,7 @@ func init() {
|
|||||||
func handleNotificationTestCommand(cmd *NotificationTestCommand) error {
|
func handleNotificationTestCommand(cmd *NotificationTestCommand) error {
|
||||||
notifier := NewRootNotifier()
|
notifier := NewRootNotifier()
|
||||||
|
|
||||||
model := &models.AlertNotification{
|
model := &m.AlertNotification{
|
||||||
Name: cmd.Name,
|
Name: cmd.Name,
|
||||||
Type: cmd.Type,
|
Type: cmd.Type,
|
||||||
Settings: cmd.Settings,
|
Settings: cmd.Settings,
|
||||||
@ -35,23 +35,12 @@ func handleNotificationTestCommand(cmd *NotificationTestCommand) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
severity := models.AlertSeverityType(cmd.Severity)
|
notifier.sendNotifications([]Notifier{notifiers}, createTestEvalContext(cmd.State))
|
||||||
notifier.sendNotifications([]Notifier{notifiers}, createTestEvalContext(severity))
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTestEvalContext(severity models.AlertSeverityType) *EvalContext {
|
func createTestEvalContext(state m.AlertStateType) *EvalContext {
|
||||||
state := models.AlertStateOK
|
|
||||||
firing := false
|
|
||||||
if severity == models.AlertSeverityCritical {
|
|
||||||
state = models.AlertStateCritical
|
|
||||||
firing = true
|
|
||||||
}
|
|
||||||
if severity == models.AlertSeverityWarning {
|
|
||||||
state = models.AlertStateWarning
|
|
||||||
firing = true
|
|
||||||
}
|
|
||||||
|
|
||||||
testRule := &Rule{
|
testRule := &Rule{
|
||||||
DashboardId: 1,
|
DashboardId: 1,
|
||||||
@ -59,23 +48,22 @@ func createTestEvalContext(severity models.AlertSeverityType) *EvalContext {
|
|||||||
Name: "Test notification",
|
Name: "Test notification",
|
||||||
Message: "Someone is testing the alert notification within grafana.",
|
Message: "Someone is testing the alert notification within grafana.",
|
||||||
State: state,
|
State: state,
|
||||||
Severity: severity,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := NewEvalContext(testRule)
|
ctx := NewEvalContext(testRule)
|
||||||
ctx.ImagePublicUrl = "http://grafana.org/assets/img/blog/mixed_styles.png"
|
ctx.ImagePublicUrl = "http://grafana.org/assets/img/blog/mixed_styles.png"
|
||||||
|
|
||||||
ctx.IsTestRun = true
|
ctx.IsTestRun = true
|
||||||
ctx.Firing = firing
|
ctx.Firing = state == m.AlertStateAlerting
|
||||||
ctx.Error = nil
|
ctx.Error = nil
|
||||||
ctx.EvalMatches = evalMatchesBasedOnSeverity(severity)
|
ctx.EvalMatches = evalMatchesBasedOnState(state)
|
||||||
|
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
func evalMatchesBasedOnSeverity(severity models.AlertSeverityType) []*EvalMatch {
|
func evalMatchesBasedOnState(state m.AlertStateType) []*EvalMatch {
|
||||||
matches := make([]*EvalMatch, 0)
|
matches := make([]*EvalMatch, 0)
|
||||||
if severity == models.AlertSeverityOK {
|
if state == m.AlertStateOK {
|
||||||
return matches
|
return matches
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,7 +159,7 @@ func upsertAlerts(existingAlerts []*m.Alert, cmd *m.SaveAlertsCommand, sess *xor
|
|||||||
} else {
|
} else {
|
||||||
alert.Updated = time.Now()
|
alert.Updated = time.Now()
|
||||||
alert.Created = time.Now()
|
alert.Created = time.Now()
|
||||||
alert.State = m.AlertStateUnknown
|
alert.State = m.AlertStateNoData
|
||||||
alert.NewStateDate = time.Now()
|
alert.NewStateDate = time.Now()
|
||||||
|
|
||||||
_, err := sess.Insert(alert)
|
_, err := sess.Insert(alert)
|
||||||
|
@ -47,7 +47,7 @@ func TestAlertingDataAccess(t *testing.T) {
|
|||||||
So(err2, ShouldBeNil)
|
So(err2, ShouldBeNil)
|
||||||
So(alert.Name, ShouldEqual, "Alerting title")
|
So(alert.Name, ShouldEqual, "Alerting title")
|
||||||
So(alert.Message, ShouldEqual, "Alerting message")
|
So(alert.Message, ShouldEqual, "Alerting message")
|
||||||
So(alert.State, ShouldEqual, "unknown")
|
So(alert.State, ShouldEqual, "no_data")
|
||||||
So(alert.Frequency, ShouldEqual, 1)
|
So(alert.Frequency, ShouldEqual, 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ func TestAlertingDataAccess(t *testing.T) {
|
|||||||
So(query.Result[0].Name, ShouldEqual, "Name")
|
So(query.Result[0].Name, ShouldEqual, "Name")
|
||||||
|
|
||||||
Convey("Alert state should not be updated", func() {
|
Convey("Alert state should not be updated", func() {
|
||||||
So(query.Result[0].State, ShouldEqual, "unknown")
|
So(query.Result[0].State, ShouldEqual, "no_data")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -38,9 +38,8 @@ var reducerTypes = [
|
|||||||
|
|
||||||
var noDataModes = [
|
var noDataModes = [
|
||||||
{text: 'OK', value: 'ok'},
|
{text: 'OK', value: 'ok'},
|
||||||
{text: 'Critical', value: 'critical'},
|
{text: 'Alerting', value: 'alerting'},
|
||||||
{text: 'Warning', value: 'warning'},
|
{text: 'No Data', value: 'no_data'},
|
||||||
{text: 'Unknown', value: 'unknown'},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
function createReducerPart(model) {
|
function createReducerPart(model) {
|
||||||
@ -48,10 +47,6 @@ function createReducerPart(model) {
|
|||||||
return new QueryPart(model, def);
|
return new QueryPart(model, def);
|
||||||
}
|
}
|
||||||
|
|
||||||
var severityLevels = {
|
|
||||||
'critical': {text: 'Critical', iconClass: 'icon-gf icon-gf-critical', stateClass: 'alert-state-critical'},
|
|
||||||
'warning': {text: 'Warning', iconClass: 'icon-gf icon-gf-warning', stateClass: 'alert-state-warning'},
|
|
||||||
};
|
|
||||||
|
|
||||||
function getStateDisplayModel(state) {
|
function getStateDisplayModel(state) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
@ -62,23 +57,16 @@ function getStateDisplayModel(state) {
|
|||||||
stateClass: 'alert-state-ok'
|
stateClass: 'alert-state-ok'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case 'critical': {
|
case 'alerting': {
|
||||||
return {
|
return {
|
||||||
text: 'CRITICAL',
|
text: 'ALERTING',
|
||||||
iconClass: 'icon-gf icon-gf-critical',
|
iconClass: 'icon-gf icon-gf-critical',
|
||||||
stateClass: 'alert-state-critical'
|
stateClass: 'alert-state-critical'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case 'warning': {
|
case 'no_data': {
|
||||||
return {
|
return {
|
||||||
text: 'WARNING',
|
text: 'NO DATA',
|
||||||
iconClass: 'icon-gf icon-gf-warning',
|
|
||||||
stateClass: 'alert-state-warning'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
case 'unknown': {
|
|
||||||
return {
|
|
||||||
text: 'UNKNOWN',
|
|
||||||
iconClass: "fa fa-question",
|
iconClass: "fa fa-question",
|
||||||
stateClass: 'alert-state-warning'
|
stateClass: 'alert-state-warning'
|
||||||
};
|
};
|
||||||
@ -106,7 +94,6 @@ export default {
|
|||||||
getStateDisplayModel: getStateDisplayModel,
|
getStateDisplayModel: getStateDisplayModel,
|
||||||
conditionTypes: conditionTypes,
|
conditionTypes: conditionTypes,
|
||||||
evalFunctions: evalFunctions,
|
evalFunctions: evalFunctions,
|
||||||
severityLevels: severityLevels,
|
|
||||||
noDataModes: noDataModes,
|
noDataModes: noDataModes,
|
||||||
reducerTypes: reducerTypes,
|
reducerTypes: reducerTypes,
|
||||||
createReducerPart: createReducerPart,
|
createReducerPart: createReducerPart,
|
||||||
|
@ -13,9 +13,8 @@ export class AlertListCtrl {
|
|||||||
stateFilters = [
|
stateFilters = [
|
||||||
{text: 'All', value: null},
|
{text: 'All', value: null},
|
||||||
{text: 'OK', value: 'ok'},
|
{text: 'OK', value: 'ok'},
|
||||||
{text: 'Unknown', value: 'unknown'},
|
{text: 'Alerting', value: 'alerting'},
|
||||||
{text: 'Warning', value: 'warning'},
|
{text: 'No Data', value: 'no_data'},
|
||||||
{text: 'Critical', value: 'critical'},
|
|
||||||
{text: 'Execution Error', value: 'execution_error'},
|
{text: 'Execution Error', value: 'execution_error'},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -17,7 +17,6 @@ export class AlertTabCtrl {
|
|||||||
alert: any;
|
alert: any;
|
||||||
conditionModels: any;
|
conditionModels: any;
|
||||||
evalFunctions: any;
|
evalFunctions: any;
|
||||||
severityLevels: any;
|
|
||||||
noDataModes: any;
|
noDataModes: any;
|
||||||
addNotificationSegment;
|
addNotificationSegment;
|
||||||
notifications;
|
notifications;
|
||||||
@ -41,7 +40,6 @@ export class AlertTabCtrl {
|
|||||||
this.subTabIndex = 0;
|
this.subTabIndex = 0;
|
||||||
this.evalFunctions = alertDef.evalFunctions;
|
this.evalFunctions = alertDef.evalFunctions;
|
||||||
this.conditionTypes = alertDef.conditionTypes;
|
this.conditionTypes = alertDef.conditionTypes;
|
||||||
this.severityLevels = alertDef.severityLevels;
|
|
||||||
this.noDataModes = alertDef.noDataModes;
|
this.noDataModes = alertDef.noDataModes;
|
||||||
this.appSubUrl = config.appSubUrl;
|
this.appSubUrl = config.appSubUrl;
|
||||||
}
|
}
|
||||||
@ -155,8 +153,7 @@ export class AlertTabCtrl {
|
|||||||
alert.conditions.push(this.buildDefaultCondition());
|
alert.conditions.push(this.buildDefaultCondition());
|
||||||
}
|
}
|
||||||
|
|
||||||
alert.noDataState = alert.noDataState || 'unknown';
|
alert.noDataState = alert.noDataState || 'no_data';
|
||||||
alert.severity = alert.severity || 'critical';
|
|
||||||
alert.frequency = alert.frequency || '60s';
|
alert.frequency = alert.frequency || '60s';
|
||||||
alert.handler = alert.handler || 1;
|
alert.handler = alert.handler || 1;
|
||||||
alert.notifications = alert.notifications || [];
|
alert.notifications = alert.notifications || [];
|
||||||
@ -321,11 +318,6 @@ export class AlertTabCtrl {
|
|||||||
this.panelCtrl.render();
|
this.panelCtrl.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
severityChanged() {
|
|
||||||
ThresholdMapper.alertToGraphThresholds(this.panel);
|
|
||||||
this.panelCtrl.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
evaluatorTypeChanged(evaluator) {
|
evaluatorTypeChanged(evaluator) {
|
||||||
// ensure params array is correct length
|
// ensure params array is correct length
|
||||||
switch (evaluator.type) {
|
switch (evaluator.type) {
|
||||||
|
@ -29,18 +29,8 @@
|
|||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<span class="gf-form-label width-8">Name</span>
|
<span class="gf-form-label width-8">Name</span>
|
||||||
<input type="text" class="gf-form-input width-25" ng-model="ctrl.alert.name">
|
<input type="text" class="gf-form-input width-25" ng-model="ctrl.alert.name">
|
||||||
</div>
|
<span class="gf-form-label width-8">Evaluate every</span>
|
||||||
<div class="gf-form-inline">
|
<input class="gf-form-input max-width-5" type="text" ng-model="ctrl.alert.frequency"></input>
|
||||||
<div class="gf-form">
|
|
||||||
<span class="gf-form-label width-8">Evaluate every</span>
|
|
||||||
<input class="gf-form-input max-width-7" type="text" ng-model="ctrl.alert.frequency"></input>
|
|
||||||
</div>
|
|
||||||
<div class="gf-form">
|
|
||||||
<span class="gf-form-label">Severity</span>
|
|
||||||
<div class="gf-form-select-wrapper width-13">
|
|
||||||
<select class="gf-form-input" ng-model="ctrl.alert.severity" ng-options="key as value.text for (key, value) in ctrl.severityLevels" ng-change="ctrl.severityChanged()">
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -62,7 +62,7 @@ export class ThresholdMapper {
|
|||||||
for (var t of panel.thresholds) {
|
for (var t of panel.thresholds) {
|
||||||
t.fill = true;
|
t.fill = true;
|
||||||
t.line = true;
|
t.line = true;
|
||||||
t.colorMode = panel.alert.severity;
|
t.colorMode = 'critical';
|
||||||
}
|
}
|
||||||
|
|
||||||
var updated = true;
|
var updated = true;
|
||||||
|
Loading…
Reference in New Issue
Block a user