Commit 783d6975 by Torkel Ödegaard

feat(alerting): more output when testing alert

parent b073fe0e
...@@ -50,3 +50,8 @@ type AlertTestResultLog struct { ...@@ -50,3 +50,8 @@ type AlertTestResultLog struct {
Message string `json:"message"` Message string `json:"message"`
Data interface{} `json:"data"` Data interface{} `json:"data"`
} }
type AlertEvent struct {
Metric string `json:"metric"`
Value float64 `json:"value"`
}
...@@ -29,11 +29,10 @@ func (this *UpdateAlertStateCommand) IsValidState() bool { ...@@ -29,11 +29,10 @@ func (this *UpdateAlertStateCommand) IsValidState() bool {
// Commands // Commands
type UpdateAlertStateCommand struct { type UpdateAlertStateCommand struct {
AlertId int64 `json:"alertId" binding:"Required"` AlertId int64 `json:"alertId" binding:"Required"`
OrgId int64 `json:"orgId" binding:"Required"` OrgId int64 `json:"orgId" binding:"Required"`
State string `json:"state" binding:"Required"` State string `json:"state" binding:"Required"`
Info string `json:"info"` Info string `json:"info"`
TriggeredAlerts *simplejson.Json `json:"triggeredAlerts"`
Result *Alert Result *Alert
} }
......
...@@ -70,11 +70,11 @@ func NewAlertRuleFromDBModel(ruleDef *m.Alert) (*AlertRule, error) { ...@@ -70,11 +70,11 @@ func NewAlertRuleFromDBModel(ruleDef *m.Alert) (*AlertRule, error) {
} }
} }
for _, condition := range ruleDef.Settings.Get("conditions").MustArray() { for index, condition := range ruleDef.Settings.Get("conditions").MustArray() {
conditionModel := simplejson.NewFromAny(condition) conditionModel := simplejson.NewFromAny(condition)
switch conditionModel.Get("type").MustString() { switch conditionModel.Get("type").MustString() {
case "query": case "query":
queryCondition, err := NewQueryCondition(conditionModel) queryCondition, err := NewQueryCondition(conditionModel, index)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -11,6 +11,7 @@ import ( ...@@ -11,6 +11,7 @@ import (
) )
type QueryCondition struct { type QueryCondition struct {
Index int
Query AlertQuery Query AlertQuery
Reducer QueryReducer Reducer QueryReducer
Evaluator AlertEvaluator Evaluator AlertEvaluator
...@@ -27,7 +28,18 @@ func (c *QueryCondition) Eval(context *AlertResultContext) { ...@@ -27,7 +28,18 @@ func (c *QueryCondition) Eval(context *AlertResultContext) {
for _, series := range seriesList { for _, series := range seriesList {
reducedValue := c.Reducer.Reduce(series) reducedValue := c.Reducer.Reduce(series)
pass := c.Evaluator.Eval(series, reducedValue) pass := c.Evaluator.Eval(series, reducedValue)
if context.IsTestRun {
context.Logs = append(context.Logs, &AlertResultLogEntry{
Message: fmt.Sprintf("Condition[%d]: Eval: %v, Metric: %s, Value: %1.3f", c.Index, pass, series.Name, reducedValue),
})
}
if pass { if pass {
context.Events = append(context.Events, &AlertEvent{
Metric: series.Name,
Value: reducedValue,
})
context.Triggered = true context.Triggered = true
break break
} }
...@@ -61,7 +73,7 @@ func (c *QueryCondition) executeQuery(context *AlertResultContext) (tsdb.TimeSer ...@@ -61,7 +73,7 @@ func (c *QueryCondition) executeQuery(context *AlertResultContext) (tsdb.TimeSer
if context.IsTestRun { if context.IsTestRun {
context.Logs = append(context.Logs, &AlertResultLogEntry{ context.Logs = append(context.Logs, &AlertResultLogEntry{
Message: "Query Condition Query Result", Message: fmt.Sprintf("Condition[%d]: Query Result", c.Index),
Data: v.Series, Data: v.Series,
}) })
} }
...@@ -93,8 +105,9 @@ func (c *QueryCondition) getRequestForAlertRule(datasource *m.DataSource) *tsdb. ...@@ -93,8 +105,9 @@ func (c *QueryCondition) getRequestForAlertRule(datasource *m.DataSource) *tsdb.
return req return req
} }
func NewQueryCondition(model *simplejson.Json) (*QueryCondition, error) { func NewQueryCondition(model *simplejson.Json, index int) (*QueryCondition, error) {
condition := QueryCondition{} condition := QueryCondition{}
condition.Index = index
condition.HandleRequest = tsdb.HandleRequest condition.HandleRequest = tsdb.HandleRequest
queryJson := model.Get("query") queryJson := model.Get("query")
......
...@@ -60,7 +60,7 @@ func (ctx *queryConditionTestContext) exec() { ...@@ -60,7 +60,7 @@ func (ctx *queryConditionTestContext) exec() {
}`)) }`))
So(err, ShouldBeNil) So(err, ShouldBeNil)
condition, err := NewQueryCondition(jsonModel) condition, err := NewQueryCondition(jsonModel, 0)
So(err, ShouldBeNil) So(err, ShouldBeNil)
condition.HandleRequest = func(req *tsdb.Request) (*tsdb.Response, error) { condition.HandleRequest = func(req *tsdb.Request) (*tsdb.Response, error) {
......
...@@ -33,7 +33,7 @@ func (e *HandlerImpl) Execute(context *AlertResultContext) { ...@@ -33,7 +33,7 @@ func (e *HandlerImpl) Execute(context *AlertResultContext) {
context.EndTime = time.Now() context.EndTime = time.Now()
e.log.Debug("Job Execution timeout", "alertId", context.Rule.Id) e.log.Debug("Job Execution timeout", "alertId", context.Rule.Id)
case <-context.DoneChan: case <-context.DoneChan:
e.log.Debug("Job Execution done", "timing", context.GetDurationSeconds(), "alertId", context.Rule.Id) e.log.Debug("Job Execution done", "timing", context.GetDurationSeconds(), "alertId", context.Rule.Id, "triggered", context.Triggered)
} }
} }
......
...@@ -30,7 +30,7 @@ func (aj *AlertJob) IncRetry() { ...@@ -30,7 +30,7 @@ func (aj *AlertJob) IncRetry() {
type AlertResultContext struct { type AlertResultContext struct {
Triggered bool Triggered bool
IsTestRun bool IsTestRun bool
Details []*AlertResultDetail Events []*AlertEvent
Logs []*AlertResultLogEntry Logs []*AlertResultLogEntry
Error error Error error
Description string Description string
...@@ -51,6 +51,7 @@ func NewAlertResultContext(rule *AlertRule) *AlertResultContext { ...@@ -51,6 +51,7 @@ func NewAlertResultContext(rule *AlertRule) *AlertResultContext {
StartTime: time.Now(), StartTime: time.Now(),
Rule: rule, Rule: rule,
Logs: make([]*AlertResultLogEntry, 0), Logs: make([]*AlertResultLogEntry, 0),
Events: make([]*AlertEvent, 0),
DoneChan: make(chan bool, 1), DoneChan: make(chan bool, 1),
CancelChan: make(chan bool, 1), CancelChan: make(chan bool, 1),
log: log.New("alerting.engine"), log: log.New("alerting.engine"),
...@@ -62,7 +63,7 @@ type AlertResultLogEntry struct { ...@@ -62,7 +63,7 @@ type AlertResultLogEntry struct {
Data interface{} Data interface{}
} }
type AlertResultDetail struct { type AlertEvent struct {
Value float64 Value float64
Metric string Metric string
State string State string
......
...@@ -4,7 +4,6 @@ import ( ...@@ -4,7 +4,6 @@ import (
"time" "time"
"github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/log"
m "github.com/grafana/grafana/pkg/models" m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting/alertstates" "github.com/grafana/grafana/pkg/services/alerting/alertstates"
...@@ -37,11 +36,10 @@ func (handler *ResultHandlerImpl) Handle(result *AlertResultContext) { ...@@ -37,11 +36,10 @@ func (handler *ResultHandlerImpl) Handle(result *AlertResultContext) {
if handler.shouldUpdateState(result, newState) { if handler.shouldUpdateState(result, newState) {
cmd := &m.UpdateAlertStateCommand{ cmd := &m.UpdateAlertStateCommand{
AlertId: result.Rule.Id, AlertId: result.Rule.Id,
Info: result.Description, Info: result.Description,
OrgId: result.Rule.OrgId, OrgId: result.Rule.OrgId,
State: newState, State: newState,
TriggeredAlerts: simplejson.NewFromAny(result.Details),
} }
if err := bus.Dispatch(cmd); err != nil { if err := bus.Dispatch(cmd); err != nil {
......
...@@ -51,12 +51,11 @@ func SetNewAlertState(cmd *m.UpdateAlertStateCommand) error { ...@@ -51,12 +51,11 @@ func SetNewAlertState(cmd *m.UpdateAlertStateCommand) error {
sess.Id(alert.Id).Update(&alert) sess.Id(alert.Id).Update(&alert)
alertState := m.AlertState{ alertState := m.AlertState{
AlertId: cmd.AlertId, AlertId: cmd.AlertId,
OrgId: cmd.OrgId, OrgId: cmd.OrgId,
State: cmd.State, State: cmd.State,
Info: cmd.Info, Info: cmd.Info,
Created: time.Now(), Created: time.Now(),
TriggeredAlerts: cmd.TriggeredAlerts,
} }
sess.Insert(&alertState) sess.Insert(&alertState)
......
...@@ -22,7 +22,7 @@ export class AlertLogCtrl { ...@@ -22,7 +22,7 @@ export class AlertLogCtrl {
loadAlertLogs(alertId: number) { loadAlertLogs(alertId: number) {
this.backendSrv.get(`/api/alerts/${alertId}/states`).then(result => { this.backendSrv.get(`/api/alerts/${alertId}/states`).then(result => {
this.alertLogs = _.map(result, log => { this.alertLogs = _.map(result, log => {
log.iconCss = alertDef.getCssForState(log.newState); log.iconCss = alertDef.getCssForState(log.state);
log.humanTime = moment(log.created).format("YYYY-MM-DD HH:mm:ss"); log.humanTime = moment(log.created).format("YYYY-MM-DD HH:mm:ss");
return log; return log;
}); });
......
...@@ -6,55 +6,6 @@ ...@@ -6,55 +6,6 @@
<h1>Alert history for {{ctrl.alert.title}}</h1> <h1>Alert history for {{ctrl.alert.title}}</h1>
</div> </div>
<div class="gf-form-group section" >
<h5 class="section-heading">Thresholds</h5>
<div class="gf-form">
<span class="gf-form-label width-9">
<i class="icon-gf icon-gf-warn alert-icon-warn"></i>
Warn level
</span>
<div class="gf-form-label max-width-10">
{{ctrl.alert.warnOperator}}
</div>
<div class="gf-form-label max-width-10">
{{ctrl.alert.warnLevel}}
</div>
</div>
<div class="gf-form">
<span class="gf-form-label width-9">
<i class="icon-gf icon-gf-critical alert-icon-critical"></i>
Critical level
</span>
<div class="gf-form-label max-width-10">
{{ctrl.alert.critOperator}}
</div>
<div class="gf-form-label max-width-10">
{{ctrl.alert.critLevel}}
</div>
</div>
</div>
<div class="gf-form-group section" >
<h5 class="section-heading">Aggregators</h5>
<div class="gf-form">
<span class="gf-form-label width-12">
Aggregator
</span>
<div class="gf-form-label max-width-10">
{{ctrl.alert.aggregator}}
</div>
</div>
<div class="gf-form">
<span class="gf-form-label width-12">Query range (seconds)</span>
<span class="gf-form-label width-10">{{ctrl.alert.queryRange}}</span>
</div>
<div class="gf-form">
<span class="gf-form-label width-12">Frequency (seconds)</span>
<span class="gf-form-label width-10">{{ctrl.alert.frequency}}</span>
</div>
</div>
<table class="filter-table"> <table class="filter-table">
<thead> <thead>
<th style="width: 68px">Status</th> <th style="width: 68px">Status</th>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment