mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat(alerting): more output when testing alert
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user