chore: fix alerting options (#4752)

This commit is contained in:
Srikanth Chekuri 2024-03-27 20:25:18 +05:30 committed by GitHub
parent 0ac9f6f663
commit 31b1d58a70
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 63 additions and 36 deletions

View File

@ -37,11 +37,16 @@
"text_condition1": "Send a notification when", "text_condition1": "Send a notification when",
"text_condition2": "the threshold", "text_condition2": "the threshold",
"text_condition3": "during the last", "text_condition3": "during the last",
"option_1min": "1 min",
"option_5min": "5 mins", "option_5min": "5 mins",
"option_10min": "10 mins", "option_10min": "10 mins",
"option_15min": "15 mins", "option_15min": "15 mins",
"option_30min": "30 mins",
"option_60min": "60 mins", "option_60min": "60 mins",
"option_4hours": "4 hours", "option_4hours": "4 hours",
"option_3hours": "3 hours",
"option_6hours": "6 hours",
"option_12hours": "12 hours",
"option_24hours": "24 hours", "option_24hours": "24 hours",
"field_threshold": "Alert Threshold", "field_threshold": "Alert Threshold",
"option_allthetimes": "all the times", "option_allthetimes": "all the times",

View File

@ -37,11 +37,16 @@
"text_condition1": "Send a notification when", "text_condition1": "Send a notification when",
"text_condition2": "the threshold", "text_condition2": "the threshold",
"text_condition3": "during the last", "text_condition3": "during the last",
"option_1min": "1 min",
"option_5min": "5 mins", "option_5min": "5 mins",
"option_10min": "10 mins", "option_10min": "10 mins",
"option_15min": "15 mins", "option_15min": "15 mins",
"option_30min": "30 mins",
"option_60min": "60 mins", "option_60min": "60 mins",
"option_3hours": "3 hours",
"option_4hours": "4 hours", "option_4hours": "4 hours",
"option_6hours": "6 hours",
"option_12hours": "12 hours",
"option_24hours": "24 hours", "option_24hours": "24 hours",
"field_threshold": "Alert Threshold", "field_threshold": "Alert Threshold",
"option_allthetimes": "all the times", "option_allthetimes": "all the times",

View File

@ -20,6 +20,7 @@ import {
AlertDef, AlertDef,
defaultCompareOp, defaultCompareOp,
defaultEvalWindow, defaultEvalWindow,
defaultFrequency,
defaultMatchType, defaultMatchType,
} from 'types/api/alerts/def'; } from 'types/api/alerts/def';
import { EQueryType } from 'types/common/dashboard'; import { EQueryType } from 'types/common/dashboard';
@ -206,6 +207,35 @@ function RuleOptions({
}); });
}; };
const onChangeFrequency = (value: string | unknown): void => {
const freq = (value as string) || alertDef.frequency;
setAlertDef({
...alertDef,
frequency: freq,
});
};
const renderFrequency = (): JSX.Element => (
<InlineSelect
getPopupContainer={popupContainer}
defaultValue={defaultFrequency}
style={{ minWidth: '120px' }}
value={alertDef.frequency}
onChange={onChangeFrequency}
>
<Select.Option value="1m0s">{t('option_1min')}</Select.Option>
<Select.Option value="5m0s">{t('option_5min')}</Select.Option>
<Select.Option value="10m0s">{t('option_10min')}</Select.Option>
<Select.Option value="15m0s">{t('option_15min')}</Select.Option>
<Select.Option value="30m0s">{t('option_30min')}</Select.Option>
<Select.Option value="1h0m0s">{t('option_60min')}</Select.Option>
<Select.Option value="3h0m0s">{t('option_3hours')}</Select.Option>
<Select.Option value="6h0m0s">{t('option_6hours')}</Select.Option>
<Select.Option value="12h0m0s">{t('option_12hours')}</Select.Option>
<Select.Option value="24h0m0s">{t('option_24hours')}</Select.Option>
</InlineSelect>
);
const selectedCategory = getCategoryByOptionId(currentQuery?.unit || ''); const selectedCategory = getCategoryByOptionId(currentQuery?.unit || '');
const categorySelectOptions = getCategorySelectOptionByName( const categorySelectOptions = getCategorySelectOptionByName(
@ -250,22 +280,7 @@ function RuleOptions({
<VerticalLine> <VerticalLine>
<Space direction="horizontal" align="center"> <Space direction="horizontal" align="center">
<Typography.Text>{t('text_alert_frequency')}</Typography.Text> <Typography.Text>{t('text_alert_frequency')}</Typography.Text>
<Form.Item noStyle name={['condition', 'frequency']}> {renderFrequency()}
<InputNumber
defaultValue={1}
min={1}
value={alertDef?.frequency}
onChange={(value): void => {
setAlertDef({
...alertDef,
frequency: Number(value) || 0,
});
}}
type="number"
onWheel={(e): void => e.currentTarget.blur()}
/>
</Form.Item>
<Typography.Text>{t('text_for')}</Typography.Text>
</Space> </Space>
</VerticalLine> </VerticalLine>

View File

@ -6,6 +6,8 @@ export const defaultMatchType = '1';
// default eval window // default eval window
export const defaultEvalWindow = '5m0s'; export const defaultEvalWindow = '5m0s';
export const defaultFrequency = '1m0s';
// default compare op: above // default compare op: above
export const defaultCompareOp = '1'; export const defaultCompareOp = '1';
@ -14,7 +16,7 @@ export interface AlertDef {
alertType?: string; alertType?: string;
alert?: string; alert?: string;
ruleType?: string; ruleType?: string;
frequency?: number | undefined; frequency?: string;
condition: RuleCondition; condition: RuleCondition;
labels?: Labels; labels?: Labels;
annotations?: Labels; annotations?: Labels;

View File

@ -137,7 +137,7 @@ type RuleCondition struct {
CompareOp CompareOp `yaml:"op,omitempty" json:"op,omitempty"` CompareOp CompareOp `yaml:"op,omitempty" json:"op,omitempty"`
Target *float64 `yaml:"target,omitempty" json:"target,omitempty"` Target *float64 `yaml:"target,omitempty" json:"target,omitempty"`
AlertOnAbsent bool `yaml:"alertOnAbsent,omitempty" json:"alertOnAbsent,omitempty"` AlertOnAbsent bool `yaml:"alertOnAbsent,omitempty" json:"alertOnAbsent,omitempty"`
AbsentFor time.Duration `yaml:"absentFor,omitempty" json:"absentFor,omitempty"` AbsentFor uint64 `yaml:"absentFor,omitempty" json:"absentFor,omitempty"`
MatchType MatchType `json:"matchType,omitempty"` MatchType MatchType `json:"matchType,omitempty"`
TargetUnit string `json:"targetUnit,omitempty"` TargetUnit string `json:"targetUnit,omitempty"`
SelectedQuery string `json:"selectedQueryName,omitempty"` SelectedQuery string `json:"selectedQueryName,omitempty"`

View File

@ -31,7 +31,7 @@ func newApiErrorBadData(err error) *model.ApiError {
// PostableRule is used to create alerting rule from HTTP api // PostableRule is used to create alerting rule from HTTP api
type PostableRule struct { type PostableRule struct {
Alert string `yaml:"alert,omitempty" json:"alert,omitempty"` AlertName string `yaml:"alert,omitempty" json:"alert,omitempty"`
AlertType string `yaml:"alertType,omitempty" json:"alertType,omitempty"` AlertType string `yaml:"alertType,omitempty" json:"alertType,omitempty"`
Description string `yaml:"description,omitempty" json:"description,omitempty"` Description string `yaml:"description,omitempty" json:"description,omitempty"`
RuleType RuleType `yaml:"ruleType,omitempty" json:"ruleType,omitempty"` RuleType RuleType `yaml:"ruleType,omitempty" json:"ruleType,omitempty"`
@ -188,7 +188,7 @@ func (r *PostableRule) Validate() (errs []error) {
} }
func testTemplateParsing(rl *PostableRule) (errs []error) { func testTemplateParsing(rl *PostableRule) (errs []error) {
if rl.Alert == "" { if rl.AlertName == "" {
// Not an alerting rule. // Not an alerting rule.
return errs return errs
} }
@ -200,7 +200,7 @@ func testTemplateParsing(rl *PostableRule) (errs []error) {
tmpl := NewTemplateExpander( tmpl := NewTemplateExpander(
context.TODO(), context.TODO(),
defs+text, defs+text,
"__alert_"+rl.Alert, "__alert_"+rl.AlertName,
tmplData, tmplData,
times.Time(timestamp.FromTime(time.Now())), times.Time(timestamp.FromTime(time.Now())),
nil, nil,

View File

@ -503,7 +503,7 @@ func (m *Manager) prepareTask(acquireLock bool, r *PostableRule, taskName string
rules := make([]Rule, 0) rules := make([]Rule, 0)
var task Task var task Task
if r.Alert == "" { if r.AlertName == "" {
zap.L().Error("task load failed, at least one rule must be set", zap.String("name", taskName)) zap.L().Error("task load failed, at least one rule must be set", zap.String("name", taskName))
return task, fmt.Errorf("task load failed, at least one rule must be set") return task, fmt.Errorf("task load failed, at least one rule must be set")
} }
@ -525,7 +525,7 @@ func (m *Manager) prepareTask(acquireLock bool, r *PostableRule, taskName string
rules = append(rules, tr) rules = append(rules, tr)
// create ch rule task for evalution // create ch rule task for evalution
task = newTask(TaskTypeCh, taskName, taskNamesuffix, time.Duration(r.Frequency*Duration(time.Minute)), rules, m.opts, m.prepareNotifyFunc()) task = newTask(TaskTypeCh, taskName, taskNamesuffix, time.Duration(r.Frequency), rules, m.opts, m.prepareNotifyFunc())
// add rule to memory // add rule to memory
m.rules[ruleId] = tr m.rules[ruleId] = tr
@ -536,7 +536,7 @@ func (m *Manager) prepareTask(acquireLock bool, r *PostableRule, taskName string
pr, err := NewPromRule( pr, err := NewPromRule(
ruleId, ruleId,
r, r,
log.With(m.logger, "alert", r.Alert), log.With(m.logger, "alert", r.AlertName),
PromRuleOpts{}, PromRuleOpts{},
) )
@ -547,7 +547,7 @@ func (m *Manager) prepareTask(acquireLock bool, r *PostableRule, taskName string
rules = append(rules, pr) rules = append(rules, pr)
// create promql rule task for evalution // create promql rule task for evalution
task = newTask(TaskTypeProm, taskName, taskNamesuffix, time.Duration(r.Frequency*Duration(time.Minute)), rules, m.opts, m.prepareNotifyFunc()) task = newTask(TaskTypeProm, taskName, taskNamesuffix, time.Duration(r.Frequency), rules, m.opts, m.prepareNotifyFunc())
// add rule to memory // add rule to memory
m.rules[ruleId] = pr m.rules[ruleId] = pr
@ -850,7 +850,7 @@ func (m *Manager) TestNotification(ctx context.Context, ruleStr string) (int, *m
return 0, newApiErrorBadData(errs[0]) return 0, newApiErrorBadData(errs[0])
} }
var alertname = parsedRule.Alert var alertname = parsedRule.AlertName
if alertname == "" { if alertname == "" {
// alertname is not mandatory for testing, so picking // alertname is not mandatory for testing, so picking
// a random string here // a random string here
@ -858,7 +858,7 @@ func (m *Manager) TestNotification(ctx context.Context, ruleStr string) (int, *m
} }
// append name to indicate this is test alert // append name to indicate this is test alert
parsedRule.Alert = fmt.Sprintf("%s%s", alertname, TestAlertPostFix) parsedRule.AlertName = fmt.Sprintf("%s%s", alertname, TestAlertPostFix)
var rule Rule var rule Rule
var err error var err error

View File

@ -71,7 +71,7 @@ func NewPromRule(
p := PromRule{ p := PromRule{
id: id, id: id,
name: postableRule.Alert, name: postableRule.AlertName,
source: postableRule.Source, source: postableRule.Source,
ruleCondition: postableRule.RuleCondition, ruleCondition: postableRule.RuleCondition,
evalWindow: time.Duration(postableRule.EvalWindow), evalWindow: time.Duration(postableRule.EvalWindow),
@ -612,7 +612,7 @@ func (r *PromRule) shouldAlert(series pql.Series) (pql.Sample, bool) {
func (r *PromRule) String() string { func (r *PromRule) String() string {
ar := PostableRule{ ar := PostableRule{
Alert: r.name, AlertName: r.name,
RuleCondition: r.ruleCondition, RuleCondition: r.ruleCondition,
EvalWindow: Duration(r.evalWindow), EvalWindow: Duration(r.evalWindow),
Labels: r.labels.Map(), Labels: r.labels.Map(),

View File

@ -20,7 +20,7 @@ func (l testLogger) Log(args ...interface{}) error {
func TestPromRuleShouldAlert(t *testing.T) { func TestPromRuleShouldAlert(t *testing.T) {
postableRule := PostableRule{ postableRule := PostableRule{
Alert: "Test Rule", AlertName: "Test Rule",
AlertType: "METRIC_BASED_ALERT", AlertType: "METRIC_BASED_ALERT",
RuleType: RuleTypeProm, RuleType: RuleTypeProm,
EvalWindow: Duration(5 * time.Minute), EvalWindow: Duration(5 * time.Minute),

View File

@ -102,7 +102,7 @@ func NewThresholdRule(
t := ThresholdRule{ t := ThresholdRule{
id: id, id: id,
name: p.Alert, name: p.AlertName,
source: p.Source, source: p.Source,
ruleCondition: p.RuleCondition, ruleCondition: p.RuleCondition,
evalWindow: time.Duration(p.EvalWindow), evalWindow: time.Duration(p.EvalWindow),
@ -713,7 +713,7 @@ func (r *ThresholdRule) runChQuery(ctx context.Context, db clickhouse.Conn, quer
zap.L().Debug("resultmap(potential alerts)", zap.String("ruleid", r.ID()), zap.Int("count", len(resultMap))) zap.L().Debug("resultmap(potential alerts)", zap.String("ruleid", r.ID()), zap.Int("count", len(resultMap)))
// if the data is missing for `For` duration then we should send alert // if the data is missing for `For` duration then we should send alert
if r.ruleCondition.AlertOnAbsent && r.lastTimestampWithDatapoints.Add(r.Condition().AbsentFor*time.Minute).Before(time.Now()) { if r.ruleCondition.AlertOnAbsent && r.lastTimestampWithDatapoints.Add(time.Duration(r.Condition().AbsentFor)*time.Minute).Before(time.Now()) {
zap.L().Info("no data found for rule condition", zap.String("ruleid", r.ID())) zap.L().Info("no data found for rule condition", zap.String("ruleid", r.ID()))
lbls := labels.NewBuilder(labels.Labels{}) lbls := labels.NewBuilder(labels.Labels{})
if !r.lastTimestampWithDatapoints.IsZero() { if !r.lastTimestampWithDatapoints.IsZero() {
@ -1289,7 +1289,7 @@ func (r *ThresholdRule) Eval(ctx context.Context, ts time.Time, queriers *Querie
func (r *ThresholdRule) String() string { func (r *ThresholdRule) String() string {
ar := PostableRule{ ar := PostableRule{
Alert: r.name, AlertName: r.name,
RuleCondition: r.ruleCondition, RuleCondition: r.ruleCondition,
EvalWindow: Duration(r.evalWindow), EvalWindow: Duration(r.evalWindow),
Labels: r.labels.Map(), Labels: r.labels.Map(),

View File

@ -14,7 +14,7 @@ import (
func TestThresholdRuleCombinations(t *testing.T) { func TestThresholdRuleCombinations(t *testing.T) {
postableRule := PostableRule{ postableRule := PostableRule{
Alert: "Tricky Condition Tests", AlertName: "Tricky Condition Tests",
AlertType: "METRIC_BASED_ALERT", AlertType: "METRIC_BASED_ALERT",
RuleType: RuleTypeThreshold, RuleType: RuleTypeThreshold,
EvalWindow: Duration(5 * time.Minute), EvalWindow: Duration(5 * time.Minute),
@ -339,7 +339,7 @@ func TestNormalizeLabelName(t *testing.T) {
func TestPrepareLinksToLogs(t *testing.T) { func TestPrepareLinksToLogs(t *testing.T) {
postableRule := PostableRule{ postableRule := PostableRule{
Alert: "Tricky Condition Tests", AlertName: "Tricky Condition Tests",
AlertType: "LOGS_BASED_ALERT", AlertType: "LOGS_BASED_ALERT",
RuleType: RuleTypeThreshold, RuleType: RuleTypeThreshold,
EvalWindow: Duration(5 * time.Minute), EvalWindow: Duration(5 * time.Minute),
@ -381,7 +381,7 @@ func TestPrepareLinksToLogs(t *testing.T) {
func TestPrepareLinksToTraces(t *testing.T) { func TestPrepareLinksToTraces(t *testing.T) {
postableRule := PostableRule{ postableRule := PostableRule{
Alert: "Links to traces test", AlertName: "Links to traces test",
AlertType: "TRACES_BASED_ALERT", AlertType: "TRACES_BASED_ALERT",
RuleType: RuleTypeThreshold, RuleType: RuleTypeThreshold,
EvalWindow: Duration(5 * time.Minute), EvalWindow: Duration(5 * time.Minute),