Commit 783d6975 by Torkel Ödegaard

feat(alerting): more output when testing alert

parent b073fe0e
......@@ -50,3 +50,8 @@ type AlertTestResultLog struct {
Message string `json:"message"`
Data interface{} `json:"data"`
}
type AlertEvent struct {
Metric string `json:"metric"`
Value float64 `json:"value"`
}
......@@ -29,11 +29,10 @@ func (this *UpdateAlertStateCommand) IsValidState() bool {
// Commands
type UpdateAlertStateCommand struct {
AlertId int64 `json:"alertId" binding:"Required"`
OrgId int64 `json:"orgId" binding:"Required"`
State string `json:"state" binding:"Required"`
Info string `json:"info"`
TriggeredAlerts *simplejson.Json `json:"triggeredAlerts"`
AlertId int64 `json:"alertId" binding:"Required"`
OrgId int64 `json:"orgId" binding:"Required"`
State string `json:"state" binding:"Required"`
Info string `json:"info"`
Result *Alert
}
......
......@@ -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)
switch conditionModel.Get("type").MustString() {
case "query":
queryCondition, err := NewQueryCondition(conditionModel)
queryCondition, err := NewQueryCondition(conditionModel, index)
if err != nil {
return nil, err
}
......
......@@ -11,6 +11,7 @@ import (
)
type QueryCondition struct {
Index int
Query AlertQuery
Reducer QueryReducer
Evaluator AlertEvaluator
......@@ -27,7 +28,18 @@ func (c *QueryCondition) Eval(context *AlertResultContext) {
for _, series := range seriesList {
reducedValue := c.Reducer.Reduce(series)
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 {
context.Events = append(context.Events, &AlertEvent{
Metric: series.Name,
Value: reducedValue,
})
context.Triggered = true
break
}
......@@ -61,7 +73,7 @@ func (c *QueryCondition) executeQuery(context *AlertResultContext) (tsdb.TimeSer
if context.IsTestRun {
context.Logs = append(context.Logs, &AlertResultLogEntry{
Message: "Query Condition Query Result",
Message: fmt.Sprintf("Condition[%d]: Query Result", c.Index),
Data: v.Series,
})
}
......@@ -93,8 +105,9 @@ func (c *QueryCondition) getRequestForAlertRule(datasource *m.DataSource) *tsdb.
return req
}
func NewQueryCondition(model *simplejson.Json) (*QueryCondition, error) {
func NewQueryCondition(model *simplejson.Json, index int) (*QueryCondition, error) {
condition := QueryCondition{}
condition.Index = index
condition.HandleRequest = tsdb.HandleRequest
queryJson := model.Get("query")
......
......@@ -60,7 +60,7 @@ func (ctx *queryConditionTestContext) exec() {
}`))
So(err, ShouldBeNil)
condition, err := NewQueryCondition(jsonModel)
condition, err := NewQueryCondition(jsonModel, 0)
So(err, ShouldBeNil)
condition.HandleRequest = func(req *tsdb.Request) (*tsdb.Response, error) {
......
......@@ -33,7 +33,7 @@ func (e *HandlerImpl) Execute(context *AlertResultContext) {
context.EndTime = time.Now()
e.log.Debug("Job Execution timeout", "alertId", context.Rule.Id)
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() {
type AlertResultContext struct {
Triggered bool
IsTestRun bool
Details []*AlertResultDetail
Events []*AlertEvent
Logs []*AlertResultLogEntry
Error error
Description string
......@@ -51,6 +51,7 @@ func NewAlertResultContext(rule *AlertRule) *AlertResultContext {
StartTime: time.Now(),
Rule: rule,
Logs: make([]*AlertResultLogEntry, 0),
Events: make([]*AlertEvent, 0),
DoneChan: make(chan bool, 1),
CancelChan: make(chan bool, 1),
log: log.New("alerting.engine"),
......@@ -62,7 +63,7 @@ type AlertResultLogEntry struct {
Data interface{}
}
type AlertResultDetail struct {
type AlertEvent struct {
Value float64
Metric string
State string
......
......@@ -4,7 +4,6 @@ import (
"time"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/log"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting/alertstates"
......@@ -37,11 +36,10 @@ func (handler *ResultHandlerImpl) Handle(result *AlertResultContext) {
if handler.shouldUpdateState(result, newState) {
cmd := &m.UpdateAlertStateCommand{
AlertId: result.Rule.Id,
Info: result.Description,
OrgId: result.Rule.OrgId,
State: newState,
TriggeredAlerts: simplejson.NewFromAny(result.Details),
AlertId: result.Rule.Id,
Info: result.Description,
OrgId: result.Rule.OrgId,
State: newState,
}
if err := bus.Dispatch(cmd); err != nil {
......
......@@ -51,12 +51,11 @@ func SetNewAlertState(cmd *m.UpdateAlertStateCommand) error {
sess.Id(alert.Id).Update(&alert)
alertState := m.AlertState{
AlertId: cmd.AlertId,
OrgId: cmd.OrgId,
State: cmd.State,
Info: cmd.Info,
Created: time.Now(),
TriggeredAlerts: cmd.TriggeredAlerts,
AlertId: cmd.AlertId,
OrgId: cmd.OrgId,
State: cmd.State,
Info: cmd.Info,
Created: time.Now(),
}
sess.Insert(&alertState)
......
......@@ -22,7 +22,7 @@ export class AlertLogCtrl {
loadAlertLogs(alertId: number) {
this.backendSrv.get(`/api/alerts/${alertId}/states`).then(result => {
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");
return log;
});
......
......@@ -6,55 +6,6 @@
<h1>Alert history for {{ctrl.alert.title}}</h1>
</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">
<thead>
<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