diff --git a/rules/alerting.go b/rules/alerting.go index 730e5a76f..e862ee241 100644 --- a/rules/alerting.go +++ b/rules/alerting.go @@ -311,7 +311,7 @@ const resolvedRetention = 15 * time.Minute // Eval evaluates the rule expression and then creates pending alerts and fires // or removes previously pending alerts accordingly. func (r *AlertingRule) Eval(ctx context.Context, ts time.Time, query QueryFunc, externalURL *url.URL, limit int) (promql.Vector, error) { - ctx = NewOriginContext(ctx, NewRuleDetail(r.Name(), r.Query().String(), KindAlerting)) + ctx = NewOriginContext(ctx, NewRuleDetail(r)) res, err := query(ctx, r.vector.String(), ts) if err != nil { diff --git a/rules/alerting_test.go b/rules/alerting_test.go index bc41c0ff1..6e6b72bce 100644 --- a/rules/alerting_test.go +++ b/rules/alerting_test.go @@ -713,14 +713,19 @@ func TestSendAlertsDontAffectActiveAlerts(t *testing.T) { require.Equal(t, labels.FromStrings("a1", "1"), rule.active[h].Labels) } +// TestAlertingEvalWithOrigin checks that the alerting rule details are passed through the context. func TestAlertingEvalWithOrigin(t *testing.T) { ctx := context.Background() now := time.Now() - const name = "my-recording-rule" - const query = `count(metric{foo="bar"}) > 0` - - var detail RuleDetail + const ( + name = "my-recording-rule" + query = `count(metric{foo="bar"}) > 0` + ) + var ( + detail RuleDetail + lbs = labels.FromStrings("test", "test") + ) expr, err := parser.ParseExpr(query) require.NoError(t, err) @@ -729,7 +734,7 @@ func TestAlertingEvalWithOrigin(t *testing.T) { name, expr, time.Minute, - labels.FromStrings("test", "test"), + lbs, nil, nil, "", @@ -742,5 +747,5 @@ func TestAlertingEvalWithOrigin(t *testing.T) { }, nil, 0) require.NoError(t, err) - require.Equal(t, detail, NewRuleDetail(name, query, KindAlerting)) + require.Equal(t, detail, NewRuleDetail(rule)) } diff --git a/rules/origin.go b/rules/origin.go index e78a07de5..edc7471c1 100644 --- a/rules/origin.go +++ b/rules/origin.go @@ -1,13 +1,19 @@ package rules -import "context" +import ( + "context" + + "github.com/prometheus/prometheus/model/labels" +) type ruleOrigin struct{} +// RuleDetail contains information about the rule that is being evaluated. type RuleDetail struct { - Name string - Kind string - Query string + Name string + Query string + Labels labels.Labels + Kind string } const ( @@ -15,11 +21,23 @@ const ( KindRecording = "recording" ) -func NewRuleDetail(name, query, kind string) RuleDetail { +// NewRuleDetail creates a RuleDetail from a given Rule. +func NewRuleDetail(r Rule) RuleDetail { + var kind string + switch r.(type) { + case *AlertingRule: + kind = KindAlerting + case *RecordingRule: + kind = KindRecording + default: + kind = "unknown" + } + return RuleDetail{ - Name: name, - Query: query, - Kind: kind, + Name: r.Name(), + Query: r.Query().String(), + Labels: r.Labels(), + Kind: kind, } } @@ -28,6 +46,7 @@ func NewOriginContext(ctx context.Context, rule RuleDetail) context.Context { return context.WithValue(ctx, ruleOrigin{}, rule) } +// FromOriginContext returns the RuleDetail origin data from the context. func FromOriginContext(ctx context.Context) RuleDetail { if rule, ok := ctx.Value(ruleOrigin{}).(RuleDetail); ok { return rule diff --git a/rules/recording.go b/rules/recording.go index 81ca47c91..49ffa2d6d 100644 --- a/rules/recording.go +++ b/rules/recording.go @@ -73,7 +73,7 @@ func (rule *RecordingRule) Labels() labels.Labels { // Eval evaluates the rule and then overrides the metric names and labels accordingly. func (rule *RecordingRule) Eval(ctx context.Context, ts time.Time, query QueryFunc, _ *url.URL, limit int) (promql.Vector, error) { - ctx = NewOriginContext(ctx, NewRuleDetail(rule.Name(), rule.Query().String(), KindRecording)) + ctx = NewOriginContext(ctx, NewRuleDetail(rule)) vector, err := query(ctx, rule.vector.String(), ts) if err != nil { diff --git a/rules/recording_test.go b/rules/recording_test.go index 54c391215..ea33fbdd6 100644 --- a/rules/recording_test.go +++ b/rules/recording_test.go @@ -157,24 +157,30 @@ func TestRecordingRuleLimit(t *testing.T) { } } +// TestRecordingEvalWithOrigin checks that the recording rule details are passed through the context. func TestRecordingEvalWithOrigin(t *testing.T) { ctx := context.Background() now := time.Now() - const name = "my-recording-rule" - const query = `count(metric{foo="bar"})` + const ( + name = "my-recording-rule" + query = `count(metric{foo="bar"})` + ) - var detail RuleDetail + var ( + detail RuleDetail + lbs = labels.FromStrings("foo", "bar") + ) expr, err := parser.ParseExpr(query) require.NoError(t, err) - rule := NewRecordingRule(name, expr, []labels.Label{}) + rule := NewRecordingRule(name, expr, lbs) _, err = rule.Eval(ctx, now, func(ctx context.Context, qs string, _ time.Time) (promql.Vector, error) { detail = FromOriginContext(ctx) return nil, nil }, nil, 0) require.NoError(t, err) - require.Equal(t, detail, NewRuleDetail(name, query, KindRecording)) + require.Equal(t, detail, NewRuleDetail(rule)) }