package alerter import ( "context" "log" "time" "github.com/lab/observability-core/internal/db" ) type Alerter struct { queries *db.Queries } func New(queries *db.Queries) *Alerter { return &Alerter{queries: queries} } func (a *Alerter) Start() { log.Println("Starting alerter") ticker := time.NewTicker(30 * time.Second) // Run every 30 seconds go func() { for range ticker.C { a.runAlerts() } }() } func (a *Alerter) runAlerts() { rules, err := a.queries.ListAlertRules(context.Background()) if err != nil { log.Printf("Error listing alert rules: %v", err) return } for _, rule := range rules { go a.evaluateRule(rule) } } func (a *Alerter) evaluateRule(rule db.AlertRule) { // This is a very simplified logic. // It should query metrics within the `for_duration` and check if they meet the threshold. // For now, we'll just log a message. log.Printf("Evaluating alert rule: %s", rule.Name) // A real implementation would look something like this: /* params := db.GetMetricsForCheckParams{ CheckID: rule.CheckID, StartTime: time.Now().Add(-time.Duration(rule.ForDuration) * time.Second), EndTime: time.Now(), } metrics, err := a.queries.GetMetricsForCheck(context.Background(), params) if err != nil { log.Printf("Error getting metrics for rule %s: %v", rule.Name, err) return } isFailing := true for _, metric := range metrics { if !compare(metric.Value, rule.Threshold, rule.Operator) { isFailing = false break } } if isFailing { // Create or update incident } */ } func compare(value, threshold float64, operator string) bool { switch operator { case ">": return value > threshold case "<": return value < threshold case "=": return value == threshold } return false }