mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Include annotations in prometheus Alert response. (#45970)
* Alerting: Include annotations in prometheus Alert response. * add tests * re-order depedencies
This commit is contained in:
parent
b1e6f7126a
commit
8d4a0a0396
@ -24,7 +24,7 @@ import (
|
|||||||
|
|
||||||
type PrometheusSrv struct {
|
type PrometheusSrv struct {
|
||||||
log log.Logger
|
log log.Logger
|
||||||
manager *state.Manager
|
manager state.AlertInstanceManager
|
||||||
store store.RuleStore
|
store store.RuleStore
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,14 +43,16 @@ func (srv PrometheusSrv) RouteGetAlertStatuses(c *models.ReqContext) response.Re
|
|||||||
if alertState.State == eval.Alerting {
|
if alertState.State == eval.Alerting {
|
||||||
valString = alertState.LastEvaluationString
|
valString = alertState.LastEvaluationString
|
||||||
}
|
}
|
||||||
|
|
||||||
alertResponse.Data.Alerts = append(alertResponse.Data.Alerts, &apimodels.Alert{
|
alertResponse.Data.Alerts = append(alertResponse.Data.Alerts, &apimodels.Alert{
|
||||||
Labels: map[string]string(alertState.Labels),
|
Labels: map[string]string(alertState.Labels),
|
||||||
Annotations: map[string]string{}, //TODO: Once annotations are added to the evaluation result, set them here
|
Annotations: alertState.Annotations,
|
||||||
State: alertState.State.String(),
|
State: alertState.State.String(),
|
||||||
ActiveAt: &startsAt,
|
ActiveAt: &startsAt,
|
||||||
Value: valString,
|
Value: valString,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.JSON(http.StatusOK, alertResponse)
|
return response.JSON(http.StatusOK, alertResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
80
pkg/services/ngalert/api/api_prometheus_test.go
Normal file
80
pkg/services/ngalert/api/api_prometheus_test.go
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
|
"github.com/grafana/grafana/pkg/models"
|
||||||
|
"github.com/grafana/grafana/pkg/services/ngalert/store"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRouteGetAlertStatuses(t *testing.T) {
|
||||||
|
fakeStore := store.NewFakeRuleStore(t)
|
||||||
|
fakeAlertInstanceManager := NewFakeAlertInstanceManager(t)
|
||||||
|
orgID := int64(1)
|
||||||
|
|
||||||
|
server := PrometheusSrv{
|
||||||
|
log: log.NewNopLogger(),
|
||||||
|
manager: fakeAlertInstanceManager,
|
||||||
|
store: fakeStore,
|
||||||
|
}
|
||||||
|
|
||||||
|
c := &models.ReqContext{SignedInUser: &models.SignedInUser{OrgId: orgID}}
|
||||||
|
|
||||||
|
t.Run("with no alerts", func(t *testing.T) {
|
||||||
|
r := server.RouteGetAlertStatuses(c)
|
||||||
|
require.Equal(t, http.StatusOK, r.Status())
|
||||||
|
require.JSONEq(t, `
|
||||||
|
{
|
||||||
|
"status": "success",
|
||||||
|
"data": {
|
||||||
|
"alerts": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`, string(r.Body()))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("with two alerts", func(t *testing.T) {
|
||||||
|
fakeAlertInstanceManager.GenerateAlertInstances(1, 2)
|
||||||
|
r := server.RouteGetAlertStatuses(c)
|
||||||
|
require.Equal(t, http.StatusOK, r.Status())
|
||||||
|
require.JSONEq(t, `
|
||||||
|
{
|
||||||
|
"status": "success",
|
||||||
|
"data": {
|
||||||
|
"alerts": [{
|
||||||
|
"labels": {
|
||||||
|
"__alert_rule_namespace_uid__": "test_namespace_uid",
|
||||||
|
"__alert_rule_uid__": "test_alert_rule_uid_0",
|
||||||
|
"alertname": "test_title_0",
|
||||||
|
"instance_label": "test",
|
||||||
|
"label": "test"
|
||||||
|
},
|
||||||
|
"annotations": {
|
||||||
|
"annotation": "test"
|
||||||
|
},
|
||||||
|
"state": "Normal",
|
||||||
|
"activeAt": "0001-01-01T00:00:00Z",
|
||||||
|
"value": ""
|
||||||
|
}, {
|
||||||
|
"labels": {
|
||||||
|
"__alert_rule_namespace_uid__": "test_namespace_uid",
|
||||||
|
"__alert_rule_uid__": "test_alert_rule_uid_1",
|
||||||
|
"alertname": "test_title_1",
|
||||||
|
"instance_label": "test",
|
||||||
|
"label": "test"
|
||||||
|
},
|
||||||
|
"annotations": {
|
||||||
|
"annotation": "test"
|
||||||
|
},
|
||||||
|
"state": "Normal",
|
||||||
|
"activeAt": "0001-01-01T00:00:00Z",
|
||||||
|
"value": ""
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}`, string(r.Body()))
|
||||||
|
})
|
||||||
|
}
|
@ -2,10 +2,18 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/services/ngalert/eval"
|
||||||
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||||
|
"github.com/grafana/grafana/pkg/services/ngalert/state"
|
||||||
"github.com/grafana/grafana/pkg/services/ngalert/store"
|
"github.com/grafana/grafana/pkg/services/ngalert/store"
|
||||||
|
"github.com/grafana/grafana/pkg/util"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FakeAlertingStore struct {
|
type FakeAlertingStore struct {
|
||||||
@ -30,3 +38,85 @@ func (f FakeAlertingStore) GetLatestAlertmanagerConfiguration(_ context.Context,
|
|||||||
}
|
}
|
||||||
return store.ErrNoAlertmanagerConfiguration
|
return store.ErrNoAlertmanagerConfiguration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type fakeAlertInstanceManager struct {
|
||||||
|
mtx sync.Mutex
|
||||||
|
// orgID -> RuleID -> States
|
||||||
|
states map[int64]map[string][]*state.State
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFakeAlertInstanceManager(t *testing.T) *fakeAlertInstanceManager {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
return &fakeAlertInstanceManager{
|
||||||
|
states: map[int64]map[string][]*state.State{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fakeAlertInstanceManager) GetAll(orgID int64) []*state.State {
|
||||||
|
f.mtx.Lock()
|
||||||
|
defer f.mtx.Unlock()
|
||||||
|
var s []*state.State
|
||||||
|
|
||||||
|
for orgID := range f.states {
|
||||||
|
for _, states := range f.states[orgID] {
|
||||||
|
s = append(s, states...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fakeAlertInstanceManager) GetStatesForRuleUID(orgID int64, alertRuleUID string) []*state.State {
|
||||||
|
f.mtx.Lock()
|
||||||
|
defer f.mtx.Unlock()
|
||||||
|
return f.states[orgID][alertRuleUID]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fakeAlertInstanceManager) GenerateAlertInstances(orgID int64, count int) {
|
||||||
|
f.mtx.Lock()
|
||||||
|
defer f.mtx.Unlock()
|
||||||
|
|
||||||
|
evaluationTime := time.Now()
|
||||||
|
evaluationDuration := 1 * time.Minute
|
||||||
|
alertRuleUID := util.GenerateShortUID()
|
||||||
|
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
_, ok := f.states[orgID]
|
||||||
|
if !ok {
|
||||||
|
f.states[orgID] = map[string][]*state.State{}
|
||||||
|
}
|
||||||
|
_, ok = f.states[orgID][alertRuleUID]
|
||||||
|
if !ok {
|
||||||
|
f.states[orgID][alertRuleUID] = []*state.State{}
|
||||||
|
}
|
||||||
|
|
||||||
|
f.states[orgID][alertRuleUID] = append(f.states[orgID][alertRuleUID], &state.State{
|
||||||
|
AlertRuleUID: fmt.Sprintf("alert_rule_%v", i),
|
||||||
|
OrgID: 1,
|
||||||
|
Labels: data.Labels{
|
||||||
|
"__alert_rule_namespace_uid__": "test_namespace_uid",
|
||||||
|
"__alert_rule_uid__": fmt.Sprintf("test_alert_rule_uid_%v", i),
|
||||||
|
"alertname": fmt.Sprintf("test_title_%v", i),
|
||||||
|
"label": "test",
|
||||||
|
"instance_label": "test",
|
||||||
|
},
|
||||||
|
State: eval.Normal,
|
||||||
|
Results: []state.Evaluation{
|
||||||
|
{
|
||||||
|
EvaluationTime: evaluationTime,
|
||||||
|
EvaluationState: eval.Normal,
|
||||||
|
Values: make(map[string]*float64),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
EvaluationTime: evaluationTime.Add(1 * time.Minute),
|
||||||
|
EvaluationState: eval.Normal,
|
||||||
|
Values: make(map[string]*float64),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LastEvaluationTime: evaluationTime.Add(1 * time.Minute),
|
||||||
|
EvaluationDuration: evaluationDuration,
|
||||||
|
Annotations: map[string]string{"annotation": "test"},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -22,6 +22,12 @@ import (
|
|||||||
|
|
||||||
var ResendDelay = 30 * time.Second
|
var ResendDelay = 30 * time.Second
|
||||||
|
|
||||||
|
// AlertInstanceManager defines the interface for querying the current alert instances.
|
||||||
|
type AlertInstanceManager interface {
|
||||||
|
GetAll(orgID int64) []*State
|
||||||
|
GetStatesForRuleUID(orgID int64, alertRuleUID string) []*State
|
||||||
|
}
|
||||||
|
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
log log.Logger
|
log log.Logger
|
||||||
metrics *metrics.State
|
metrics *metrics.State
|
||||||
|
Loading…
Reference in New Issue
Block a user