Skip to content

Commit

Permalink
Add keep_firing_for support to alerting rule (#6943)
Browse files Browse the repository at this point in the history
* Add keep_firing_for to alert rules

Signed-off-by: JHeil <[email protected]>

* Updating changelog

Signed-off-by: JHeil <[email protected]>

* Re-order keepFiringFor at the end of the struct

Signed-off-by: JHeil <[email protected]>

---------

Signed-off-by: JHeil <[email protected]>
Signed-off-by: JHeil <[email protected]>
  • Loading branch information
JHeilCoveo authored Dec 7, 2023
1 parent 07e43ca commit 5d4fc6d
Show file tree
Hide file tree
Showing 17 changed files with 263 additions and 76 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ We use *breaking :warning:* to mark changes that are not backward compatible (re
- [#6453](https://github.com/thanos-io/thanos/pull/6453) Sidecar: Added `--reloader.method` to support configuration reloads via SIHUP signal.
- [#6925](https://github.com/thanos-io/thanos/pull/6925) Store Gateway: Support float native histogram.
- [#6954](https://github.com/thanos-io/thanos/pull/6954) Index Cache: Support tracing for fetch APIs.
- [#6943](https://github.com/thanos-io/thanos/pull/6943) Ruler: Added `keep_firing_for` field in alerting rule.

### Changed

Expand Down
4 changes: 4 additions & 0 deletions docs/components/rule.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ expr: <string>
# Alerts which have not yet fired for long enough are considered pending.
[ for: <duration> | default = 0s ]
# How long an alert will continue firing after the condition that triggered it
# has cleared.
[ keep_firing_for: <duration> | default = 0s ]
# Labels to add or overwrite for each alert.
labels:
[ <labelname>: <tmpl_string> ]
Expand Down
30 changes: 30 additions & 0 deletions pkg/api/query/v1_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1720,6 +1720,7 @@ func TestRulesHandler(t *testing.T) {
Health: "x",
Query: "sum(up2) == 2",
DurationSeconds: 101,
KeepFiringForSeconds: 102,
Labels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{{Name: "some", Value: "label3"}}},
Annotations: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{{Name: "ann", Value: "a1"}}},
Alerts: []*rulespb.AlertInstance{
Expand Down Expand Up @@ -1750,10 +1751,22 @@ func TestRulesHandler(t *testing.T) {
EvaluationDurationSeconds: 122,
Health: "x",
DurationSeconds: 102,
KeepFiringForSeconds: 103,
Query: "sum(up3) == 3",
Labels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{{Name: "some", Value: "label4"}}},
State: rulespb.AlertState_INACTIVE,
}),
rulespb.NewAlertingRule(&rulespb.Alert{
Name: "5",
LastEvaluation: time.Time{}.Add(4 * time.Minute),
EvaluationDurationSeconds: 122,
Health: "x",
DurationSeconds: 61,
KeepFiringForSeconds: 62,
Query: "sum(up4) == 4",
Labels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{{Name: "some", Value: "label5"}}},
State: rulespb.AlertState_INACTIVE,
}),
}

endpoint := NewRulesHandler(mockedRulesClient{
Expand Down Expand Up @@ -1839,6 +1852,7 @@ func TestRulesHandler(t *testing.T) {
LastEvaluation: all[2].GetAlert().LastEvaluation,
EvaluationTime: all[2].GetAlert().EvaluationDurationSeconds,
Duration: all[2].GetAlert().DurationSeconds,
KeepFiringFor: all[2].GetAlert().KeepFiringForSeconds,
Annotations: labelpb.ZLabelsToPromLabels(all[2].GetAlert().Annotations.Labels),
Alerts: []*testpromcompatibility.Alert{
{
Expand Down Expand Up @@ -1870,6 +1884,22 @@ func TestRulesHandler(t *testing.T) {
LastEvaluation: all[3].GetAlert().LastEvaluation,
EvaluationTime: all[3].GetAlert().EvaluationDurationSeconds,
Duration: all[3].GetAlert().DurationSeconds,
KeepFiringFor: all[3].GetAlert().KeepFiringForSeconds,
Annotations: nil,
Alerts: []*testpromcompatibility.Alert{},
Type: "alerting",
},
testpromcompatibility.AlertingRule{
State: strings.ToLower(all[4].GetAlert().State.String()),
Name: all[4].GetAlert().Name,
Query: all[4].GetAlert().Query,
Labels: labelpb.ZLabelsToPromLabels(all[4].GetAlert().Labels.Labels),
Health: rules.RuleHealth(all[2].GetAlert().Health),
LastError: all[4].GetAlert().LastError,
LastEvaluation: all[4].GetAlert().LastEvaluation,
EvaluationTime: all[4].GetAlert().EvaluationDurationSeconds,
Duration: all[4].GetAlert().DurationSeconds,
KeepFiringFor: all[4].GetAlert().KeepFiringForSeconds,
Annotations: nil,
Alerts: []*testpromcompatibility.Alert{},
Type: "alerting",
Expand Down
1 change: 1 addition & 0 deletions pkg/rules/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ func (g Group) toProto() *rulespb.RuleGroup {
Name: rule.Name(),
Query: rule.Query().String(),
DurationSeconds: rule.HoldDuration().Seconds(),
KeepFiringForSeconds: rule.KeepFiringFor().Seconds(),
Labels: labelpb.ZLabelSet{Labels: labelpb.ZLabelsFromPromLabels(rule.Labels())},
Annotations: labelpb.ZLabelSet{Labels: labelpb.ZLabelsFromPromLabels(rule.Annotations())},
Alerts: ActiveAlertsToProto(g.PartialResponseStrategy, rule),
Expand Down
6 changes: 4 additions & 2 deletions pkg/rules/rulespb/custom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ func TestJSONUnmarshalMarshal(t *testing.T) {
},
},
},
expectedErr: errors.New("rule: alerting rule unmarshal: {\"state\":\"sdfsdf\",\"name\":\"alert1\",\"query\":\"\",\"duration\":0,\"labels\":{},\"annotations\":{},\"alerts\":null,\"health\":\"\",\"evaluationTime\":0,\"lastEvaluation\":\"0001-01-01T00:00:00Z\",\"type\":\"alerting\"}: unknown alertState: \"sdfsdf\""),
expectedErr: errors.New("rule: alerting rule unmarshal: {\"state\":\"sdfsdf\",\"name\":\"alert1\",\"query\":\"\",\"duration\":0,\"labels\":{},\"annotations\":{},\"alerts\":null,\"health\":\"\",\"evaluationTime\":0,\"lastEvaluation\":\"0001-01-01T00:00:00Z\",\"keepFiringFor\":0,\"type\":\"alerting\"}: unknown alertState: \"sdfsdf\""),
},
{
name: "one group with WRONG partial response fields",
Expand Down Expand Up @@ -180,6 +180,7 @@ func TestJSONUnmarshalMarshal(t *testing.T) {
Health: "health2",
LastError: "1",
Duration: 60,
KeepFiringFor: 0,
State: "pending",
EvaluationTime: 1.1,
},
Expand Down Expand Up @@ -212,6 +213,7 @@ func TestJSONUnmarshalMarshal(t *testing.T) {
},
},
DurationSeconds: 60,
KeepFiringForSeconds: 0,
State: AlertState_PENDING,
LastError: "1",
Health: "health2",
Expand All @@ -226,7 +228,7 @@ func TestJSONUnmarshalMarshal(t *testing.T) {
},
},
// Different than input due to the alerts slice being initialized to a zero-length slice instead of nil.
expectedJSONOutput: `{"groups":[{"name":"group1","file":"file1.yml","rules":[{"state":"pending","name":"alert1","query":"up == 0","duration":60,"labels":{"a2":"b2","c2":"d2"},"annotations":{"ann1":"ann44","ann2":"ann33"},"alerts":[],"health":"health2","lastError":"1","evaluationTime":1.1,"lastEvaluation":"0001-01-01T00:00:00Z","type":"alerting"}],"interval":2442,"evaluationTime":2.1,"lastEvaluation":"0001-01-01T00:00:00Z","limit":0,"partialResponseStrategy":"ABORT"}]}`,
expectedJSONOutput: `{"groups":[{"name":"group1","file":"file1.yml","rules":[{"state":"pending","name":"alert1","query":"up == 0","duration":60,"labels":{"a2":"b2","c2":"d2"},"annotations":{"ann1":"ann44","ann2":"ann33"},"alerts":[],"health":"health2","lastError":"1","evaluationTime":1.1,"lastEvaluation":"0001-01-01T00:00:00Z","keepFiringFor":0,"type":"alerting"}],"interval":2442,"evaluationTime":2.1,"lastEvaluation":"0001-01-01T00:00:00Z","limit":0,"partialResponseStrategy":"ABORT"}]}`,
},
{
name: "one valid group, with 1 rule and alert each and second empty group.",
Expand Down
Loading

0 comments on commit 5d4fc6d

Please sign in to comment.