Revert changes post code review and move them to notification page

This commit is contained in:
John Baublitz
2018-05-19 16:21:00 -04:00
committed by bergquist
parent e068be4c26
commit 3cb0e27e1c
34 changed files with 215 additions and 107 deletions

View File

@@ -21,18 +21,17 @@ type AlertRule struct {
ExecutionError string `json:"executionError"`
Url string `json:"url"`
CanEdit bool `json:"canEdit"`
NotifyOnce bool `json:"notifyOnce"`
NotifyEval uint64 `json:"notifyEval"`
NotifyFreq uint64 `json:"notifyFrequency"`
}
type AlertNotification struct {
Id int64 `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
IsDefault bool `json:"isDefault"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
Id int64 `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
IsDefault bool `json:"isDefault"`
NotifyOnce bool `json:"notifyOnce"`
Frequency bool `json:"frequency"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
}
type AlertTestCommand struct {
@@ -62,9 +61,11 @@ type EvalMatch struct {
}
type NotificationTestCommand struct {
Name string `json:"name"`
Type string `json:"type"`
Settings *simplejson.Json `json:"settings"`
Name string `json:"name"`
Type string `json:"type"`
NotifyOnce bool `json:"notifyOnce"`
Frequency time.Duration `json:"frequency"`
Settings *simplejson.Json `json:"settings"`
}
type PauseAlertCommand struct {

View File

@@ -72,9 +72,6 @@ type Alert struct {
Silenced bool
ExecutionError string
Frequency int64
NotifyOnce bool
NotifyFreq uint64
NotifyEval uint64
EvalData *simplejson.Json
NewStateDate time.Time
@@ -98,8 +95,6 @@ func (this *Alert) ContainsUpdates(other *Alert) bool {
result := false
result = result || this.Name != other.Name
result = result || this.Message != other.Message
result = result || this.NotifyOnce != other.NotifyOnce
result = result || (!other.NotifyOnce && this.NotifyFreq != other.NotifyFreq)
if this.Settings != nil && other.Settings != nil {
json1, err1 := this.Settings.Encode()
@@ -164,10 +159,6 @@ type SetAlertStateCommand struct {
Timestamp time.Time
}
type IncAlertEvalCommand struct {
AlertId int64
}
//Queries
type GetAlertsQuery struct {
OrgId int64

View File

@@ -7,32 +7,38 @@ import (
)
type AlertNotification struct {
Id int64 `json:"id"`
OrgId int64 `json:"-"`
Name string `json:"name"`
Type string `json:"type"`
IsDefault bool `json:"isDefault"`
Settings *simplejson.Json `json:"settings"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
Id int64 `json:"id"`
OrgId int64 `json:"-"`
Name string `json:"name"`
Type string `json:"type"`
NotifyOnce bool `json:"notifyOnce"`
Frequency time.Duration `json:"frequency"`
IsDefault bool `json:"isDefault"`
Settings *simplejson.Json `json:"settings"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
}
type CreateAlertNotificationCommand struct {
Name string `json:"name" binding:"Required"`
Type string `json:"type" binding:"Required"`
IsDefault bool `json:"isDefault"`
Settings *simplejson.Json `json:"settings"`
Name string `json:"name" binding:"Required"`
Type string `json:"type" binding:"Required"`
NotifyOnce bool `json:"notifyOnce" binding:"Required"`
Frequency time.Duration `json:"frequency"`
IsDefault bool `json:"isDefault"`
Settings *simplejson.Json `json:"settings"`
OrgId int64 `json:"-"`
Result *AlertNotification
}
type UpdateAlertNotificationCommand struct {
Id int64 `json:"id" binding:"Required"`
Name string `json:"name" binding:"Required"`
Type string `json:"type" binding:"Required"`
IsDefault bool `json:"isDefault"`
Settings *simplejson.Json `json:"settings" binding:"Required"`
Id int64 `json:"id" binding:"Required"`
Name string `json:"name" binding:"Required"`
Type string `json:"type" binding:"Required"`
NotifyOnce string `json:"notifyOnce" binding:"Required"`
Frequency string `json:"frequency"`
IsDefault bool `json:"isDefault"`
Settings *simplejson.Json `json:"settings" binding:"Required"`
OrgId int64 `json:"-"`
Result *AlertNotification
@@ -63,3 +69,34 @@ type GetAllAlertNotificationsQuery struct {
Result []*AlertNotification
}
type NotificationJournal struct {
Id int64
OrgId int64
AlertId int64
NotifierId int64
SentAt time.Time
Success bool
}
type RecordNotificationJournalCommand struct {
OrgId int64
AlertId int64
NotifierId int64
SentAt time.Time
Success bool
}
type GetLatestNotificationQuery struct {
OrgId int64
AlertId int64
NotifierId int64
Result *NotificationJournal
}
type CleanNotificationJournalCommand struct {
OrgId int64
AlertId int64
NotifierId int64
}

View File

@@ -143,3 +143,18 @@ func (c *EvalContext) GetNewState() m.AlertStateType {
return m.AlertStateOK
}
func (c *EvalContext) LastNotify(notifierId int64) *time.Time {
cmd := &m.GetLatestNotificationQuery{
OrgId: c.Rule.OrgId,
AlertId: c.Rule.Id,
NotifierId: notifierId,
}
if err := bus.Dispatch(cmd); err != nil {
c.log.Warn("Could not determine last time alert",
c.Rule.Name, "notified")
return nil
}
return &cmd.Result.SentAt
}

View File

@@ -122,8 +122,6 @@ func (e *DashAlertExtractor) getAlertFromPanels(jsonWithPanels *simplejson.Json,
Handler: jsonAlert.Get("handler").MustInt64(),
Message: jsonAlert.Get("message").MustString(),
Frequency: frequency,
NotifyOnce: jsonAlert.Get("notifyOnce").MustBool(),
NotifyFreq: jsonAlert.Get("notifyFrequency").MustUint64(),
}
for _, condition := range jsonAlert.Get("conditions").MustArray() {

View File

@@ -19,6 +19,8 @@ type Notifier interface {
GetNotifierId() int64
GetIsDefault() bool
GetNotifyOnce() bool
GetFrequency() time.Duration
}
type NotifierSlice []Notifier

View File

@@ -66,7 +66,17 @@ func (n *notificationService) sendNotifications(context *EvalContext, notifiers
not := notifier //avoid updating scope variable in go routine
n.log.Debug("Sending notification", "type", not.GetType(), "id", not.GetNotifierId(), "isDefault", not.GetIsDefault())
metrics.M_Alerting_Notification_Sent.WithLabelValues(not.GetType()).Inc()
g.Go(func() error { return not.Notify(context) })
g.Go(func() error {
success := not.Notify(context) == nil
cmd := &m.RecordNotificationJournalCommand{
OrgId: context.Rule.OrgId,
AlertId: context.Rule.Id,
NotifierId: not.GetNotifierId(),
SentAt: time.Now(),
Success: success,
}
return bus.Dispatch(cmd)
})
}
return g.Wait()

View File

@@ -33,7 +33,7 @@ func NewAlertmanagerNotifier(model *m.AlertNotification) (alerting.Notifier, err
}
return &AlertmanagerNotifier{
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings),
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
Url: url,
log: log.New("alerting.notifier.prometheus-alertmanager"),
}, nil

View File

@@ -1,6 +1,8 @@
package notifiers
import (
"time"
"github.com/grafana/grafana/pkg/components/simplejson"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
@@ -12,9 +14,11 @@ type NotifierBase struct {
Id int64
IsDeault bool
UploadImage bool
NotifyOnce bool
Frequency time.Duration
}
func NewNotifierBase(id int64, isDefault bool, name, notifierType string, model *simplejson.Json) NotifierBase {
func NewNotifierBase(id int64, isDefault bool, name, notifierType string, notifyOnce bool, frequency time.Duration, model *simplejson.Json) NotifierBase {
uploadImage := true
value, exist := model.CheckGet("uploadImage")
if exist {
@@ -27,15 +31,17 @@ func NewNotifierBase(id int64, isDefault bool, name, notifierType string, model
IsDeault: isDefault,
Type: notifierType,
UploadImage: uploadImage,
NotifyOnce: notifyOnce,
Frequency: frequency,
}
}
func defaultShouldNotify(context *alerting.EvalContext) bool {
func defaultShouldNotify(context *alerting.EvalContext, notifyOnce bool, frequency time.Duration, lastNotify *time.Time) bool {
// Only notify on state change.
if context.PrevAlertState == context.Rule.State && context.Rule.NotifyOnce {
if context.PrevAlertState == context.Rule.State && notifyOnce {
return false
}
if !context.Rule.NotifyOnce && context.Rule.NotifyEval != 0 {
if !notifyOnce && lastNotify != nil && lastNotify.Add(frequency).After(time.Now()) {
return false
}
// Do not notify when we become OK for the first time.
@@ -46,7 +52,8 @@ func defaultShouldNotify(context *alerting.EvalContext) bool {
}
func (n *NotifierBase) ShouldNotify(context *alerting.EvalContext) bool {
return defaultShouldNotify(context)
lastNotify := context.LastNotify(n.Id)
return defaultShouldNotify(context, n.NotifyOnce, n.Frequency, lastNotify)
}
func (n *NotifierBase) GetType() string {
@@ -64,3 +71,11 @@ func (n *NotifierBase) GetNotifierId() int64 {
func (n *NotifierBase) GetIsDefault() bool {
return n.IsDeault
}
func (n *NotifierBase) GetNotifyOnce() bool {
return n.NotifyOnce
}
func (n *NotifierBase) GetFrequency() time.Duration {
return n.Frequency
}

View File

@@ -32,7 +32,7 @@ func NewDingDingNotifier(model *m.AlertNotification) (alerting.Notifier, error)
}
return &DingDingNotifier{
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings),
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
Url: url,
log: log.New("alerting.notifier.dingding"),
}, nil

View File

@@ -39,7 +39,7 @@ func NewDiscordNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
}
return &DiscordNotifier{
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings),
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
WebhookURL: url,
log: log.New("alerting.notifier.discord"),
}, nil

View File

@@ -52,7 +52,7 @@ func NewEmailNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
})
return &EmailNotifier{
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings),
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
Addresses: addresses,
log: log.New("alerting.notifier.email"),
}, nil

View File

@@ -59,7 +59,7 @@ func NewHipChatNotifier(model *models.AlertNotification) (alerting.Notifier, err
roomId := model.Settings.Get("roomid").MustString()
return &HipChatNotifier{
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings),
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
Url: url,
ApiKey: apikey,
RoomId: roomId,

View File

@@ -43,7 +43,7 @@ func NewKafkaNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
}
return &KafkaNotifier{
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings),
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
Endpoint: endpoint,
Topic: topic,
log: log.New("alerting.notifier.kafka"),

View File

@@ -39,7 +39,7 @@ func NewLINENotifier(model *m.AlertNotification) (alerting.Notifier, error) {
}
return &LineNotifier{
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings),
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
Token: token,
log: log.New("alerting.notifier.line"),
}, nil

View File

@@ -56,7 +56,7 @@ func NewOpsGenieNotifier(model *m.AlertNotification) (alerting.Notifier, error)
}
return &OpsGenieNotifier{
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings),
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
ApiKey: apiKey,
ApiUrl: apiUrl,
AutoClose: autoClose,

View File

@@ -51,7 +51,7 @@ func NewPagerdutyNotifier(model *m.AlertNotification) (alerting.Notifier, error)
}
return &PagerdutyNotifier{
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings),
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
Key: key,
AutoResolve: autoResolve,
log: log.New("alerting.notifier.pagerduty"),

View File

@@ -99,7 +99,7 @@ func NewPushoverNotifier(model *m.AlertNotification) (alerting.Notifier, error)
return nil, alerting.ValidationError{Reason: "API token not given"}
}
return &PushoverNotifier{
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings),
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
UserKey: userKey,
ApiToken: apiToken,
Priority: priority,

View File

@@ -51,7 +51,7 @@ func NewSensuNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
}
return &SensuNotifier{
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings),
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
Url: url,
User: model.Settings.Get("username").MustString(),
Source: model.Settings.Get("source").MustString(),

View File

@@ -78,7 +78,7 @@ func NewSlackNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
uploadImage := model.Settings.Get("uploadImage").MustBool(true)
return &SlackNotifier{
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings),
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
Url: url,
Recipient: recipient,
Mention: mention,

View File

@@ -33,7 +33,7 @@ func NewTeamsNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
}
return &TeamsNotifier{
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings),
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
Url: url,
log: log.New("alerting.notifier.teams"),
}, nil

View File

@@ -78,7 +78,7 @@ func NewTelegramNotifier(model *m.AlertNotification) (alerting.Notifier, error)
}
return &TelegramNotifier{
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings),
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
BotToken: botToken,
ChatID: chatId,
UploadImage: uploadImage,

View File

@@ -106,7 +106,7 @@ func NewThreemaNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
}
return &ThreemaNotifier{
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings),
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
GatewayID: gatewayID,
RecipientID: recipientID,
APISecret: apiSecret,

View File

@@ -51,7 +51,7 @@ func NewVictoropsNotifier(model *models.AlertNotification) (alerting.Notifier, e
}
return &VictoropsNotifier{
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings),
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
URL: url,
AutoResolve: autoResolve,
log: log.New("alerting.notifier.victorops"),

View File

@@ -47,7 +47,7 @@ func NewWebHookNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
}
return &WebhookNotifier{
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings),
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
Url: url,
User: model.Settings.Get("username").MustString(),
Password: model.Settings.Get("password").MustString(),

View File

@@ -88,7 +88,6 @@ func (handler *DefaultResultHandler) Handle(evalContext *EvalContext) error {
}
}
bus.Dispatch(&m.IncAlertEvalCommand{AlertId: evalContext.Rule.Id})
handler.notifier.SendIfNeeded(evalContext)
return nil

View File

@@ -23,9 +23,6 @@ type Rule struct {
State m.AlertStateType
Conditions []Condition
Notifications []int64
NotifyOnce bool
NotifyFreq uint64
NotifyEval uint64
}
type ValidationError struct {
@@ -100,9 +97,6 @@ func NewRuleFromDBAlert(ruleDef *m.Alert) (*Rule, error) {
model.Name = ruleDef.Name
model.Message = ruleDef.Message
model.Frequency = ruleDef.Frequency
model.NotifyOnce = ruleDef.NotifyOnce
model.NotifyFreq = ruleDef.NotifyFreq
model.NotifyEval = ruleDef.NotifyEval
model.State = ruleDef.State
model.NoDataState = m.NoDataOption(ruleDef.Settings.Get("noDataState").MustString("no_data"))
model.ExecutionErrorState = m.ExecutionErrorOption(ruleDef.Settings.Get("executionErrorState").MustString("alerting"))

View File

@@ -22,7 +22,6 @@ func init() {
bus.AddHandler("sql", GetAlertStatesForDashboard)
bus.AddHandler("sql", PauseAlert)
bus.AddHandler("sql", PauseAllAlerts)
bus.AddHandler("sql", IncAlertEval)
}
func GetAlertById(query *m.GetAlertByIdQuery) error {
@@ -189,7 +188,7 @@ func updateAlerts(existingAlerts []*m.Alert, cmd *m.SaveAlertsCommand, sess *DBS
if alertToUpdate.ContainsUpdates(alert) {
alert.Updated = timeNow()
alert.State = alertToUpdate.State
sess.MustCols("message", "notify_freq", "notify_once")
sess.MustCols("message")
_, err := sess.Id(alert.Id).Update(alert)
if err != nil {
return err
@@ -344,22 +343,3 @@ func GetAlertStatesForDashboard(query *m.GetAlertStatesForDashboardQuery) error
return err
}
func IncAlertEval(cmd *m.IncAlertEvalCommand) error {
return inTransaction(func(sess *DBSession) error {
alert := m.Alert{}
if _, err := sess.Id(cmd.AlertId).Get(&alert); err != nil {
return err
}
alert.NotifyEval = (alert.NotifyEval + 1) % alert.NotifyFreq
sess.MustCols("notify_eval")
if _, err := sess.Id(cmd.AlertId).Update(alert); err != nil {
return err
}
return nil
})
}

View File

@@ -17,6 +17,9 @@ func init() {
bus.AddHandler("sql", DeleteAlertNotification)
bus.AddHandler("sql", GetAlertNotificationsToSend)
bus.AddHandler("sql", GetAllAlertNotifications)
bus.AddHandler("sql", RecordNotificationJournal)
bus.AddHandler("sql", GetLatestNotification)
bus.AddHandler("sql", CleanNotificationJournal)
}
func DeleteAlertNotification(cmd *m.DeleteAlertNotificationCommand) error {
@@ -138,13 +141,15 @@ func CreateAlertNotificationCommand(cmd *m.CreateAlertNotificationCommand) error
}
alertNotification := &m.AlertNotification{
OrgId: cmd.OrgId,
Name: cmd.Name,
Type: cmd.Type,
Settings: cmd.Settings,
Created: time.Now(),
Updated: time.Now(),
IsDefault: cmd.IsDefault,
OrgId: cmd.OrgId,
Name: cmd.Name,
Type: cmd.Type,
Settings: cmd.Settings,
NotifyOnce: cmd.NotifyOnce,
Frequency: cmd.Frequency,
Created: time.Now(),
Updated: time.Now(),
IsDefault: cmd.IsDefault,
}
if _, err = sess.Insert(alertNotification); err != nil {
@@ -192,3 +197,42 @@ func UpdateAlertNotification(cmd *m.UpdateAlertNotificationCommand) error {
return nil
})
}
func RecordNotificationJournal(cmd *m.RecordNotificationJournalCommand) error {
return inTransaction(func(sess *DBSession) error {
journalEntry := &m.NotificationJournal{
OrgId: cmd.OrgId,
AlertId: cmd.AlertId,
NotifierId: cmd.NotifierId,
SentAt: cmd.SentAt,
Success: cmd.Success,
}
if _, err := sess.Insert(journalEntry); err != nil {
return err
}
return nil
})
}
func GetLatestNotification(cmd *m.GetLatestNotificationQuery) error {
return inTransaction(func(sess *DBSession) error {
notificationJournal := &m.NotificationJournal{}
_, err := sess.OrderBy("notification_journal.sent_at").Desc().Where("notification_journal.org_id = ? AND notification_journal.alert_id = ? AND notification_journal.notifier_id = ?", cmd.OrgId, cmd.AlertId, cmd.NotifierId).Get(notificationJournal)
if err != nil {
return err
}
cmd.Result = notificationJournal
return nil
})
}
func CleanNotificationJournal(cmd *m.CleanNotificationJournalCommand) error {
return inTransaction(func(sess *DBSession) error {
sql := "DELETE FROM notification_journal WHERE notification_journal.org_id = ? AND notification_journal.alert_id = ? AND notification_journal.notifier_id = ?"
_, err := sess.Exec(sql, cmd.OrgId, cmd.AlertId, cmd.NotifierId)
return err
})
}

View File

@@ -29,9 +29,6 @@ func addAlertMigrations(mg *Migrator) {
{Name: "state_changes", Type: DB_Int, Nullable: false},
{Name: "created", Type: DB_DateTime, Nullable: false},
{Name: "updated", Type: DB_DateTime, Nullable: false},
{Name: "notify_once", Type: DB_Bool, Nullable: false},
{Name: "notify_freq", Type: DB_Int, Nullable: false},
{Name: "notify_eval", Type: DB_Int, Nullable: false},
},
Indices: []*Index{
{Cols: []string{"org_id", "id"}, Type: IndexType},
@@ -68,8 +65,32 @@ func addAlertMigrations(mg *Migrator) {
mg.AddMigration("Add column is_default", NewAddColumnMigration(alert_notification, &Column{
Name: "is_default", Type: DB_Bool, Nullable: false, Default: "0",
}))
mg.AddMigration("Add column frequency", NewAddColumnMigration(alert_notification, &Column{
Name: "frequency", Type: DB_BigInt, Nullable: true,
}))
mg.AddMigration("Add column notify_once", NewAddColumnMigration(alert_notification, &Column{
Name: "notify_once", Type: DB_Bool, Nullable: false, Default: "1",
}))
mg.AddMigration("add index alert_notification org_id & name", NewAddIndexMigration(alert_notification, alert_notification.Indices[0]))
notification_journal := Table{
Name: "notification_journal",
Columns: []*Column{
{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
{Name: "org_id", Type: DB_BigInt, Nullable: false},
{Name: "alert_id", Type: DB_BigInt, Nullable: false},
{Name: "notifier_id", Type: DB_BigInt, Nullable: false},
{Name: "sent_at", Type: DB_DateTime, Nullable: false},
{Name: "success", Type: DB_Bool, Nullable: false},
},
Indices: []*Index{
{Cols: []string{"org_id", "alert_id", "notifier_id"}, Type: IndexType},
},
}
mg.AddMigration("create notification_journal table v1", NewAddTableMigration(notification_journal))
mg.AddMigration("add index notification_journal org_id & alert_id & notifier_id", NewAddIndexMigration(notification_journal, notification_journal.Indices[0]))
mg.AddMigration("Update alert table charset", NewTableCharsetMigration("alert", []*Column{
{Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false},
{Name: "message", Type: DB_Text, Nullable: false},

View File

@@ -167,9 +167,6 @@ export class AlertTabCtrl {
alert.noDataState = alert.noDataState || 'no_data';
alert.executionErrorState = alert.executionErrorState || 'alerting';
alert.frequency = alert.frequency || '60s';
alert.notifyFrequency = alert.notifyFrequency || 10;
alert.notifyOnce = alert.notifyOnce == null ? true : alert.notifyOnce;
alert.frequency = alert.frequency || '60s';
alert.handler = alert.handler || 1;
alert.notifications = alert.notifications || [];

View File

@@ -11,6 +11,7 @@ export class AlertNotificationEditCtrl {
model: any;
defaults: any = {
type: 'email',
notifyOnce: true,
settings: {
httpMethod: 'POST',
autoResolve: true,
@@ -102,6 +103,7 @@ export class AlertNotificationEditCtrl {
var payload = {
name: this.model.name,
type: this.model.type,
frequency: this.model.frequency,
settings: this.model.settings,
};

View File

@@ -31,9 +31,6 @@
<input type="text" class="gf-form-input width-20" ng-model="ctrl.alert.name">
<span class="gf-form-label">Evaluate every</span>
<input class="gf-form-input max-width-5" type="text" ng-model="ctrl.alert.frequency"></input>
<a class="gf-form-label" ng-click="ctrl.alert.notifyOnce = !ctrl.alert.notifyOnce;">{{ ctrl.alert.notifyOnce ? 'Notify on state change' : 'Notify every' }}</a>
<input class="gf-form-input max-width-5" type="number" ng-model="ctrl.alert.notifyFrequency" ng-hide="ctrl.alert.notifyOnce"></input>
<span class="gf-form-label" ng-hide="ctrl.alert.notifyOnce">evaluations</span>
</div>
</div>

View File

@@ -18,6 +18,11 @@
</select>
</div>
</div>
<div class="gf-form">
<a class="gf-form-label width-12" ng-click="ctrl.model.notifyOnce = !ctrl.model.notifyOnce;">{{ ctrl.model.notifyOnce ? 'Notify on state change' : 'Notify at most every' }}</a>
<input class="gf-form-input max-width-10" type="number" required ng-model="ctrl.model.frequency" required ng-hide="ctrl.model.notifyOnce"></input>
<span class="gf-form-label max-width-5" ng-hide="ctrl.model.notifyOnce">seconds</span>
</div>
<gf-form-switch
class="gf-form"
label="Send on all alerts"