Files
poimen-workflows/internal/alerting/alert_manager.go
T

218 lines
4.3 KiB
Go
Raw Normal View History

package alerting
import (
"fmt"
"sync"
"time"
)
// AlertLevel represents alert severity
type AlertLevel string
const (
AlertWarning AlertLevel = "warning"
AlertError AlertLevel = "error"
AlertCritical AlertLevel = "critical"
)
// Alert represents an alert notification
type Alert struct {
ID string
Level AlertLevel
Title string
Message string
Timestamp time.Time
Resolved bool
Source string
}
// AlertRule represents a rule that triggers alerts
type AlertRule struct {
ID string
Name string
Threshold float64
Metric string
Level AlertLevel
}
// AlertManager manages alert rules and notifications
type AlertManager struct {
mu sync.RWMutex
rules map[string]*AlertRule
alerts map[string]*Alert
history []*Alert
}
// NewAlertManager creates a new alert manager
func NewAlertManager() *AlertManager {
return &AlertManager{
rules: make(map[string]*AlertRule),
alerts: make(map[string]*Alert),
history: make([]*Alert, 0),
}
}
// AddRule adds an alert rule
func (am *AlertManager) AddRule(rule *AlertRule) error {
if rule.ID == "" || rule.Name == "" {
return fmt.Errorf("rule ID and name required")
}
am.mu.Lock()
defer am.mu.Unlock()
am.rules[rule.ID] = rule
return nil
}
// RemoveRule removes an alert rule
func (am *AlertManager) RemoveRule(ruleID string) error {
am.mu.Lock()
defer am.mu.Unlock()
if _, exists := am.rules[ruleID]; !exists {
return fmt.Errorf("rule not found: %s", ruleID)
}
delete(am.rules, ruleID)
return nil
}
// TriggerAlert triggers a new alert
func (am *AlertManager) TriggerAlert(title, message string, level AlertLevel) (*Alert, error) {
if title == "" {
return nil, fmt.Errorf("alert title required")
}
am.mu.Lock()
defer am.mu.Unlock()
alert := &Alert{
ID: fmt.Sprintf("alert-%d", len(am.alerts)),
Level: level,
Title: title,
Message: message,
Timestamp: time.Now(),
Resolved: false,
}
am.alerts[alert.ID] = alert
am.history = append(am.history, alert)
return alert, nil
}
// ResolveAlert marks an alert as resolved
func (am *AlertManager) ResolveAlert(alertID string) error {
am.mu.Lock()
defer am.mu.Unlock()
alert, exists := am.alerts[alertID]
if !exists {
return fmt.Errorf("alert not found: %s", alertID)
}
alert.Resolved = true
return nil
}
// GetActiveAlerts returns all unresolved alerts
func (am *AlertManager) GetActiveAlerts() []*Alert {
am.mu.RLock()
defer am.mu.RUnlock()
result := make([]*Alert, 0)
for _, alert := range am.alerts {
if !alert.Resolved {
result = append(result, alert)
}
}
return result
}
// GetAlertsByLevel returns alerts by severity level
func (am *AlertManager) GetAlertsByLevel(level AlertLevel) []*Alert {
am.mu.RLock()
defer am.mu.RUnlock()
result := make([]*Alert, 0)
for _, alert := range am.alerts {
if alert.Level == level {
result = append(result, alert)
}
}
return result
}
// GetHistory returns alert history
func (am *AlertManager) GetHistory() []*Alert {
am.mu.RLock()
defer am.mu.RUnlock()
result := make([]*Alert, len(am.history))
copy(result, am.history)
return result
}
// GetRules returns all alert rules
func (am *AlertManager) GetRules() map[string]*AlertRule {
am.mu.RLock()
defer am.mu.RUnlock()
result := make(map[string]*AlertRule)
for id, rule := range am.rules {
result[id] = rule
}
return result
}
// GetAlertCount returns total active alert count
func (am *AlertManager) GetAlertCount() int {
am.mu.RLock()
defer am.mu.RUnlock()
return len(am.alerts)
}
// Clear clears all alerts
func (am *AlertManager) Clear() {
am.mu.Lock()
defer am.mu.Unlock()
am.alerts = make(map[string]*Alert)
}
// EvaluateRule checks if a metric triggers an alert rule
func (am *AlertManager) EvaluateRule(ruleID string, metricValue float64) (*Alert, error) {
am.mu.Lock()
defer am.mu.Unlock()
rule, exists := am.rules[ruleID]
if !exists {
return nil, fmt.Errorf("rule not found: %s", ruleID)
}
if metricValue >= rule.Threshold {
alert := &Alert{
ID: fmt.Sprintf("alert-%d", len(am.alerts)),
Level: rule.Level,
Title: rule.Name,
Message: fmt.Sprintf("Threshold %.2f exceeded: %.2f", rule.Threshold, metricValue),
Timestamp: time.Now(),
Resolved: false,
Source: ruleID,
}
am.alerts[alert.ID] = alert
am.history = append(am.history, alert)
return alert, nil
}
return nil, nil
}