mirror of
https://github.com/SigNoz/signoz.git
synced 2026-02-09 03:02:20 +00:00
Compare commits
2 Commits
query-rang
...
chore/post
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0752c867d2 | ||
|
|
cc7895e398 |
@@ -11,6 +11,7 @@ import (
|
||||
signozError "github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/query-service/model"
|
||||
v3 "github.com/SigNoz/signoz/pkg/query-service/model/v3"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/query-service/utils/times"
|
||||
"github.com/SigNoz/signoz/pkg/query-service/utils/timestamp"
|
||||
@@ -30,6 +31,9 @@ const (
|
||||
|
||||
const (
|
||||
DefaultSchemaVersion = "v1"
|
||||
// No schema version means the rule is not schema versioned
|
||||
// and the rule is in the old format
|
||||
NoSchemaVersion = ""
|
||||
)
|
||||
|
||||
type RuleDataKind string
|
||||
@@ -304,6 +308,39 @@ func isValidLabelValue(v string) bool {
|
||||
return utf8.ValidString(v)
|
||||
}
|
||||
|
||||
// isValidAlertType validates that the AlertType is one of the allowed enum values
|
||||
func isValidAlertType(alertType AlertType) bool {
|
||||
switch alertType {
|
||||
case AlertTypeMetric, AlertTypeTraces, AlertTypeLogs, AlertTypeExceptions:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// isValidRuleType validates that the RuleType is one of the allowed enum values
|
||||
func isValidRuleType(ruleType RuleType) bool {
|
||||
switch ruleType {
|
||||
case RuleTypeThreshold, RuleTypeProm, RuleTypeAnomaly:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// isValidVersion validates that the version is one of the supported versions
|
||||
func isValidVersion(version string) bool {
|
||||
if version == "" {
|
||||
return true // empty version is allowed (optional field)
|
||||
}
|
||||
switch version {
|
||||
case "v3", "v4", "v5":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func isAllQueriesDisabled(compositeQuery *v3.CompositeQuery) bool {
|
||||
if compositeQuery == nil {
|
||||
return false
|
||||
@@ -359,6 +396,35 @@ func (r *PostableRule) validate() error {
|
||||
errs = append(errs, signozError.NewInvalidInputf(signozError.CodeInvalidInput, "all queries are disabled in rule condition"))
|
||||
}
|
||||
|
||||
// Validate AlertName - required field
|
||||
if r.AlertName == "" {
|
||||
// errs = append(errs, signozError.NewInvalidInputf(signozError.CodeInvalidInput, "alert name is required"))
|
||||
zap.L().Warn("expected validation error in PostableRule.validate: alert name is required")
|
||||
}
|
||||
|
||||
// Validate AlertType - must be one of the allowed enum values
|
||||
if !isValidAlertType(r.AlertType) {
|
||||
// errs = append(errs, signozError.NewInvalidInputf(signozError.CodeInvalidInput, "invalid alert type: %s, must be one of: METRIC_BASED_ALERT, TRACES_BASED_ALERT, LOGS_BASED_ALERT, EXCEPTIONS_BASED_ALERT", r.AlertType))
|
||||
zap.L().Warn("expected validation error in PostableRule.validate: invalid alert type", zap.Any("alertType", r.AlertType))
|
||||
}
|
||||
|
||||
// Validate RuleType - must be one of the allowed enum values
|
||||
if !isValidRuleType(r.RuleType) {
|
||||
// errs = append(errs, signozError.NewInvalidInputf(signozError.CodeInvalidInput, "invalid rule type: %s, must be one of: threshold_rule, promql_rule, anomaly_rule", r.RuleType))
|
||||
zap.L().Warn("expected validation error in PostableRule.validate: invalid rule type", zap.Any("ruleType", r.RuleType))
|
||||
}
|
||||
|
||||
// Validate Version - must be one of the supported versions if provided
|
||||
if !isValidVersion(r.Version) {
|
||||
// errs = append(errs, signozError.NewInvalidInputf(signozError.CodeInvalidInput, "invalid version: %s, must be one of: v3, v4, v5", r.Version))
|
||||
zap.L().Warn("expected validation error in PostableRule.validate: invalid version", zap.Any("version", r.Version))
|
||||
}
|
||||
|
||||
// Notification channel should be provided for older schema versions where there was no schema
|
||||
if r.SchemaVersion == NoSchemaVersion && len(r.PreferredChannels) == 0 {
|
||||
errs = append(errs, signozError.NewInvalidInputf(signozError.CodeInvalidInput, "at least one notification channel is required"))
|
||||
}
|
||||
|
||||
for k, v := range r.Labels {
|
||||
if !isValidLabelName(k) {
|
||||
errs = append(errs, signozError.NewInvalidInputf(signozError.CodeInvalidInput, "invalid label name: %s", k))
|
||||
|
||||
@@ -111,8 +111,10 @@ func TestParseIntoRule(t *testing.T) {
|
||||
"condition": {
|
||||
"compositeQuery": {
|
||||
"queryType": "builder",
|
||||
"panelType": "graph",
|
||||
"builderQueries": {
|
||||
"A": {
|
||||
"queryName": "A",
|
||||
"expression": "A",
|
||||
"disabled": false,
|
||||
"aggregateAttribute": {
|
||||
@@ -149,10 +151,12 @@ func TestParseIntoRule(t *testing.T) {
|
||||
initRule: PostableRule{},
|
||||
content: []byte(`{
|
||||
"alert": "DefaultsRule",
|
||||
"alertType": "METRIC_BASED_ALERT",
|
||||
"ruleType": "threshold_rule",
|
||||
"condition": {
|
||||
"compositeQuery": {
|
||||
"queryType": "builder",
|
||||
"panelType": "graph",
|
||||
"builderQueries": {
|
||||
"A": {
|
||||
"disabled": false,
|
||||
@@ -187,9 +191,11 @@ func TestParseIntoRule(t *testing.T) {
|
||||
initRule: PostableRule{},
|
||||
content: []byte(`{
|
||||
"alert": "PromQLRule",
|
||||
"alertType": "METRIC_BASED_ALERT",
|
||||
"condition": {
|
||||
"compositeQuery": {
|
||||
"queryType": "promql",
|
||||
"panelType": "graph",
|
||||
"promQueries": {
|
||||
"A": {
|
||||
"query": "rate(http_requests_total[5m])",
|
||||
@@ -255,10 +261,12 @@ func TestParseIntoRuleSchemaVersioning(t *testing.T) {
|
||||
initRule: PostableRule{},
|
||||
content: []byte(`{
|
||||
"alert": "SeverityLabelTest",
|
||||
"alertType": "METRIC_BASED_ALERT",
|
||||
"schemaVersion": "v1",
|
||||
"condition": {
|
||||
"compositeQuery": {
|
||||
"queryType": "builder",
|
||||
"panelType": "graph",
|
||||
"builderQueries": {
|
||||
"A": {
|
||||
"aggregateAttribute": {
|
||||
@@ -343,10 +351,12 @@ func TestParseIntoRuleSchemaVersioning(t *testing.T) {
|
||||
initRule: PostableRule{},
|
||||
content: []byte(`{
|
||||
"alert": "NoLabelsTest",
|
||||
"alertType": "METRIC_BASED_ALERT",
|
||||
"schemaVersion": "v1",
|
||||
"condition": {
|
||||
"compositeQuery": {
|
||||
"queryType": "builder",
|
||||
"panelType": "graph",
|
||||
"builderQueries": {
|
||||
"A": {
|
||||
"aggregateAttribute": {
|
||||
@@ -383,10 +393,12 @@ func TestParseIntoRuleSchemaVersioning(t *testing.T) {
|
||||
initRule: PostableRule{},
|
||||
content: []byte(`{
|
||||
"alert": "OverwriteTest",
|
||||
"alertType": "METRIC_BASED_ALERT",
|
||||
"schemaVersion": "v1",
|
||||
"condition": {
|
||||
"compositeQuery": {
|
||||
"queryType": "builder",
|
||||
"panelType": "graph",
|
||||
"builderQueries": {
|
||||
"A": {
|
||||
"aggregateAttribute": {
|
||||
@@ -473,10 +485,12 @@ func TestParseIntoRuleSchemaVersioning(t *testing.T) {
|
||||
initRule: PostableRule{},
|
||||
content: []byte(`{
|
||||
"alert": "V2Test",
|
||||
"alertType": "METRIC_BASED_ALERT",
|
||||
"schemaVersion": "v2",
|
||||
"condition": {
|
||||
"compositeQuery": {
|
||||
"queryType": "builder",
|
||||
"panelType": "graph",
|
||||
"builderQueries": {
|
||||
"A": {
|
||||
"aggregateAttribute": {
|
||||
@@ -517,9 +531,11 @@ func TestParseIntoRuleSchemaVersioning(t *testing.T) {
|
||||
initRule: PostableRule{},
|
||||
content: []byte(`{
|
||||
"alert": "DefaultSchemaTest",
|
||||
"alertType": "METRIC_BASED_ALERT",
|
||||
"condition": {
|
||||
"compositeQuery": {
|
||||
"queryType": "builder",
|
||||
"panelType": "graph",
|
||||
"builderQueries": {
|
||||
"A": {
|
||||
"aggregateAttribute": {
|
||||
@@ -569,12 +585,16 @@ func TestParseIntoRuleSchemaVersioning(t *testing.T) {
|
||||
func TestParseIntoRuleThresholdGeneration(t *testing.T) {
|
||||
content := []byte(`{
|
||||
"alert": "TestThresholds",
|
||||
"alertType": "METRIC_BASED_ALERT",
|
||||
"condition": {
|
||||
"compositeQuery": {
|
||||
"queryType": "builder",
|
||||
"panelType": "graph",
|
||||
"builderQueries": {
|
||||
"A": {
|
||||
"queryName": "A",
|
||||
"expression": "A",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"aggregateAttribute": {
|
||||
"key": "response_time"
|
||||
@@ -638,14 +658,18 @@ func TestParseIntoRuleMultipleThresholds(t *testing.T) {
|
||||
content := []byte(`{
|
||||
"schemaVersion": "v2",
|
||||
"alert": "MultiThresholdAlert",
|
||||
"alertType": "METRIC_BASED_ALERT",
|
||||
"ruleType": "threshold_rule",
|
||||
"condition": {
|
||||
"compositeQuery": {
|
||||
"queryType": "builder",
|
||||
"panelType": "graph",
|
||||
"unit": "%",
|
||||
"builderQueries": {
|
||||
"A": {
|
||||
"queryName": "A",
|
||||
"expression": "A",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"aggregateAttribute": {
|
||||
"key": "cpu_usage"
|
||||
@@ -731,10 +755,12 @@ func TestAnomalyNegationEval(t *testing.T) {
|
||||
name: "anomaly rule with ValueIsBelow - should alert",
|
||||
ruleJSON: []byte(`{
|
||||
"alert": "AnomalyBelowTest",
|
||||
"alertType": "METRIC_BASED_ALERT",
|
||||
"ruleType": "anomaly_rule",
|
||||
"condition": {
|
||||
"compositeQuery": {
|
||||
"queryType": "builder",
|
||||
"panelType": "graph",
|
||||
"queries": [{
|
||||
"type": "builder_query",
|
||||
"spec": {
|
||||
@@ -765,10 +791,12 @@ func TestAnomalyNegationEval(t *testing.T) {
|
||||
name: "anomaly rule with ValueIsBelow; should not alert",
|
||||
ruleJSON: []byte(`{
|
||||
"alert": "AnomalyBelowTest",
|
||||
"alertType": "METRIC_BASED_ALERT",
|
||||
"ruleType": "anomaly_rule",
|
||||
"condition": {
|
||||
"compositeQuery": {
|
||||
"queryType": "builder",
|
||||
"panelType": "graph",
|
||||
"queries": [{
|
||||
"type": "builder_query",
|
||||
"spec": {
|
||||
@@ -798,10 +826,12 @@ func TestAnomalyNegationEval(t *testing.T) {
|
||||
name: "anomaly rule with ValueIsAbove; should alert",
|
||||
ruleJSON: []byte(`{
|
||||
"alert": "AnomalyAboveTest",
|
||||
"alertType": "METRIC_BASED_ALERT",
|
||||
"ruleType": "anomaly_rule",
|
||||
"condition": {
|
||||
"compositeQuery": {
|
||||
"queryType": "builder",
|
||||
"panelType": "graph",
|
||||
"queries": [{
|
||||
"type": "builder_query",
|
||||
"spec": {
|
||||
@@ -832,10 +862,12 @@ func TestAnomalyNegationEval(t *testing.T) {
|
||||
name: "anomaly rule with ValueIsAbove; should not alert",
|
||||
ruleJSON: []byte(`{
|
||||
"alert": "AnomalyAboveTest",
|
||||
"alertType": "METRIC_BASED_ALERT",
|
||||
"ruleType": "anomaly_rule",
|
||||
"condition": {
|
||||
"compositeQuery": {
|
||||
"queryType": "builder",
|
||||
"panelType": "graph",
|
||||
"queries": [{
|
||||
"type": "builder_query",
|
||||
"spec": {
|
||||
@@ -865,10 +897,12 @@ func TestAnomalyNegationEval(t *testing.T) {
|
||||
name: "anomaly rule with ValueIsBelow and AllTheTimes; should alert",
|
||||
ruleJSON: []byte(`{
|
||||
"alert": "AnomalyBelowAllTest",
|
||||
"alertType": "METRIC_BASED_ALERT",
|
||||
"ruleType": "anomaly_rule",
|
||||
"condition": {
|
||||
"compositeQuery": {
|
||||
"queryType": "builder",
|
||||
"panelType": "graph",
|
||||
"queries": [{
|
||||
"type": "builder_query",
|
||||
"spec": {
|
||||
@@ -900,10 +934,12 @@ func TestAnomalyNegationEval(t *testing.T) {
|
||||
name: "anomaly rule with ValueIsBelow and AllTheTimes; should not alert",
|
||||
ruleJSON: []byte(`{
|
||||
"alert": "AnomalyBelowAllTest",
|
||||
"alertType": "METRIC_BASED_ALERT",
|
||||
"ruleType": "anomaly_rule",
|
||||
"condition": {
|
||||
"compositeQuery": {
|
||||
"queryType": "builder",
|
||||
"panelType": "graph",
|
||||
"queries": [{
|
||||
"type": "builder_query",
|
||||
"spec": {
|
||||
@@ -934,10 +970,12 @@ func TestAnomalyNegationEval(t *testing.T) {
|
||||
name: "anomaly rule with ValueOutsideBounds; should alert",
|
||||
ruleJSON: []byte(`{
|
||||
"alert": "AnomalyOutOfBoundsTest",
|
||||
"alertType": "METRIC_BASED_ALERT",
|
||||
"ruleType": "anomaly_rule",
|
||||
"condition": {
|
||||
"compositeQuery": {
|
||||
"queryType": "builder",
|
||||
"panelType": "graph",
|
||||
"queries": [{
|
||||
"type": "builder_query",
|
||||
"spec": {
|
||||
@@ -968,10 +1006,12 @@ func TestAnomalyNegationEval(t *testing.T) {
|
||||
name: "non-anomaly threshold rule with ValueIsBelow; should alert",
|
||||
ruleJSON: []byte(`{
|
||||
"alert": "ThresholdTest",
|
||||
"alertType": "METRIC_BASED_ALERT",
|
||||
"ruleType": "threshold_rule",
|
||||
"condition": {
|
||||
"compositeQuery": {
|
||||
"queryType": "builder",
|
||||
"panelType": "graph",
|
||||
"queries": [{
|
||||
"type": "builder_query",
|
||||
"spec": {
|
||||
@@ -1002,10 +1042,12 @@ func TestAnomalyNegationEval(t *testing.T) {
|
||||
name: "non-anomaly rule with ValueIsBelow - should not alert",
|
||||
ruleJSON: []byte(`{
|
||||
"alert": "ThresholdTest",
|
||||
"alertType": "METRIC_BASED_ALERT",
|
||||
"ruleType": "threshold_rule",
|
||||
"condition": {
|
||||
"compositeQuery": {
|
||||
"queryType": "builder",
|
||||
"panelType": "graph",
|
||||
"queries": [{
|
||||
"type": "builder_query",
|
||||
"spec": {
|
||||
|
||||
Reference in New Issue
Block a user