Alerting: Extra dedup stage in Grafana Alertmanager (#99825)

* add feature flags

* update alerting module

* update grafana alertmanager to configure the extra dedup stage

---------

Co-authored-by: Santiago <santiagohernandez.1997@gmail.com>
This commit is contained in:
Yuri Tseretyan
2025-01-31 11:12:38 -05:00
committed by GitHub
co-authored by Santiago
parent d0703cfdbd
commit 0be6e1bb86
14 changed files with 87 additions and 14 deletions
+18
View File
@@ -1772,6 +1772,24 @@ var (
HideFromAdminPage: true,
HideFromDocs: true,
},
{
Name: "alertingAlertmanagerExtraDedupStage",
Description: "enables extra deduplication stage in alertmanager that checks that timestamps of the pipeline and the current state are matching",
Stage: FeatureStageExperimental,
Owner: grafanaAlertingSquad,
HideFromAdminPage: true,
HideFromDocs: true,
RequiresRestart: true,
},
{
Name: "alertingAlertmanagerExtraDedupStageStopPipeline",
Description: "works together with alertingAlertmanagerExtraDedupStage, if enabled, it will stop the pipeline if the timestamps are not matching. Otherwise, it will emit a warning",
Stage: FeatureStageExperimental,
Owner: grafanaAlertingSquad,
HideFromAdminPage: true,
HideFromDocs: true,
RequiresRestart: true,
},
}
)
+2
View File
@@ -236,3 +236,5 @@ grafanaAdvisor,experimental,@grafana/plugins-platform-backend,false,false,false
elasticsearchImprovedParsing,experimental,@grafana/aws-datasources,false,false,false
datasourceConnectionsTab,experimental,@grafana/plugins-platform-backend,false,false,true
fetchRulesUsingPost,experimental,@grafana/alerting-squad,false,false,false
alertingAlertmanagerExtraDedupStage,experimental,@grafana/alerting-squad,false,true,false
alertingAlertmanagerExtraDedupStageStopPipeline,experimental,@grafana/alerting-squad,false,true,false
1 Name Stage Owner requiresDevMode RequiresRestart FrontendOnly
236 elasticsearchImprovedParsing experimental @grafana/aws-datasources false false false
237 datasourceConnectionsTab experimental @grafana/plugins-platform-backend false false true
238 fetchRulesUsingPost experimental @grafana/alerting-squad false false false
239 alertingAlertmanagerExtraDedupStage experimental @grafana/alerting-squad false true false
240 alertingAlertmanagerExtraDedupStageStopPipeline experimental @grafana/alerting-squad false true false
+8
View File
@@ -954,4 +954,12 @@ const (
// FlagFetchRulesUsingPost
// Use a POST request to list rules by passing down the namespaces user has access to
FlagFetchRulesUsingPost = "fetchRulesUsingPost"
// FlagAlertingAlertmanagerExtraDedupStage
// enables extra deduplication stage in alertmanager that checks that timestamps of the pipeline and the current state are matching
FlagAlertingAlertmanagerExtraDedupStage = "alertingAlertmanagerExtraDedupStage"
// FlagAlertingAlertmanagerExtraDedupStageStopPipeline
// works together with alertingAlertmanagerExtraDedupStage, if enabled, it will stop the pipeline if the timestamps are not matching. Otherwise, it will emit a warning
FlagAlertingAlertmanagerExtraDedupStageStopPipeline = "alertingAlertmanagerExtraDedupStageStopPipeline"
)
+30
View File
@@ -143,6 +143,36 @@
"codeowner": "@grafana/alerting-squad"
}
},
{
"metadata": {
"name": "alertingAlertmanagerExtraDedupStage",
"resourceVersion": "1738251165994",
"creationTimestamp": "2025-01-30T15:32:45Z"
},
"spec": {
"description": "enables extra deduplication stage in alertmanager that checks that timestamps of the pipeline and the current state are matching",
"stage": "experimental",
"codeowner": "@grafana/alerting-squad",
"requiresRestart": true,
"hideFromAdminPage": true,
"hideFromDocs": true
}
},
{
"metadata": {
"name": "alertingAlertmanagerExtraDedupStageStopPipeline",
"resourceVersion": "1738251165994",
"creationTimestamp": "2025-01-30T15:32:45Z"
},
"spec": {
"description": "works together with alertingAlertmanagerExtraDedupStage, if enabled, it will stop the pipeline if the timestamps are not matching. Otherwise, it will emit a warning",
"stage": "experimental",
"codeowner": "@grafana/alerting-squad",
"requiresRestart": true,
"hideFromAdminPage": true,
"hideFromDocs": true
}
},
{
"metadata": {
"name": "alertingApiServer",
+15 -3
View File
@@ -10,6 +10,7 @@ import (
"time"
alertingNotify "github.com/grafana/alerting/notify"
"github.com/grafana/alerting/notify/stages"
"github.com/grafana/alerting/receivers"
alertingTemplates "github.com/grafana/alerting/templates"
"github.com/prometheus/alertmanager/config"
@@ -17,6 +18,7 @@ import (
amv2 "github.com/prometheus/alertmanager/api/v2/models"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/featuremgmt"
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
"github.com/grafana/grafana/pkg/services/ngalert/metrics"
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
@@ -91,7 +93,7 @@ func (m maintenanceOptions) MaintenanceFunc(state alertingNotify.State) (int64,
func NewAlertmanager(ctx context.Context, orgID int64, cfg *setting.Cfg, store AlertingStore, stateStore stateStore,
peer alertingNotify.ClusterPeer, decryptFn alertingNotify.GetDecryptedValueFn, ns notifications.Service,
m *metrics.Alertmanager, withAutogen bool,
m *metrics.Alertmanager, featureToggles featuremgmt.FeatureToggles,
) (*alertmanager, error) {
nflog, err := stateStore.GetNotificationLog(ctx)
if err != nil {
@@ -121,6 +123,16 @@ func NewAlertmanager(ctx context.Context, orgID int64, cfg *setting.Cfg, store A
return stateStore.SaveNotificationLog(context.Background(), state)
},
}
l := log.New("ngalert.notifier.alertmanager", "org", orgID)
action := stages.Disabled
if featureToggles.IsEnabledGlobally(featuremgmt.FlagAlertingAlertmanagerExtraDedupStage) {
if featureToggles.IsEnabledGlobally(featuremgmt.FlagAlertingAlertmanagerExtraDedupStageStopPipeline) {
action = stages.StopPipeline
} else {
action = stages.LogOnly
}
l.Info("Initializing Alertmanager", "extra_dedup_stage", action)
}
amcfg := &alertingNotify.GrafanaAlertmanagerConfig{
ExternalURL: cfg.AppURL,
@@ -132,9 +144,9 @@ func NewAlertmanager(ctx context.Context, orgID int64, cfg *setting.Cfg, store A
MaxSilences: cfg.UnifiedAlerting.AlertmanagerMaxSilencesCount,
MaxSilenceSizeBytes: cfg.UnifiedAlerting.AlertmanagerMaxSilenceSizeBytes,
},
PipelineAndStateTimestampsMismatchAction: action,
}
l := log.New("ngalert.notifier.alertmanager", "org", orgID)
gam, err := alertingNotify.NewGrafanaAlertmanager("orgID", orgID, amcfg, peer, l, alertingNotify.NewGrafanaAlertmanagerMetrics(m.Registerer, l))
if err != nil {
return nil, err
@@ -152,7 +164,7 @@ func NewAlertmanager(ctx context.Context, orgID int64, cfg *setting.Cfg, store A
logger: l,
// TODO: Preferably, logic around autogen would be outside of the specific alertmanager implementation so that remote alertmanager will get it for free.
withAutogen: withAutogen,
withAutogen: featureToggles.IsEnabled(ctx, featuremgmt.FlagAlertingSimplifiedRouting),
}
return am, nil
@@ -11,6 +11,7 @@ import (
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/ngalert/metrics"
"github.com/grafana/grafana/pkg/services/ngalert/store"
"github.com/grafana/grafana/pkg/services/ngalert/tests/fakes"
@@ -52,7 +53,7 @@ func setupAMTest(t *testing.T) *alertmanager {
orgID := 1
stateStore := NewFileStore(int64(orgID), kvStore)
am, err := NewAlertmanager(context.Background(), 1, cfg, s, stateStore, &NilPeer{}, decryptFn, nil, m, false)
am, err := NewAlertmanager(context.Background(), 1, cfg, s, stateStore, &NilPeer{}, decryptFn, nil, m, featuremgmt.WithFeatures())
require.NoError(t, err)
return am
}
@@ -160,7 +160,7 @@ func NewMultiOrgAlertmanager(
moa.factory = func(ctx context.Context, orgID int64) (Alertmanager, error) {
m := metrics.NewAlertmanagerMetrics(moa.metrics.GetOrCreateOrgRegistry(orgID), l)
stateStore := NewFileStore(orgID, kvStore)
return NewAlertmanager(ctx, orgID, moa.settings, moa.configStore, stateStore, moa.peer, moa.decryptFn, moa.ns, m, featureManager.IsEnabled(ctx, featuremgmt.FlagAlertingSimplifiedRouting))
return NewAlertmanager(ctx, orgID, moa.settings, moa.configStore, stateStore, moa.peer, moa.decryptFn, moa.ns, m, featureManager)
}
for _, opt := range opts {