Alerting: Add rule_query_offset setting for Prometheus rule conversion (#102500)

Adds a new configuration option to specify a time offset for rule evaluation, which gets applied and saved during the Prometheus -> Grafana conversion. For example:

[unified_alerting.prometheus_conversion]
rule_query_offset = 1m

Changing this option affects only the rules imported after the change. If query_offset is set at the group level, it takes precedence over this setting.

Default is set to 1m.
This commit is contained in:
Alexander Akhmetov
2025-03-20 15:31:21 +01:00
committed by GitHub
parent 41a2aa41f8
commit 756b45402c
5 changed files with 66 additions and 2 deletions
+10
View File
@@ -1515,6 +1515,16 @@ max_age =
# Configures max number of alert annotations that Grafana stores. Default value is 0, which keeps all alert annotations.
max_annotations_to_keep =
[unified_alerting.prometheus_conversion]
# Configuration options for converting Prometheus alerting and recording rules to Grafana rules.
# These settings affect rules created via the Prometheus conversion API.
# Offset the rule evaluation time for imported rules by a specified duration in the past.
# This offset is applied and saved to the rule query during the conversion process from Prometheus to Grafana format.
# The setting only affects rules imported after the configuration change is made and does not modify existing rules.
# Accepts duration formats like: 30s, 1m, 1h.
rule_query_offset = 1m
[recording_rules]
# Enable recording rules. You must provide write credentials below.
enabled = false
+10
View File
@@ -1496,6 +1496,16 @@ max_age =
# Configures max number of alert annotations that Grafana stores. Default value is 0, which keeps all alert annotations.
max_annotations_to_keep =
[unified_alerting.prometheus_conversion]
# Configuration options for converting Prometheus alerting and recording rules to Grafana rules.
# These settings affect rules created via the Prometheus conversion API.
# Offset the rule evaluation time for imported rules by a specified duration in the past.
# This offset is applied and saved to the rule query during the conversion process from Prometheus to Grafana format.
# The setting only affects rules imported after the configuration change is made and does not modify existing rules.
# Accepts duration formats like: 30s, 1m, 1h.
rule_query_offset = 1m
#################################### Recording Rules #####################
[recording_rules]
# Enable recording rules. You must provide write credentials below.
@@ -463,6 +463,7 @@ func (srv *ConvertPrometheusSrv) convertToGrafanaRuleGroup(
IsPaused: pauseAlertRules,
},
KeepOriginalRuleDefinition: util.Pointer(keepOriginalRuleDefinition),
EvaluationOffset: &srv.cfg.PrometheusConversion.RuleQueryOffset,
},
)
if err != nil {
+33 -2
View File
@@ -179,6 +179,32 @@ func TestPrometheusRulesToGrafana(t *testing.T) {
},
expectError: false,
},
{
name: "when global query offset is set, it should be used",
orgID: 1,
namespace: "some-namespace-uid",
promGroup: PrometheusRuleGroup{
Name: "test-group-1",
Interval: prommodel.Duration(10 * time.Second),
Rules: []PrometheusRule{
{
Alert: "alert-1",
Expr: "cpu_usage > 80",
For: util.Pointer(prommodel.Duration(5 * time.Minute)),
Labels: map[string]string{
"severity": "critical",
},
Annotations: map[string]string{
"summary": "CPU usage is critical",
},
},
},
},
config: Config{
EvaluationOffset: util.Pointer(5 * time.Minute),
},
expectError: false,
},
}
for _, tc := range testCases {
@@ -244,8 +270,13 @@ func TestPrometheusRulesToGrafana(t *testing.T) {
require.Equal(t, expectedLabels, grafanaRule.Labels, tc.name)
require.Equal(t, promRule.Annotations, grafanaRule.Annotations, tc.name)
require.Equal(t, models.Duration(0*time.Minute), grafanaRule.Data[0].RelativeTimeRange.To)
require.Equal(t, models.Duration(10*time.Minute), grafanaRule.Data[0].RelativeTimeRange.From)
evalOffset := time.Duration(0)
if tc.config.EvaluationOffset != nil {
evalOffset = *tc.config.EvaluationOffset
}
require.Equal(t, models.Duration(evalOffset), grafanaRule.Data[0].RelativeTimeRange.To)
require.Equal(t, models.Duration(evalOffset+10*time.Minute), grafanaRule.Data[0].RelativeTimeRange.From)
originalRuleDefinition, err := yaml.Marshal(promRule)
require.NoError(t, err)
+12
View File
@@ -112,6 +112,7 @@ type UnifiedAlertingSettings struct {
StateHistory UnifiedAlertingStateHistorySettings
RemoteAlertmanager RemoteAlertmanagerSettings
RecordingRules RecordingRuleSettings
PrometheusConversion UnifiedAlertingPrometheusConversionSettings
// MaxStateSaveConcurrency controls the number of goroutines (per rule) that can save alert state in parallel.
MaxStateSaveConcurrency int
@@ -165,6 +166,12 @@ type UnifiedAlertingReservedLabelSettings struct {
DisabledLabels map[string]struct{}
}
// UnifiedAlertingPrometheusConversionSettings contains configuration for converting Prometheus rules to Grafana format
type UnifiedAlertingPrometheusConversionSettings struct {
// RuleQueryOffset defines a time offset to apply to rule queries during conversion from Prometheus to Grafana format
RuleQueryOffset time.Duration
}
type UnifiedAlertingStateHistorySettings struct {
Enabled bool
Backend string
@@ -437,6 +444,11 @@ func (cfg *Cfg) ReadUnifiedAlertingSettings(iniFile *ini.File) error {
}
uaCfg.StateHistory = uaCfgStateHistory
prometheusConversion := iniFile.Section("unified_alerting.prometheus_conversion")
uaCfg.PrometheusConversion = UnifiedAlertingPrometheusConversionSettings{
RuleQueryOffset: prometheusConversion.Key("rule_query_offset").MustDuration(time.Minute),
}
rr := iniFile.Section("recording_rules")
uaCfgRecordingRules := RecordingRuleSettings{
Enabled: rr.Key("enabled").MustBool(false),