diff --git a/frontend/src/container/SideNav/NavItem/NavItem.styles.scss b/frontend/src/container/SideNav/NavItem/NavItem.styles.scss index aea7b3a0ee..ede4376033 100644 --- a/frontend/src/container/SideNav/NavItem/NavItem.styles.scss +++ b/frontend/src/container/SideNav/NavItem/NavItem.styles.scss @@ -75,6 +75,10 @@ text-overflow: ellipsis; } } + + .beta-tag { + padding-right: 0; + } } .lightMode { diff --git a/frontend/src/container/SideNav/NavItem/NavItem.tsx b/frontend/src/container/SideNav/NavItem/NavItem.tsx index b3d57193f1..97a8cdb0ed 100644 --- a/frontend/src/container/SideNav/NavItem/NavItem.tsx +++ b/frontend/src/container/SideNav/NavItem/NavItem.tsx @@ -24,7 +24,7 @@ export default function NavItem({ onClick={(event): void => onClick(event)} >
-Consumer Lag
+{MessagingQueuesViewType.consumerLag.label}
1D
@@ -128,7 +131,7 @@ function MessagingQueues(): JSX.Element {Avg. Partition latency
+{MessagingQueuesViewType.partitionLatency.label}
1D
@@ -140,7 +143,7 @@ function MessagingQueues(): JSX.Element {Avg. Partition latency
+{MessagingQueuesViewType.producerLatency.label}
1D
@@ -152,7 +155,7 @@ function MessagingQueues(): JSX.Element {Avg. Partition latency
+{MessagingQueuesViewType.consumerLatency.label}
1D
diff --git a/frontend/src/pages/MessagingQueues/MessagingQueuesUtils.ts b/frontend/src/pages/MessagingQueues/MessagingQueuesUtils.ts index 91501e9c5c..b0855ce524 100644 --- a/frontend/src/pages/MessagingQueues/MessagingQueuesUtils.ts +++ b/frontend/src/pages/MessagingQueues/MessagingQueuesUtils.ts @@ -204,3 +204,22 @@ export function setSelectedTimelineQuery( const generatedUrl = `${location.pathname}?${urlQuery.toString()}`; history.replace(generatedUrl); } + +export const MessagingQueuesViewType = { + consumerLag: { + label: 'Consumer Lag view', + value: 'consumerLag', + }, + partitionLatency: { + label: 'Partition Latency view', + value: 'partitionLatency', + }, + producerLatency: { + label: 'Producer Latency view', + value: 'producerLatency', + }, + consumerLatency: { + label: 'Consumer latency view', + value: 'consumerLatency', + }, +}; diff --git a/pkg/query-service/app/http_handler.go b/pkg/query-service/app/http_handler.go index 5d3d9affd5..1210cd4f67 100644 --- a/pkg/query-service/app/http_handler.go +++ b/pkg/query-service/app/http_handler.go @@ -805,7 +805,7 @@ func (aH *APIHandler) getRuleStateHistory(w http.ResponseWriter, r *http.Request continue } filterItems := []v3.FilterItem{} - if rule.AlertType == "LOGS_BASED_ALERT" || rule.AlertType == "TRACES_BASED_ALERT" { + if rule.AlertType == rules.AlertTypeLogs || rule.AlertType == rules.AlertTypeTraces { if rule.RuleCondition.CompositeQuery != nil { if rule.RuleCondition.QueryType() == v3.QueryTypeBuilder { for _, query := range rule.RuleCondition.CompositeQuery.BuilderQueries { @@ -818,9 +818,9 @@ func (aH *APIHandler) getRuleStateHistory(w http.ResponseWriter, r *http.Request } newFilters := common.PrepareFilters(lbls, filterItems) ts := time.Unix(res.Items[idx].UnixMilli/1000, 0) - if rule.AlertType == "LOGS_BASED_ALERT" { + if rule.AlertType == rules.AlertTypeLogs { res.Items[idx].RelatedLogsLink = common.PrepareLinksToLogs(ts, newFilters) - } else if rule.AlertType == "TRACES_BASED_ALERT" { + } else if rule.AlertType == rules.AlertTypeTraces { res.Items[idx].RelatedTracesLink = common.PrepareLinksToTraces(ts, newFilters) } } @@ -854,9 +854,9 @@ func (aH *APIHandler) getRuleStateHistoryTopContributors(w http.ResponseWriter, } ts := time.Unix(params.End/1000, 0) filters := common.PrepareFilters(lbls, nil) - if rule.AlertType == "LOGS_BASED_ALERT" { + if rule.AlertType == rules.AlertTypeLogs { res[idx].RelatedLogsLink = common.PrepareLinksToLogs(ts, filters) - } else if rule.AlertType == "TRACES_BASED_ALERT" { + } else if rule.AlertType == rules.AlertTypeTraces { res[idx].RelatedTracesLink = common.PrepareLinksToTraces(ts, filters) } } diff --git a/pkg/query-service/migrate/0_45_alerts_to_v4/run.go b/pkg/query-service/migrate/0_45_alerts_to_v4/run.go deleted file mode 100644 index f68f4ca43b..0000000000 --- a/pkg/query-service/migrate/0_45_alerts_to_v4/run.go +++ /dev/null @@ -1,153 +0,0 @@ -package alertstov4 - -import ( - "context" - "encoding/json" - - "github.com/jmoiron/sqlx" - v3 "go.signoz.io/signoz/pkg/query-service/model/v3" - "go.signoz.io/signoz/pkg/query-service/rules" - "go.uber.org/multierr" - "go.uber.org/zap" -) - -var Version = "0.45-alerts-to-v4" - -var mapTimeAggregation = map[v3.AggregateOperator]v3.TimeAggregation{ - v3.AggregateOperatorSum: v3.TimeAggregationSum, - v3.AggregateOperatorMin: v3.TimeAggregationMin, - v3.AggregateOperatorMax: v3.TimeAggregationMax, - v3.AggregateOperatorSumRate: v3.TimeAggregationRate, - v3.AggregateOperatorAvgRate: v3.TimeAggregationRate, - v3.AggregateOperatorMinRate: v3.TimeAggregationRate, - v3.AggregateOperatorMaxRate: v3.TimeAggregationRate, - v3.AggregateOperatorHistQuant50: v3.TimeAggregationUnspecified, - v3.AggregateOperatorHistQuant75: v3.TimeAggregationUnspecified, - v3.AggregateOperatorHistQuant90: v3.TimeAggregationUnspecified, - v3.AggregateOperatorHistQuant95: v3.TimeAggregationUnspecified, - v3.AggregateOperatorHistQuant99: v3.TimeAggregationUnspecified, -} - -var mapSpaceAggregation = map[v3.AggregateOperator]v3.SpaceAggregation{ - v3.AggregateOperatorSum: v3.SpaceAggregationSum, - v3.AggregateOperatorMin: v3.SpaceAggregationMin, - v3.AggregateOperatorMax: v3.SpaceAggregationMax, - v3.AggregateOperatorSumRate: v3.SpaceAggregationSum, - v3.AggregateOperatorAvgRate: v3.SpaceAggregationAvg, - v3.AggregateOperatorMinRate: v3.SpaceAggregationMin, - v3.AggregateOperatorMaxRate: v3.SpaceAggregationMax, - v3.AggregateOperatorHistQuant50: v3.SpaceAggregationPercentile50, - v3.AggregateOperatorHistQuant75: v3.SpaceAggregationPercentile75, - v3.AggregateOperatorHistQuant90: v3.SpaceAggregationPercentile90, - v3.AggregateOperatorHistQuant95: v3.SpaceAggregationPercentile95, - v3.AggregateOperatorHistQuant99: v3.SpaceAggregationPercentile99, -} - -func canMigrateOperator(operator v3.AggregateOperator) bool { - switch operator { - case v3.AggregateOperatorSum, - v3.AggregateOperatorMin, - v3.AggregateOperatorMax, - v3.AggregateOperatorSumRate, - v3.AggregateOperatorAvgRate, - v3.AggregateOperatorMinRate, - v3.AggregateOperatorMaxRate, - v3.AggregateOperatorHistQuant50, - v3.AggregateOperatorHistQuant75, - v3.AggregateOperatorHistQuant90, - v3.AggregateOperatorHistQuant95, - v3.AggregateOperatorHistQuant99: - return true - } - return false -} - -func Migrate(conn *sqlx.DB) error { - ruleDB := rules.NewRuleDB(conn) - storedRules, err := ruleDB.GetStoredRules(context.Background()) - if err != nil { - return err - } - - for _, storedRule := range storedRules { - parsedRule, errs := rules.ParsePostableRule([]byte(storedRule.Data)) - if len(errs) > 0 { - // this should not happen but if it does, we should not stop the migration - zap.L().Error("Error parsing rule", zap.Error(multierr.Combine(errs...)), zap.Int("rule", storedRule.Id)) - continue - } - zap.L().Info("Rule parsed", zap.Int("rule", storedRule.Id)) - updated := false - if parsedRule.RuleCondition != nil && parsedRule.Version == "" { - if parsedRule.RuleCondition.QueryType() == v3.QueryTypeBuilder { - // check if all the queries can be converted to v4 - canMigrate := true - for _, query := range parsedRule.RuleCondition.CompositeQuery.BuilderQueries { - if query.DataSource == v3.DataSourceMetrics && query.Expression == query.QueryName { - if !canMigrateOperator(query.AggregateOperator) { - canMigrate = false - break - } - } - } - - if canMigrate { - parsedRule.Version = "v4" - for _, query := range parsedRule.RuleCondition.CompositeQuery.BuilderQueries { - if query.DataSource == v3.DataSourceMetrics && query.Expression == query.QueryName { - // update aggregate attribute - if query.AggregateOperator == v3.AggregateOperatorSum || - query.AggregateOperator == v3.AggregateOperatorMin || - query.AggregateOperator == v3.AggregateOperatorMax { - query.AggregateAttribute.Type = "Gauge" - } - if query.AggregateOperator == v3.AggregateOperatorSumRate || - query.AggregateOperator == v3.AggregateOperatorAvgRate || - query.AggregateOperator == v3.AggregateOperatorMinRate || - query.AggregateOperator == v3.AggregateOperatorMaxRate { - query.AggregateAttribute.Type = "Sum" - } - - if query.AggregateOperator == v3.AggregateOperatorHistQuant50 || - query.AggregateOperator == v3.AggregateOperatorHistQuant75 || - query.AggregateOperator == v3.AggregateOperatorHistQuant90 || - query.AggregateOperator == v3.AggregateOperatorHistQuant95 || - query.AggregateOperator == v3.AggregateOperatorHistQuant99 { - query.AggregateAttribute.Type = "Histogram" - } - query.AggregateAttribute.DataType = v3.AttributeKeyDataTypeFloat64 - query.AggregateAttribute.IsColumn = true - query.TimeAggregation = mapTimeAggregation[query.AggregateOperator] - query.SpaceAggregation = mapSpaceAggregation[query.AggregateOperator] - query.AggregateOperator = v3.AggregateOperator(query.TimeAggregation) - updated = true - } - } - } - } - } - - if !updated { - zap.L().Info("Rule not updated", zap.Int("rule", storedRule.Id)) - continue - } - - ruleJSON, jsonErr := json.Marshal(parsedRule) - if jsonErr != nil { - zap.L().Error("Error marshalling rule; skipping rule migration", zap.Error(jsonErr), zap.Int("rule", storedRule.Id)) - continue - } - - stmt, prepareError := conn.PrepareContext(context.Background(), `UPDATE rules SET data=$3 WHERE id=$4;`) - if prepareError != nil { - zap.L().Error("Error in preparing statement for UPDATE to rules", zap.Error(prepareError)) - continue - } - defer stmt.Close() - - if _, err := stmt.Exec(ruleJSON, storedRule.Id); err != nil { - zap.L().Error("Error in Executing prepared statement for UPDATE to rules", zap.Error(err)) - } - } - return nil -} diff --git a/pkg/query-service/migrate/0_47_alerts_custom_step/run.go b/pkg/query-service/migrate/0_47_alerts_custom_step/run.go deleted file mode 100644 index b25705aaf2..0000000000 --- a/pkg/query-service/migrate/0_47_alerts_custom_step/run.go +++ /dev/null @@ -1,70 +0,0 @@ -package alertscustomstep - -import ( - "context" - "encoding/json" - "time" - - "github.com/jmoiron/sqlx" - v3 "go.signoz.io/signoz/pkg/query-service/model/v3" - "go.signoz.io/signoz/pkg/query-service/rules" - "go.uber.org/multierr" - "go.uber.org/zap" -) - -var Version = "0.47-alerts-custom-step" - -func Migrate(conn *sqlx.DB) error { - ruleDB := rules.NewRuleDB(conn) - storedRules, err := ruleDB.GetStoredRules(context.Background()) - if err != nil { - return err - } - - for _, storedRule := range storedRules { - parsedRule, errs := rules.ParsePostableRule([]byte(storedRule.Data)) - if len(errs) > 0 { - // this should not happen but if it does, we should not stop the migration - zap.L().Error("Error parsing rule", zap.Error(multierr.Combine(errs...)), zap.Int("rule", storedRule.Id)) - continue - } - zap.L().Info("Rule parsed", zap.Int("rule", storedRule.Id)) - updated := false - if parsedRule.RuleCondition != nil { - if parsedRule.RuleCondition.QueryType() == v3.QueryTypeBuilder { - if parsedRule.EvalWindow <= rules.Duration(6*time.Hour) { - for _, query := range parsedRule.RuleCondition.CompositeQuery.BuilderQueries { - if query.StepInterval > 60 { - updated = true - zap.L().Info("Updating step interval", zap.Int("rule", storedRule.Id), zap.Int64("old", query.StepInterval), zap.Int64("new", 60)) - query.StepInterval = 60 - } - } - } - } - } - - if !updated { - zap.L().Info("Rule not updated", zap.Int("rule", storedRule.Id)) - continue - } - - ruleJSON, jsonErr := json.Marshal(parsedRule) - if jsonErr != nil { - zap.L().Error("Error marshalling rule; skipping rule migration", zap.Error(jsonErr), zap.Int("rule", storedRule.Id)) - continue - } - - stmt, prepareError := conn.PrepareContext(context.Background(), `UPDATE rules SET data=$3 WHERE id=$4;`) - if prepareError != nil { - zap.L().Error("Error in preparing statement for UPDATE to rules", zap.Error(prepareError)) - continue - } - defer stmt.Close() - - if _, err := stmt.Exec(ruleJSON, storedRule.Id); err != nil { - zap.L().Error("Error in Executing prepared statement for UPDATE to rules", zap.Error(err)) - } - } - return nil -} diff --git a/pkg/query-service/migrate/migate.go b/pkg/query-service/migrate/migate.go index bf5f3a7738..60e65d6d72 100644 --- a/pkg/query-service/migrate/migate.go +++ b/pkg/query-service/migrate/migate.go @@ -7,9 +7,6 @@ import ( "github.com/ClickHouse/clickhouse-go/v2/lib/driver" "github.com/jmoiron/sqlx" - alertstov4 "go.signoz.io/signoz/pkg/query-service/migrate/0_45_alerts_to_v4" - alertscustomstep "go.signoz.io/signoz/pkg/query-service/migrate/0_47_alerts_custom_step" - "go.uber.org/zap" ) type DataMigration struct { @@ -56,28 +53,6 @@ func Migrate(dsn string) error { return err } - if m, err := getMigrationVersion(conn, "0.45_alerts_to_v4"); err == nil && m == nil { - if err := alertstov4.Migrate(conn); err != nil { - zap.L().Error("failed to migrate 0.45_alerts_to_v4", zap.Error(err)) - } else { - _, err := conn.Exec("INSERT INTO data_migrations (version, succeeded) VALUES ('0.45_alerts_to_v4', true)") - if err != nil { - return err - } - } - } - - if m, err := getMigrationVersion(conn, "0.47_alerts_custom_step"); err == nil && m == nil { - if err := alertscustomstep.Migrate(conn); err != nil { - zap.L().Error("failed to migrate 0.47_alerts_custom_step", zap.Error(err)) - } else { - _, err := conn.Exec("INSERT INTO data_migrations (version, succeeded) VALUES ('0.47_alerts_custom_step', true)") - if err != nil { - return err - } - } - } - return nil } diff --git a/pkg/query-service/rules/alerting.go b/pkg/query-service/rules/alerting.go index 36a0ea1b69..7c7fb40ed6 100644 --- a/pkg/query-service/rules/alerting.go +++ b/pkg/query-service/rules/alerting.go @@ -61,6 +61,35 @@ func (s AlertState) String() string { panic(errors.Errorf("unknown alert state: %d", s)) } +func (s AlertState) MarshalJSON() ([]byte, error) { + return json.Marshal(s.String()) +} + +func (s *AlertState) UnmarshalJSON(b []byte) error { + var v interface{} + if err := json.Unmarshal(b, &v); err != nil { + return err + } + switch value := v.(type) { + case string: + switch value { + case "inactive": + *s = StateInactive + case "pending": + *s = StatePending + case "firing": + *s = StateFiring + case "disabled": + *s = StateDisabled + default: + return errors.New("invalid alert state") + } + return nil + default: + return errors.New("invalid alert state") + } +} + type Alert struct { State AlertState diff --git a/pkg/query-service/rules/api_params.go b/pkg/query-service/rules/api_params.go index 74ca041aae..890d464671 100644 --- a/pkg/query-service/rules/api_params.go +++ b/pkg/query-service/rules/api_params.go @@ -16,6 +16,22 @@ import ( yaml "gopkg.in/yaml.v2" ) +type AlertType string + +const ( + AlertTypeMetric AlertType = "METRIC_BASED_ALERT" + AlertTypeTraces AlertType = "TRACES_BASED_ALERT" + AlertTypeLogs AlertType = "LOGS_BASED_ALERT" + AlertTypeExceptions AlertType = "EXCEPTIONS_BASED_ALERT" +) + +type RuleDataKind string + +const ( + RuleDataKindJson RuleDataKind = "json" + RuleDataKindYaml RuleDataKind = "yaml" +) + // this file contains api request and responses to be // served over http @@ -31,12 +47,12 @@ func newApiErrorBadData(err error) *model.ApiError { // PostableRule is used to create alerting rule from HTTP api type PostableRule struct { - AlertName string `yaml:"alert,omitempty" json:"alert,omitempty"` - AlertType string `yaml:"alertType,omitempty" json:"alertType,omitempty"` - Description string `yaml:"description,omitempty" json:"description,omitempty"` - RuleType RuleType `yaml:"ruleType,omitempty" json:"ruleType,omitempty"` - EvalWindow Duration `yaml:"evalWindow,omitempty" json:"evalWindow,omitempty"` - Frequency Duration `yaml:"frequency,omitempty" json:"frequency,omitempty"` + AlertName string `yaml:"alert,omitempty" json:"alert,omitempty"` + AlertType AlertType `yaml:"alertType,omitempty" json:"alertType,omitempty"` + Description string `yaml:"description,omitempty" json:"description,omitempty"` + RuleType RuleType `yaml:"ruleType,omitempty" json:"ruleType,omitempty"` + EvalWindow Duration `yaml:"evalWindow,omitempty" json:"evalWindow,omitempty"` + Frequency Duration `yaml:"frequency,omitempty" json:"frequency,omitempty"` RuleCondition *RuleCondition `yaml:"condition,omitempty" json:"condition,omitempty"` Labels map[string]string `yaml:"labels,omitempty" json:"labels,omitempty"` @@ -234,8 +250,8 @@ type GettableRules struct { // GettableRule has info for an alerting rules. type GettableRule struct { - Id string `json:"id"` - State string `json:"state"` + Id string `json:"id"` + State AlertState `json:"state"` PostableRule CreatedAt *time.Time `json:"createAt"` CreatedBy *string `json:"createBy"` diff --git a/pkg/query-service/rules/db.go b/pkg/query-service/rules/db.go index 37e45f2711..d9a9be195c 100644 --- a/pkg/query-service/rules/db.go +++ b/pkg/query-service/rules/db.go @@ -325,9 +325,9 @@ func (r *ruleDB) GetAlertsInfo(ctx context.Context) (*model.AlertsInfo, error) { continue } alertNames = append(alertNames, rule.AlertName) - if rule.AlertType == "LOGS_BASED_ALERT" { + if rule.AlertType == AlertTypeLogs { alertsInfo.LogsBasedAlerts = alertsInfo.LogsBasedAlerts + 1 - } else if rule.AlertType == "METRIC_BASED_ALERT" { + } else if rule.AlertType == AlertTypeMetric { alertsInfo.MetricBasedAlerts = alertsInfo.MetricBasedAlerts + 1 if rule.RuleCondition != nil && rule.RuleCondition.CompositeQuery != nil { if rule.RuleCondition.CompositeQuery.QueryType == v3.QueryTypeBuilder { @@ -343,7 +343,7 @@ func (r *ruleDB) GetAlertsInfo(ctx context.Context) (*model.AlertsInfo, error) { } } } - } else if rule.AlertType == "TRACES_BASED_ALERT" { + } else if rule.AlertType == AlertTypeTraces { alertsInfo.TracesBasedAlerts = alertsInfo.TracesBasedAlerts + 1 } alertsInfo.TotalAlerts = alertsInfo.TotalAlerts + 1 diff --git a/pkg/query-service/rules/manager.go b/pkg/query-service/rules/manager.go index 40764f9fb0..f738fefcc7 100644 --- a/pkg/query-service/rules/manager.go +++ b/pkg/query-service/rules/manager.go @@ -20,11 +20,9 @@ import ( "github.com/jmoiron/sqlx" - // opentracing "github.com/opentracing/opentracing-go" am "go.signoz.io/signoz/pkg/query-service/integrations/alertManager" "go.signoz.io/signoz/pkg/query-service/interfaces" "go.signoz.io/signoz/pkg/query-service/model" - v3 "go.signoz.io/signoz/pkg/query-service/model/v3" "go.signoz.io/signoz/pkg/query-service/telemetry" "go.signoz.io/signoz/pkg/query-service/utils/labels" ) @@ -240,20 +238,6 @@ func (m *Manager) EditRule(ctx context.Context, ruleStr string, id string) error parsedRule, errs := ParsePostableRule([]byte(ruleStr)) - currentRule, err := m.GetRule(ctx, id) - if err != nil { - zap.L().Error("failed to get the rule from rule db", zap.String("id", id), zap.Error(err)) - return err - } - - if !checkIfTraceOrLogQB(¤tRule.PostableRule) { - // check if the new rule uses any feature that is not enabled - err = m.checkFeatureUsage(parsedRule) - if err != nil { - return err - } - } - if len(errs) > 0 { zap.L().Error("failed to parse rules", zap.Errors("errors", errs)) // just one rule is being parsed so expect just one error @@ -272,20 +256,6 @@ func (m *Manager) EditRule(ctx context.Context, ruleStr string, id string) error } } - // update feature usage if the current rule is not a trace or log query builder - if !checkIfTraceOrLogQB(¤tRule.PostableRule) { - err = m.updateFeatureUsage(parsedRule, 1) - if err != nil { - zap.L().Error("error updating feature usage", zap.Error(err)) - } - // update feature usage if the new rule is not a trace or log query builder and the current rule is - } else if !checkIfTraceOrLogQB(parsedRule) { - err = m.updateFeatureUsage(¤tRule.PostableRule, -1) - if err != nil { - zap.L().Error("error updating feature usage", zap.Error(err)) - } - } - return nil } @@ -335,13 +305,6 @@ func (m *Manager) DeleteRule(ctx context.Context, id string) error { return fmt.Errorf("delete rule received an rule id in invalid format, must be a number") } - // update feature usage - rule, err := m.GetRule(ctx, id) - if err != nil { - zap.L().Error("failed to get the rule from rule db", zap.String("id", id), zap.Error(err)) - return err - } - taskName := prepareTaskName(int64(idInt)) if !m.opts.DisableRules { m.deleteTask(taskName) @@ -352,11 +315,6 @@ func (m *Manager) DeleteRule(ctx context.Context, id string) error { return err } - err = m.updateFeatureUsage(&rule.PostableRule, -1) - if err != nil { - zap.L().Error("error updating feature usage", zap.Error(err)) - } - return nil } @@ -381,12 +339,6 @@ func (m *Manager) deleteTask(taskName string) { func (m *Manager) CreateRule(ctx context.Context, ruleStr string) (*GettableRule, error) { parsedRule, errs := ParsePostableRule([]byte(ruleStr)) - // check if the rule uses any feature that is not enabled - err := m.checkFeatureUsage(parsedRule) - if err != nil { - return nil, err - } - if len(errs) > 0 { zap.L().Error("failed to parse rules", zap.Errors("errors", errs)) // just one rule is being parsed so expect just one error @@ -409,11 +361,6 @@ func (m *Manager) CreateRule(ctx context.Context, ruleStr string) (*GettableRule return nil, err } - // update feature usage - err = m.updateFeatureUsage(parsedRule, 1) - if err != nil { - zap.L().Error("error updating feature usage", zap.Error(err)) - } gettableRule := &GettableRule{ Id: fmt.Sprintf("%d", lastInsertId), PostableRule: *parsedRule, @@ -421,59 +368,6 @@ func (m *Manager) CreateRule(ctx context.Context, ruleStr string) (*GettableRule return gettableRule, nil } -func (m *Manager) updateFeatureUsage(parsedRule *PostableRule, usage int64) error { - isTraceOrLogQB := checkIfTraceOrLogQB(parsedRule) - if isTraceOrLogQB { - feature, err := m.featureFlags.GetFeatureFlag(model.QueryBuilderAlerts) - if err != nil { - return err - } - feature.Usage += usage - if feature.Usage == feature.UsageLimit && feature.UsageLimit != -1 { - feature.Active = false - } - if feature.Usage < feature.UsageLimit || feature.UsageLimit == -1 { - feature.Active = true - } - err = m.featureFlags.UpdateFeatureFlag(feature) - if err != nil { - return err - } - } - return nil -} - -func (m *Manager) checkFeatureUsage(parsedRule *PostableRule) error { - isTraceOrLogQB := checkIfTraceOrLogQB(parsedRule) - if isTraceOrLogQB { - err := m.featureFlags.CheckFeature(model.QueryBuilderAlerts) - if err != nil { - switch err.(type) { - case model.ErrFeatureUnavailable: - zap.L().Error("feature unavailable", zap.String("featureKey", model.QueryBuilderAlerts), zap.Error(err)) - return model.BadRequest(err) - default: - zap.L().Error("feature check failed", zap.String("featureKey", model.QueryBuilderAlerts), zap.Error(err)) - return model.BadRequest(err) - } - } - } - return nil -} - -func checkIfTraceOrLogQB(parsedRule *PostableRule) bool { - if parsedRule != nil { - if parsedRule.RuleCondition.QueryType() == v3.QueryTypeBuilder { - for _, query := range parsedRule.RuleCondition.CompositeQuery.BuilderQueries { - if query.DataSource == v3.DataSourceTraces || query.DataSource == v3.DataSourceLogs { - return true - } - } - } - } - return false -} - func (m *Manager) addTask(rule *PostableRule, taskName string) error { m.mtx.Lock() defer m.mtx.Unlock() @@ -569,7 +463,7 @@ func (m *Manager) prepareTask(acquireLock bool, r *PostableRule, taskName string m.rules[ruleId] = pr } else { - return nil, fmt.Errorf(fmt.Sprintf("unsupported rule type. Supported types: %s, %s", RuleTypeProm, RuleTypeThreshold)) + return nil, fmt.Errorf("unsupported rule type. Supported types: %s, %s", RuleTypeProm, RuleTypeThreshold) } return task, nil @@ -710,10 +604,10 @@ func (m *Manager) ListRuleStates(ctx context.Context) (*GettableRules, error) { // fetch state of rule from memory if rm, ok := m.rules[ruleResponse.Id]; !ok { - ruleResponse.State = StateDisabled.String() + ruleResponse.State = StateDisabled ruleResponse.Disabled = true } else { - ruleResponse.State = rm.State().String() + ruleResponse.State = rm.State() } ruleResponse.CreatedAt = s.CreatedAt ruleResponse.CreatedBy = s.CreatedBy @@ -737,10 +631,10 @@ func (m *Manager) GetRule(ctx context.Context, id string) (*GettableRule, error) r.Id = fmt.Sprintf("%d", s.Id) // fetch state of rule from memory if rm, ok := m.rules[r.Id]; !ok { - r.State = StateDisabled.String() + r.State = StateDisabled r.Disabled = true } else { - r.State = rm.State().String() + r.State = rm.State() } r.CreatedAt = s.CreatedAt r.CreatedBy = s.CreatedBy @@ -846,10 +740,10 @@ func (m *Manager) PatchRule(ctx context.Context, ruleStr string, ruleId string) // fetch state of rule from memory if rm, ok := m.rules[ruleId]; !ok { - response.State = StateDisabled.String() + response.State = StateDisabled response.Disabled = true } else { - response.State = rm.State().String() + response.State = rm.State() } return &response, nil diff --git a/pkg/query-service/rules/threshold_rule.go b/pkg/query-service/rules/threshold_rule.go index 5093e407dc..9bdecbc63d 100644 --- a/pkg/query-service/rules/threshold_rule.go +++ b/pkg/query-service/rules/threshold_rule.go @@ -91,8 +91,7 @@ type ThresholdRule struct { lastTimestampWithDatapoints time.Time // Type of the rule - // One of ["LOGS_BASED_ALERT", "TRACES_BASED_ALERT", "METRIC_BASED_ALERT", "EXCEPTIONS_BASED_ALERT"] - typ string + typ AlertType // querier is used for alerts created before the introduction of new metrics query builder querier interfaces.Querier @@ -975,12 +974,12 @@ func (r *ThresholdRule) Eval(ctx context.Context, ts time.Time, queriers *Querie // Links with timestamps should go in annotations since labels // is used alert grouping, and we want to group alerts with the same // label set, but different timestamps, together. - if r.typ == "TRACES_BASED_ALERT" { + if r.typ == AlertTypeTraces { link := r.prepareLinksToTraces(ts, smpl.MetricOrig) if link != "" && r.hostFromSource() != "" { annotations = append(annotations, labels.Label{Name: "related_traces", Value: fmt.Sprintf("%s/traces-explorer?%s", r.hostFromSource(), link)}) } - } else if r.typ == "LOGS_BASED_ALERT" { + } else if r.typ == AlertTypeLogs { link := r.prepareLinksToLogs(ts, smpl.MetricOrig) if link != "" && r.hostFromSource() != "" { annotations = append(annotations, labels.Label{Name: "related_logs", Value: fmt.Sprintf("%s/logs/logs-explorer?%s", r.hostFromSource(), link)}) diff --git a/pkg/query-service/rules/threshold_rule_test.go b/pkg/query-service/rules/threshold_rule_test.go index 55a831efcd..05bd613900 100644 --- a/pkg/query-service/rules/threshold_rule_test.go +++ b/pkg/query-service/rules/threshold_rule_test.go @@ -674,7 +674,7 @@ func TestNormalizeLabelName(t *testing.T) { func TestPrepareLinksToLogs(t *testing.T) { postableRule := PostableRule{ AlertName: "Tricky Condition Tests", - AlertType: "LOGS_BASED_ALERT", + AlertType: AlertTypeLogs, RuleType: RuleTypeThreshold, EvalWindow: Duration(5 * time.Minute), Frequency: Duration(1 * time.Minute),