2024-11-08 21:10:09 +05:30
package rules
import (
"context"
"fmt"
"time"
2025-03-20 21:01:41 +05:30
"github.com/SigNoz/signoz/pkg/query-service/model"
"github.com/SigNoz/signoz/pkg/query-service/utils/labels"
2025-04-18 00:04:25 +05:30
ruletypes "github.com/SigNoz/signoz/pkg/types/ruletypes"
2024-11-08 21:10:09 +05:30
"github.com/google/uuid"
"go.uber.org/zap"
)
// TestNotification prepares a dummy rule for given rule parameters and
// sends a test notification. returns alert count and error (if any)
func defaultTestNotification ( opts PrepareTestRuleOptions ) ( int , * model . ApiError ) {
ctx := context . Background ( )
if opts . Rule == nil {
return 0 , model . BadRequest ( fmt . Errorf ( "rule is required" ) )
}
parsedRule := opts . Rule
var alertname = parsedRule . AlertName
if alertname == "" {
// alertname is not mandatory for testing, so picking
// a random string here
alertname = uuid . New ( ) . String ( )
}
// append name to indicate this is test alert
2025-04-18 00:04:25 +05:30
parsedRule . AlertName = fmt . Sprintf ( "%s%s" , alertname , ruletypes . TestAlertPostFix )
2024-11-08 21:10:09 +05:30
var rule Rule
var err error
2025-04-18 00:04:25 +05:30
if parsedRule . RuleType == ruletypes . RuleTypeThreshold {
2024-11-08 21:10:09 +05:30
// add special labels for test alerts
parsedRule . Annotations [ labels . AlertSummaryLabel ] = fmt . Sprintf ( "The rule threshold is set to %.4f, and the observed metric value is {{$value}}." , * parsedRule . RuleCondition . Target )
parsedRule . Labels [ labels . RuleSourceLabel ] = ""
parsedRule . Labels [ labels . AlertRuleIdLabel ] = ""
// create a threshold rule
rule , err = NewThresholdRule (
alertname ,
2025-05-03 18:30:07 +05:30
opts . OrgID ,
2024-11-08 21:10:09 +05:30
parsedRule ,
opts . Reader ,
2025-07-30 19:25:27 +05:30
opts . Querier ,
opts . SLogger ,
2024-11-08 21:10:09 +05:30
WithSendAlways ( ) ,
WithSendUnmatched ( ) ,
2025-03-10 01:30:42 +05:30
WithSQLStore ( opts . SQLStore ) ,
2024-11-08 21:10:09 +05:30
)
if err != nil {
2025-05-03 18:30:07 +05:30
zap . L ( ) . Error ( "failed to prepare a new threshold rule for test" , zap . Error ( err ) )
2024-11-08 21:10:09 +05:30
return 0 , model . BadRequest ( err )
}
2025-04-18 00:04:25 +05:30
} else if parsedRule . RuleType == ruletypes . RuleTypeProm {
2024-11-08 21:10:09 +05:30
// create promql rule
rule , err = NewPromRule (
alertname ,
2025-05-03 18:30:07 +05:30
opts . OrgID ,
2024-11-08 21:10:09 +05:30
parsedRule ,
2025-07-30 19:25:27 +05:30
opts . SLogger ,
2024-11-08 21:10:09 +05:30
opts . Reader ,
2025-03-31 19:41:11 +05:30
opts . ManagerOpts . Prometheus ,
2024-11-08 21:10:09 +05:30
WithSendAlways ( ) ,
WithSendUnmatched ( ) ,
2025-03-10 01:30:42 +05:30
WithSQLStore ( opts . SQLStore ) ,
2024-11-08 21:10:09 +05:30
)
if err != nil {
2025-05-03 18:30:07 +05:30
zap . L ( ) . Error ( "failed to prepare a new promql rule for test" , zap . Error ( err ) )
2024-11-08 21:10:09 +05:30
return 0 , model . BadRequest ( err )
}
} else {
return 0 , model . BadRequest ( fmt . Errorf ( "failed to derive ruletype with given information" ) )
}
// set timestamp to current utc time
ts := time . Now ( ) . UTC ( )
count , err := rule . Eval ( ctx , ts )
if err != nil {
zap . L ( ) . Error ( "evaluating rule failed" , zap . String ( "rule" , rule . Name ( ) ) , zap . Error ( err ) )
return 0 , model . InternalError ( fmt . Errorf ( "rule evaluation failed" ) )
}
alertsFound , ok := count . ( int )
if ! ok {
return 0 , model . InternalError ( fmt . Errorf ( "something went wrong" ) )
}
rule . SendAlerts ( ctx , ts , 0 , time . Duration ( 1 * time . Minute ) , opts . NotifyFunc )
return alertsFound , nil
}