web/api: Expose rule health and last error (#4501)

Expose rule health and last evaluation error on `/api/v1/rules`.

Signed-off-by: Max Leonard Inden <IndenML@gmail.com>
This commit is contained in:
Max Inden 2018-08-23 15:00:10 +02:00 committed by Goutham Veeramachaneni
parent 12fe204ea6
commit ecf676cf97
3 changed files with 31 additions and 13 deletions

View file

@ -406,6 +406,7 @@ $ curl http://localhost:9090/api/v1/rules
"summary": "High request latency"
},
"duration": 600,
"health": "ok",
"labels": {
"severity": "page"
},
@ -414,6 +415,7 @@ $ curl http://localhost:9090/api/v1/rules
"type": "alerting"
},
{
"health": "ok",
"name": "job:http_inprogress_requests:sum",
"query": "sum(http_inprogress_requests) by (job)",
"type": "recording"

View file

@ -655,20 +655,24 @@ type RuleGroup struct {
type rule interface{}
type alertingRule struct {
Name string `json:"name"`
Query string `json:"query"`
Duration float64 `json:"duration"`
Labels labels.Labels `json:"labels"`
Annotations labels.Labels `json:"annotations"`
Alerts []*Alert `json:"alerts"`
Name string `json:"name"`
Query string `json:"query"`
Duration float64 `json:"duration"`
Labels labels.Labels `json:"labels"`
Annotations labels.Labels `json:"annotations"`
Alerts []*Alert `json:"alerts"`
Health rules.RuleHealth `json:"health"`
LastError string `json:"lastError,omitempty"`
// Type of an alertingRule is always "alerting".
Type string `json:"type"`
}
type recordingRule struct {
Name string `json:"name"`
Query string `json:"query"`
Labels labels.Labels `json:"labels,omitempty"`
Name string `json:"name"`
Query string `json:"query"`
Labels labels.Labels `json:"labels,omitempty"`
Health rules.RuleHealth `json:"health"`
LastError string `json:"lastError,omitempty"`
// Type of a recordingRule is always "recording".
Type string `json:"type"`
}
@ -687,6 +691,11 @@ func (api *API) rules(r *http.Request) (interface{}, *apiError, func()) {
for _, r := range grp.Rules() {
var enrichedRule rule
lastError := ""
if r.LastError() != nil {
lastError = r.LastError().Error()
}
switch rule := r.(type) {
case *rules.AlertingRule:
enrichedRule = alertingRule{
@ -696,14 +705,18 @@ func (api *API) rules(r *http.Request) (interface{}, *apiError, func()) {
Labels: rule.Labels(),
Annotations: rule.Annotations(),
Alerts: rulesAlertsToAPIAlerts(rule.ActiveAlerts()),
Health: rule.Health(),
LastError: lastError,
Type: "alerting",
}
case *rules.RecordingRule:
enrichedRule = recordingRule{
Name: rule.Name(),
Query: rule.Query().String(),
Labels: rule.Labels(),
Type: "recording",
Name: rule.Name(),
Query: rule.Query().String(),
Labels: rule.Labels(),
Health: rule.Health(),
LastError: lastError,
Type: "recording",
}
default:
err := fmt.Errorf("failed to assert type of rule '%v'", rule.Name())

View file

@ -681,6 +681,7 @@ func testEndpoints(t *testing.T, api *API, testLabelAPI bool) {
Labels: labels.Labels{},
Annotations: labels.Labels{},
Alerts: []*Alert{},
Health: "unknown",
Type: "alerting",
},
alertingRule{
@ -690,12 +691,14 @@ func testEndpoints(t *testing.T, api *API, testLabelAPI bool) {
Labels: labels.Labels{},
Annotations: labels.Labels{},
Alerts: []*Alert{},
Health: "unknown",
Type: "alerting",
},
recordingRule{
Name: "recording-rule-1",
Query: "vector(1)",
Labels: labels.Labels{},
Health: "unknown",
Type: "recording",
},
},