mirror of
https://github.com/grafana/grafana.git
synced 2024-11-25 18:30:41 -06:00
f6a46744a6
Backend: * Update the Grafana Alerting engine to provide feedback to HysteresisCommand. The feedback information is stored in state.Manager as a fingerprint of each state. The fingerprint is persisted to the database. Only fingerprints that belong to Pending and Alerting states are considered as "loaded" and provided back to the command. - add ResultFingerprint to state.State. It's different from other fingerprints we store in the state because it is calculated from the result labels. - add rule_fingerprint column to alert_instance - update alerting evaluator to accept AlertingResultsReader via context, and update scheduler to provide it. - add AlertingResultsFromRuleState that implements the new interface in eval package - update getExprRequest to patch the hysteresis command. * Only one "Recovery Threshold" query is allowed to be used in the alert rule and it must be the Condition. Frontend: * Add hysteresis option to Threshold in UI. It's called "Recovery Threshold" * Add test for getUnloadEvaluatorTypeFromCondition * Hide hysteresis in panel expressions * Refactor isInvalid and add test for it * Remove unnecesary React.memo * Add tests for updateEvaluatorConditions --------- Co-authored-by: Sonia Aguilar <soniaaguilarpeiron@gmail.com>
90 lines
1.7 KiB
Go
90 lines
1.7 KiB
Go
package eval
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand"
|
|
"time"
|
|
|
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
|
|
|
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
|
)
|
|
|
|
type ResultMutator func(r *Result)
|
|
|
|
func RandomState() State {
|
|
return []State{
|
|
Normal,
|
|
Alerting,
|
|
NoData,
|
|
Error,
|
|
}[rand.Intn(4)]
|
|
}
|
|
|
|
func GenerateResults(count int, generator func() Result) Results {
|
|
var result = make(Results, 0, count)
|
|
for i := 0; i < count; i++ {
|
|
result = append(result, generator())
|
|
}
|
|
return result
|
|
}
|
|
|
|
func ResultGen(mutators ...ResultMutator) func() Result {
|
|
return func() Result {
|
|
state := RandomState()
|
|
var err error
|
|
if state == Error {
|
|
err = fmt.Errorf("result_error")
|
|
}
|
|
result := Result{
|
|
Instance: models.GenerateAlertLabels(rand.Intn(5)+1, "result_"),
|
|
State: state,
|
|
Error: err,
|
|
EvaluatedAt: time.Time{},
|
|
EvaluationDuration: time.Duration(rand.Int63n(6)) * time.Second,
|
|
EvaluationString: "",
|
|
Values: nil,
|
|
}
|
|
for _, mutator := range mutators {
|
|
mutator(&result)
|
|
}
|
|
return result
|
|
}
|
|
}
|
|
|
|
func WithEvaluatedAt(time time.Time) ResultMutator {
|
|
return func(r *Result) {
|
|
r.EvaluatedAt = time
|
|
}
|
|
}
|
|
|
|
func WithState(state State) ResultMutator {
|
|
return func(r *Result) {
|
|
r.State = state
|
|
if state == Error {
|
|
r.Error = fmt.Errorf("with_state_error")
|
|
}
|
|
}
|
|
}
|
|
|
|
func WithError(err error) ResultMutator {
|
|
return func(r *Result) {
|
|
r.State = Error
|
|
r.Error = err
|
|
}
|
|
}
|
|
|
|
func WithLabels(labels data.Labels) ResultMutator {
|
|
return func(r *Result) {
|
|
r.Instance = labels
|
|
}
|
|
}
|
|
|
|
type FakeLoadedMetricsReader struct {
|
|
fingerprints map[data.Fingerprint]struct{}
|
|
}
|
|
|
|
func (f FakeLoadedMetricsReader) Read() map[data.Fingerprint]struct{} {
|
|
return f.fingerprints
|
|
}
|