fixes
This commit is contained in:
1 parent
f30adf05af
commit
8824af8699
29 files changed
+1201
-115
No files matched your search
@@ -15,6 +15,12 @@ type SpikeConfig struct {
|
||||
Multiple float64 // a pattern must be novel or >= Multiple * its own baseline mean
|
||||
MinExcess int // and excess errors must be >= MinExcess
|
||||
TopPatterns int
|
||||
// DataSince is when data collection began (earliest row of any kind). When
|
||||
// set, no alert fires until WarmupWindows windows of baseline exist,
|
||||
// otherwise the first window after data begins reports everything as NEW.
|
||||
// Zero disables the guard.
|
||||
DataSince time.Time
|
||||
WarmupWindows int
|
||||
}
|
||||
|
||||
func DefaultSpikeConfig() SpikeConfig {
|
||||
@@ -64,6 +70,15 @@ func DetectSpikes(events []Event, at time.Time, cfg SpikeConfig) []Spike {
|
||||
at = at.UTC()
|
||||
start := at.Add(-cfg.Window)
|
||||
baseStart := start.Add(-time.Duration(cfg.BaselineWindows) * cfg.Window)
|
||||
if !cfg.DataSince.IsZero() {
|
||||
warm := cfg.WarmupWindows
|
||||
if warm <= 0 {
|
||||
warm = min(cfg.BaselineWindows, 6)
|
||||
}
|
||||
if start.Sub(cfg.DataSince.UTC()) < time.Duration(warm)*cfg.Window {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
type agg struct {
|
||||
cur int
|
||||
|
||||
@@ -77,3 +77,24 @@ func TestSuppressorCooldownAndEscalation(t *testing.T) {
|
||||
t.Fatal("alert after cooldown should pass")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetectSpikesWarmupGuard(t *testing.T) {
|
||||
at := time.Date(2026, 9, 19, 12, 0, 0, 0, time.UTC)
|
||||
cfg := SpikeConfig{Window: 5 * time.Minute, BaselineWindows: 12, WarmupWindows: 6}
|
||||
var events []Event
|
||||
for i := 0; i < 20; i++ {
|
||||
events = append(events, Event{Timestamp: at.Add(-time.Minute).Add(time.Duration(i) * time.Second), Service: "api", IsError: true, PatternSignature: "new"})
|
||||
}
|
||||
cfg.DataSince = at.Add(-10 * time.Minute) // data began 10 min ago: cold
|
||||
if got := DetectSpikes(events, at, cfg); len(got) != 0 {
|
||||
t.Fatalf("alerted during warm-up: %+v", got)
|
||||
}
|
||||
cfg.DataSince = at.Add(-2 * time.Hour) // warm
|
||||
if got := DetectSpikes(events, at, cfg); len(got) != 1 {
|
||||
t.Fatalf("expected alert once warm, got %+v", got)
|
||||
}
|
||||
cfg.DataSince = time.Time{} // guard disabled
|
||||
if got := DetectSpikes(events, at, cfg); len(got) != 1 {
|
||||
t.Fatalf("guard should be off when DataSince is zero")
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user