@@ -16,6 +16,7 @@ package inhibit
1616import (
1717 "context"
1818 "log/slog"
19+ "strings"
1920 "sync"
2021 "time"
2122
@@ -87,14 +88,31 @@ func (ih *Inhibitor) run(ctx context.Context) {
8788 cachedSum := 0
8889 indexedSum := 0
8990 for _ , r := range ih .rules {
90- if r .SourceMatchers .Matches (a .Labels ) {
91- if err := r .scache .Set (a ); err != nil {
92- ih .logger .Error ("error on set alert" , "err" , err )
93- continue
91+ if len (r .Sources ) > 0 {
92+ allSrcMatched := true
93+ for _ , src := range r .Sources {
94+ if ! src .SrcMatchers .Matches (a .Labels ) {
95+ allSrcMatched = false
96+ break
97+ }
98+ }
99+ if allSrcMatched {
100+ if err := r .scache .Set (a ); err != nil {
101+ ih .logger .Error ("error on set alert" , "err" , err )
102+ continue
103+ }
104+ r .updateIndex (a )
105+ }
106+ } else {
107+ if r .SourceMatchers .Matches (a .Labels ) {
108+ if err := r .scache .Set (a ); err != nil {
109+ ih .logger .Error ("error on set alert" , "err" , err )
110+ continue
111+ }
112+ r .updateIndex (a )
94113 }
95- r .updateIndex (a )
96-
97114 }
115+
98116 cached := r .scache .Len ()
99117 indexed := r .sindex .Len ()
100118
@@ -169,23 +187,58 @@ func (ih *Inhibitor) Mutes(lset model.LabelSet) bool {
169187 r .metrics .matchesDurationMatched .Observe (time .Since (ruleStart ).Seconds ())
170188 // If we are here, the target side matches. If the source side matches, too, we
171189 // need to exclude inhibiting alerts for which the same is true.
172- if inhibitedByFP , eq := r .hasEqual (lset , r .SourceMatchers .Matches (lset ), ruleStart ); eq {
173- ih .marker .SetInhibited (fp , inhibitedByFP .String ())
174- now := time .Now ()
175- sinceStart := now .Sub (start )
176- sinceRuleStart := now .Sub (ruleStart )
177- ih .metrics .mutesDurationMuted .Observe (sinceStart .Seconds ())
178- r .metrics .mutesDurationMuted .Observe (sinceRuleStart .Seconds ())
179- return true
190+
191+ if len (r .Sources ) > 0 {
192+ allSourcesMatched := true
193+ var inhibitorIDs []string
194+ for _ , source := range r .Sources {
195+ if inhibitedByFP , eq := r .hasEqual (lset , source .SrcMatchers .Matches (lset ), ruleStart ); eq {
196+ inhibitorIDs = append (inhibitorIDs , inhibitedByFP .String ())
197+ } else {
198+ allSourcesMatched = false
199+ break
200+ }
201+ }
202+ if allSourcesMatched {
203+ compositeInhibitorID := strings .Join (inhibitorIDs , "," )
204+ ih .marker .SetInhibited (fp , compositeInhibitorID )
205+ now := time .Now ()
206+ sinceStart := now .Sub (start )
207+ sinceRuleStart := now .Sub (ruleStart )
208+ ih .metrics .mutesDurationMuted .Observe (sinceStart .Seconds ())
209+ r .metrics .mutesDurationMuted .Observe (sinceRuleStart .Seconds ())
210+ return true
211+ }
212+ } else {
213+ if inhibitedByFP , eq := r .hasEqual (lset , r .SourceMatchers .Matches (lset ), ruleStart ); eq {
214+ ih .marker .SetInhibited (fp , inhibitedByFP .String ())
215+ now := time .Now ()
216+ sinceStart := now .Sub (start )
217+ sinceRuleStart := now .Sub (ruleStart )
218+ ih .metrics .mutesDurationMuted .Observe (sinceStart .Seconds ())
219+ r .metrics .mutesDurationMuted .Observe (sinceRuleStart .Seconds ())
220+ return true
221+ }
222+
180223 }
181224 r .metrics .mutesDurationNotMuted .Observe (time .Since (ruleStart ).Seconds ())
182225 }
226+
183227 ih .marker .SetInhibited (fp )
184228 ih .metrics .mutesDurationNotMuted .Observe (time .Since (start ).Seconds ())
185229
186230 return false
187231}
188232
233+ type Source struct {
234+ // The set of Filters which define the group of source alerts (which inhibit
235+ // the target alerts).
236+ SrcMatchers labels.Matchers
237+ // A set of label names whose label values need to be identical in source and
238+ // target alerts in order for the inhibition to take effect.
239+ Equal map [model.LabelName ]struct {}
240+ }
241+
189242// An InhibitRule specifies that a class of (source) alerts should inhibit
190243// notifications for another class of (target) alerts if all specified matching
191244// labels are equal between the two alerts. This may be used to inhibit alerts
@@ -197,6 +250,7 @@ type InhibitRule struct {
197250 // The set of Filters which define the group of source alerts (which inhibit
198251 // the target alerts).
199252 SourceMatchers labels.Matchers
253+ Sources []Source
200254 // The set of Filters which define the group of target alerts (which are
201255 // inhibited by the source alerts).
202256 TargetMatchers labels.Matchers
@@ -219,30 +273,46 @@ type InhibitRule struct {
219273// NewInhibitRule returns a new InhibitRule based on a configuration definition.
220274func NewInhibitRule (cr config.InhibitRule , metrics * RuleMetrics ) * InhibitRule {
221275 var (
276+ sources []Source
222277 sourcem labels.Matchers
223278 targetm labels.Matchers
224279 )
225280
226- // cr.SourceMatch will be deprecated. This for loop appends regex matchers.
227- for ln , lv := range cr .SourceMatch {
228- matcher , err := labels .NewMatcher (labels .MatchEqual , ln , lv )
229- if err != nil {
230- // This error must not happen because the config already validates the yaml.
231- panic (err )
281+ if len (cr .Sources ) > 0 {
282+ for _ , sm := range cr .Sources {
283+ sourcem = append (sourcem , sm .SrcMatchers ... )
284+ equal := map [model.LabelName ]struct {}{}
285+ for _ , ln := range sm .Equal {
286+ equal [model .LabelName (ln )] = struct {}{}
287+ }
288+ sources = append (sources , Source {
289+ SrcMatchers : sourcem ,
290+ Equal : equal ,
291+ })
232292 }
233- sourcem = append (sourcem , matcher )
234- }
235- // cr.SourceMatchRE will be deprecated. This for loop appends regex matchers.
236- for ln , lv := range cr .SourceMatchRE {
237- matcher , err := labels .NewMatcher (labels .MatchRegexp , ln , lv .String ())
238- if err != nil {
239- // This error must not happen because the config already validates the yaml.
240- panic (err )
293+ } else {
294+
295+ // cr.SourceMatch will be deprecated. This for loop appends regex matchers.
296+ for ln , lv := range cr .SourceMatch {
297+ matcher , err := labels .NewMatcher (labels .MatchEqual , ln , lv )
298+ if err != nil {
299+ // This error must not happen because the config already validates the yaml.
300+ panic (err )
301+ }
302+ sourcem = append (sourcem , matcher )
241303 }
242- sourcem = append (sourcem , matcher )
304+ // cr.SourceMatchRE will be deprecated. This for loop appends regex matchers.
305+ for ln , lv := range cr .SourceMatchRE {
306+ matcher , err := labels .NewMatcher (labels .MatchRegexp , ln , lv .String ())
307+ if err != nil {
308+ // This error must not happen because the config already validates the yaml.
309+ panic (err )
310+ }
311+ sourcem = append (sourcem , matcher )
312+ }
313+ // We append the new-style matchers. This can be simplified once the deprecated matcher syntax is removed.
314+ sourcem = append (sourcem , cr .SourceMatchers ... )
243315 }
244- // We append the new-style matchers. This can be simplified once the deprecated matcher syntax is removed.
245- sourcem = append (sourcem , cr .SourceMatchers ... )
246316
247317 // cr.TargetMatch will be deprecated. This for loop appends regex matchers.
248318 for ln , lv := range cr .TargetMatch {
@@ -278,6 +348,7 @@ func NewInhibitRule(cr config.InhibitRule, metrics *RuleMetrics) *InhibitRule {
278348 scache : store .NewAlerts (),
279349 sindex : newIndex (),
280350 metrics : metrics ,
351+ Sources : sources ,
281352 }
282353
283354 rule .scache .SetGCCallback (rule .gcCallback )
@@ -288,6 +359,7 @@ func NewInhibitRule(cr config.InhibitRule, metrics *RuleMetrics) *InhibitRule {
288359// fingerprintEquals returns the fingerprint of the equal labels of the given label set.
289360func (r * InhibitRule ) fingerprintEquals (lset model.LabelSet ) model.Fingerprint {
290361 equalSet := model.LabelSet {}
362+
291363 for n := range r .Equal {
292364 equalSet [n ] = lset [n ]
293365 }
0 commit comments