Alerting: In migration improve deduplication of title and group (#78351)

* Alerting: In migration improve deduplication of title and group

This change improves alert titles generated in the legacy migration 
that occur when we need to deduplicate titles. Now when duplicate 
titles are detected we will first attempt to append a sequential index, 
falling back to a random uid if none are unique within 10 attempts. 
This should cause shorter and more easily readable deduplicated 
titles in most cases.

In addition, groups are no longer deduplicated. Instead we set them 
to a combination of truncated dashboard name and humanized alert 
frequency. This way, alerts from the same dashboard share a group 
if they have the same evaluation interval. In the event that truncation 
causes overlap, it won't be a big issue as all alerts will still be in a 
group with the correct evaluation interval.
This commit is contained in:
Matthew Jacobson
2023-11-29 10:05:00 -05:00
committed by GitHub
parent 773e0680c5
commit 2b51f0e263
9 changed files with 332 additions and 198 deletions

View File

@@ -6,6 +6,8 @@ import (
"fmt"
"time"
"github.com/prometheus/common/model"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
legacymodels "github.com/grafana/grafana/pkg/services/alerting/models"
@@ -65,27 +67,14 @@ func (om *OrgMigration) migrateAlert(ctx context.Context, l log.Logger, da *migr
}
// Here we ensure that the alert rule title is unique within the folder.
titleDedupSet := om.AlertTitleDeduplicator(info.NewFolderUID)
name := truncate(da.Name, store.AlertDefinitionMaxTitleLength)
if titleDedupSet.contains(name) {
dedupedName := titleDedupSet.deduplicate(name)
l.Debug("Duplicate alert rule name detected, renaming", "oldName", name, "newName", dedupedName)
name = dedupedName
titleDeduplicator := om.titleDeduplicatorForFolder(info.NewFolderUID)
name, err := titleDeduplicator.Deduplicate(da.Name)
if err != nil {
return nil, err
}
titleDedupSet.add(name)
// Here we ensure that the alert rule group is unique within the folder.
// This is so that we don't have to ensure that the alerts rules have the same interval.
groupDedupSet := om.AlertTitleDeduplicator(info.NewFolderUID)
panelSuffix := fmt.Sprintf(" - %d", da.PanelID)
truncatedDashboard := truncate(info.DashboardName, store.AlertRuleMaxRuleGroupNameLength-len(panelSuffix))
groupName := fmt.Sprintf("%s%s", truncatedDashboard, panelSuffix) // Unique to this dash alert but still contains useful info.
if groupDedupSet.contains(groupName) {
dedupedGroupName := groupDedupSet.deduplicate(groupName)
l.Debug("Duplicate alert rule group name detected, renaming", "oldGroup", groupName, "newGroup", dedupedGroupName)
groupName = dedupedGroupName
if name != da.Name {
l.Info(fmt.Sprintf("Alert rule title modified to be unique within the folder and fit within the maximum length of %d", store.AlertDefinitionMaxTitleLength), "old", da.Name, "new", name)
}
groupDedupSet.add(groupName)
dashUID := info.DashboardUID
ar := &ngmodels.AlertRule{
@@ -99,7 +88,7 @@ func (om *OrgMigration) migrateAlert(ctx context.Context, l log.Logger, da *migr
NamespaceUID: info.NewFolderUID,
DashboardUID: &dashUID,
PanelID: &da.PanelID,
RuleGroup: groupName,
RuleGroup: groupName(ruleAdjustInterval(da.Frequency), info.DashboardName),
For: da.For,
Updated: time.Now().UTC(),
Annotations: annotations,
@@ -304,3 +293,12 @@ func extractChannelIDs(d *migrationStore.DashAlert) (channelUids []migrationStor
return channelUids
}
// groupName constructs a group name from the dashboard title and the interval. It truncates the dashboard title
// if necessary to ensure that the group name is not longer than the maximum allowed length.
func groupName(interval int64, dashboardTitle string) string {
duration := model.Duration(time.Duration(interval) * time.Second) // Humanize.
panelSuffix := fmt.Sprintf(" - %s", duration.String())
truncatedDashboard := truncate(dashboardTitle, store.AlertRuleMaxRuleGroupNameLength-len(panelSuffix))
return fmt.Sprintf("%s%s", truncatedDashboard, panelSuffix)
}