From 7ff49ba47c2e795643310a7d7e04d82f0819a57c Mon Sep 17 00:00:00 2001 From: Amol Umbark Date: Wed, 3 Aug 2022 15:08:14 +0530 Subject: [PATCH] feat: added rule url to the title link in slack message (#1421) * feat: added rule url to the title link in slack message * fix: corrected duplication of code for generator url in rules engine * fix: removed unnecessary import in rules engine --- pkg/query-service/rules/alerting.go | 33 ++++++++++++++++++++++++ pkg/query-service/rules/promRule.go | 2 +- pkg/query-service/rules/templates.go | 3 +++ pkg/query-service/rules/thresholdRule.go | 14 +++++----- 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/pkg/query-service/rules/alerting.go b/pkg/query-service/rules/alerting.go index a4768b4036..66435baf36 100644 --- a/pkg/query-service/rules/alerting.go +++ b/pkg/query-service/rules/alerting.go @@ -2,12 +2,18 @@ package rules import ( "encoding/json" + "fmt" "github.com/pkg/errors" "go.signoz.io/query-service/model" "go.signoz.io/query-service/utils/labels" + "net/url" + "strings" "time" ) +// this file contains common structs and methods used by +// rule engine + // how long before re-sending the alert const resolvedRetention = 15 * time.Minute @@ -198,3 +204,30 @@ func (d *Duration) UnmarshalJSON(b []byte) error { return errors.New("invalid duration") } } + +// prepareRuleGeneratorURL creates an appropriate url +// for the rule. the URL is sent in slack messages as well as +// to other systems and allows backtracking to the rule definition +// from the third party systems. +func prepareRuleGeneratorURL(ruleId string, source string) string { + if source == "" { + return source + } + + // check if source is a valid url + _, err := url.Parse(source) + if err != nil { + return "" + } + // since we capture window.location when a new rule is created + // we end up with rulesource host:port/alerts/new. in this case + // we want to replace new with rule id parameter + + hasNew := strings.LastIndex(source, "new") + if hasNew > -1 { + ruleURL := fmt.Sprintf("%sedit?ruleId=%s", source[0:hasNew], ruleId) + return ruleURL + } + + return source +} diff --git a/pkg/query-service/rules/promRule.go b/pkg/query-service/rules/promRule.go index 669d6e3845..f2ceff1a1a 100644 --- a/pkg/query-service/rules/promRule.go +++ b/pkg/query-service/rules/promRule.go @@ -96,7 +96,7 @@ func (r *PromRule) Type() RuleType { } func (r *PromRule) GeneratorURL() string { - return r.source + return prepareRuleGeneratorURL(r.ID(), r.source) } func (r *PromRule) SetLastError(err error) { diff --git a/pkg/query-service/rules/templates.go b/pkg/query-service/rules/templates.go index 4789780ffc..3d9aa518d8 100644 --- a/pkg/query-service/rules/templates.go +++ b/pkg/query-service/rules/templates.go @@ -17,6 +17,9 @@ import ( "go.signoz.io/query-service/utils/times" ) +// this file contains all the methods and structs +// related to go templating in rule labels and annotations + type tmplQueryRecord struct { Labels map[string]string Value float64 diff --git a/pkg/query-service/rules/thresholdRule.go b/pkg/query-service/rules/thresholdRule.go index 8f734c113d..3358842051 100644 --- a/pkg/query-service/rules/thresholdRule.go +++ b/pkg/query-service/rules/thresholdRule.go @@ -63,9 +63,7 @@ func NewThresholdRule( return nil, fmt.Errorf("invalid rule condition") } - zap.S().Info("msg:", "creating new alerting rule", "\t name:", name, "\t condition:", ruleCondition.String()) - - return &ThresholdRule{ + thresholdRule := &ThresholdRule{ id: id, name: name, source: source, @@ -76,7 +74,11 @@ func NewThresholdRule( health: HealthUnknown, active: map[uint64]*Alert{}, - }, nil + } + + zap.S().Info("msg:", "creating new alerting rule", "\t name:", name, "\t condition:", ruleCondition.String(), "\t generatorURL:", thresholdRule.GeneratorURL()) + + return thresholdRule, nil } func (r *ThresholdRule) Name() string { @@ -92,7 +94,7 @@ func (r *ThresholdRule) Condition() *RuleCondition { } func (r *ThresholdRule) GeneratorURL() string { - return r.source + return prepareRuleGeneratorURL(r.ID(), r.source) } func (r *ThresholdRule) target() *float64 { @@ -231,9 +233,9 @@ func (r *ThresholdRule) GetEvaluationTimestamp() time.Time { // State returns the maximum state of alert instances for this rule. // StateFiring > StatePending > StateInactive func (r *ThresholdRule) State() AlertState { + r.mtx.Lock() defer r.mtx.Unlock() - maxState := StateInactive for _, a := range r.active { if a.State > maxState {