package prom import "sort" // MaxSeriesPerAlert caps how many series are kept for one alert. const MaxSeriesPerAlert = 5 // SelectSeries keeps the series that belong to this alert. The rule expression // returns every series it matches, not just the one that fired, so a series is // kept only if it agrees with the alert's labels on every label name they both // carry. Labels only one side has (the rule's severity, the series' __name__) // say nothing either way, and alertname is the rule's, not the series'. // // The result is capped at MaxSeriesPerAlert, best-labelled first: the more // labels a series shares with the alert, the likelier it is the one that fired. func SelectSeries(series []Series, alertLabels map[string]string) []Series { type scored struct { s Series score int } var kept []scored for _, s := range series { score, ok := 0, true for k, v := range s.Labels { if k == "__name__" || k == "alertname" { continue } av, has := alertLabels[k] if !has { continue } if av != v { ok = false break } score++ } if ok && len(s.Points) > 0 { kept = append(kept, scored{s, score}) } } sort.SliceStable(kept, func(i, j int) bool { return kept[i].score > kept[j].score }) if len(kept) > MaxSeriesPerAlert { kept = kept[:MaxSeriesPerAlert] } out := make([]Series, len(kept)) for i, k := range kept { out[i] = k.s } return out }