feat(alerts): add MasterID to log records and improve traffic spike detection

- Add MasterID field with index to LogRecord model for efficient queries
- Fix threshold config loading to use fixed ID=1 with FirstOrCreate
- Allow traffic spike detection to work without Redis for log-based checks
- Add traffic_spike to API documentation for alert type filter
- Add comprehensive tests for RPM/RPD/TPM spike detection scenarios
This commit is contained in:
zenfun
2025-12-31 18:01:09 +08:00
parent f714a314a9
commit 4cda273f7b
4 changed files with 324 additions and 24 deletions

View File

@@ -326,11 +326,12 @@ func (d *AlertDetector) errorRateSeverity(rate float64) model.AlertSeverity {
return model.AlertSeverityInfo
}
// loadThresholdConfig loads the threshold config from DB or returns defaults
// loadThresholdConfig loads the threshold config from DB with fixed ID=1, or returns defaults
func (d *AlertDetector) loadThresholdConfig() model.AlertThresholdConfig {
var cfg model.AlertThresholdConfig
err := d.db.First(&cfg).Error
if err != nil {
cfg := model.DefaultAlertThresholdConfig()
cfg.ID = 1 // Fixed ID to ensure single config row
if err := d.db.Where("id = ?", 1).FirstOrCreate(&cfg).Error; err != nil {
d.logger.Warn("failed to load threshold config, using defaults", "err", err)
return model.DefaultAlertThresholdConfig()
}
return cfg
@@ -360,19 +361,17 @@ func (m trafficSpikeMetadata) JSON() string {
// detectTrafficSpikes checks for traffic threshold breaches
func (d *AlertDetector) detectTrafficSpikes(ctx context.Context) {
if d.rdb == nil || d.statsService == nil {
return
}
cfg := d.loadThresholdConfig()
// 1. Global QPS check
d.detectGlobalQPSSpike(ctx, cfg)
// 1. Global QPS check (requires Redis)
if d.rdb != nil && d.statsService != nil {
d.detectGlobalQPSSpike(ctx, cfg)
}
// 2. Per-master RPM/TPM (1-minute window)
// 2. Per-master RPM/TPM (1-minute window) - uses logDB, works without Redis
d.detectMasterMinuteSpikes(ctx, cfg)
// 3. Per-master RPD/TPD (24-hour window)
// 3. Per-master RPD/TPD (24-hour window) - uses logDB, works without Redis
d.detectMasterDaySpikes(ctx, cfg)
}