Bugfix Problem Metrics
All checks were successful
release-tag / release-image (push) Successful in 5m59s

This commit is contained in:
2026-04-29 15:02:27 +02:00
parent 5e45b8cae8
commit d93151746c

94
main.go
View File

@@ -1688,6 +1688,7 @@ func main() {
s.templates = tmpl s.templates = tmpl
go s.runSOCLoop() go s.runSOCLoop()
go s.runBaselineLoop()
go s.runDetectionLoop() go s.runDetectionLoop()
mux := http.NewServeMux() mux := http.NewServeMux()
@@ -1756,6 +1757,53 @@ func (s *server) runSOCLoop() {
} }
} }
func (s *server) runBaselineLoop() {
ticker := time.NewTicker(s.cfg.DetectionInterval)
defer ticker.Stop()
s.runBaselineOnce()
for range ticker.C {
s.runBaselineOnce()
}
}
func (s *server) runBaselineOnce() {
if !s.cfg.BaselineEnabled {
return
}
rules := []struct {
name string
timeout time.Duration
fn func(context.Context) error
}{
{"baseline_anomaly", 120 * time.Second, s.detector.runBaselineAnomalyRule},
{"baseline_update", 120 * time.Second, s.detector.runBaselineUpdate},
}
for _, rule := range rules {
start := time.Now()
ctx, cancel := context.WithTimeout(context.Background(), rule.timeout)
err := rule.fn(ctx)
cancel()
dur := time.Since(start)
if err != nil {
s.logger.Printf("baseline rule %s error after %s: %v", rule.name, dur, err)
s.detector.ruleErrorsTotal.WithLabelValues(rule.name).Inc()
continue
}
s.logger.Printf("baseline rule %s completed in %s", rule.name, dur)
s.detector.ruleLastRunGauge.WithLabelValues(rule.name).Set(float64(time.Now().Unix()))
s.detector.ruleRuntimeHist.WithLabelValues(rule.name).Observe(dur.Seconds())
}
}
func (s *server) runSOCOnce() { func (s *server) runSOCOnce() {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel() defer cancel()
@@ -3941,17 +3989,18 @@ func (d *detector) runBaselineUpdate(ctx context.Context) error {
windowEnd := time.Now().UTC() windowEnd := time.Now().UTC()
windowStart := windowEnd.Add(-d.cfg.BaselineWindow) windowStart := windowEnd.Add(-d.cfg.BaselineWindow)
hour := windowEnd.Hour()
dayOfWeek := int(windowEnd.Weekday()+6) % 7 // Go: Sonntag=0, MySQL WEEKDAY: Montag=0
rows, err := d.db.QueryContext(ctx, ` rows, err := d.db.QueryContext(ctx, `
SELECT SELECT
hostname, hostname,
channel_name, channel_name,
event_id, event_id,
HOUR(ts) AS hour_of_day,
WEEKDAY(ts) AS day_of_week,
COUNT(*) AS cnt COUNT(*) AS cnt
FROM event_logs FROM event_logs
WHERE ts >= ? AND ts < ? WHERE ts >= ? AND ts < ?
GROUP BY hostname, channel_name, event_id, HOUR(ts), WEEKDAY(ts) GROUP BY hostname, channel_name, event_id
`, windowStart, windowEnd) `, windowStart, windowEnd)
if err != nil { if err != nil {
return err return err
@@ -3964,13 +4013,14 @@ GROUP BY hostname, channel_name, event_id, HOUR(ts), WEEKDAY(ts)
&b.Hostname, &b.Hostname,
&b.Channel, &b.Channel,
&b.EventID, &b.EventID,
&b.Hour,
&b.DayOfWeek,
&b.Count, &b.Count,
); err != nil { ); err != nil {
return err return err
} }
b.Hour = hour
b.DayOfWeek = dayOfWeek
excluded, err := d.isBaselineExcluded(ctx, b.Hostname, b.Channel, b.EventID) excluded, err := d.isBaselineExcluded(ctx, b.Hostname, b.Channel, b.EventID)
if err != nil { if err != nil {
return err return err
@@ -3995,6 +4045,12 @@ GROUP BY hostname, channel_name, event_id, HOUR(ts), WEEKDAY(ts)
return rows.Err() return rows.Err()
} }
func mysqlWeekday(t time.Time) int {
// MySQL WEEKDAY(): Monday=0 ... Sunday=6
// Go Weekday(): Sunday=0 ... Saturday=6
return (int(t.UTC().Weekday()) + 6) % 7
}
func (d *detector) hasConfirmedIncidentInWindow(ctx context.Context, hostname, channel string, eventID uint32, windowStart, windowEnd time.Time) (bool, error) { func (d *detector) hasConfirmedIncidentInWindow(ctx context.Context, hostname, channel string, eventID uint32, windowStart, windowEnd time.Time) (bool, error) {
var count int var count int
@@ -4129,35 +4185,34 @@ func (d *detector) runBaselineAnomalyRule(ctx context.Context) error {
windowEnd := time.Now().UTC() windowEnd := time.Now().UTC()
windowStart := windowEnd.Add(-d.cfg.BaselineWindow) windowStart := windowEnd.Add(-d.cfg.BaselineWindow)
hour := windowEnd.Hour()
dayOfWeek := mysqlWeekday(windowEnd)
rows, err := d.db.QueryContext(ctx, ` rows, err := d.db.QueryContext(ctx, `
SELECT SELECT
e.hostname, e.hostname,
e.channel_name, e.channel_name,
e.event_id, e.event_id,
HOUR(e.ts) AS hour_of_day,
WEEKDAY(e.ts) AS day_of_week,
COUNT(*) AS cnt, COUNT(*) AS cnt,
b.avg_count, COALESCE(b.avg_count, 0),
b.stddev_count, COALESCE(b.stddev_count, 0),
b.sample_count COALESCE(b.sample_count, 0)
FROM event_logs e FROM event_logs e
JOIN baseline_event_stats b LEFT JOIN baseline_event_stats b
ON b.hostname = e.hostname ON b.hostname = e.hostname
AND b.channel_name = e.channel_name AND b.channel_name = e.channel_name
AND b.event_id = e.event_id AND b.event_id = e.event_id
AND b.hour_of_day = HOUR(e.ts) AND b.hour_of_day = ?
AND b.day_of_week = WEEKDAY(e.ts) AND b.day_of_week = ?
WHERE e.ts >= ? AND e.ts < ? WHERE e.ts >= ? AND e.ts < ?
GROUP BY GROUP BY
e.hostname, e.hostname,
e.channel_name, e.channel_name,
e.event_id, e.event_id,
HOUR(e.ts),
WEEKDAY(e.ts),
b.avg_count, b.avg_count,
b.stddev_count, b.stddev_count,
b.sample_count b.sample_count
`, windowStart, windowEnd) `, hour, dayOfWeek, windowStart, windowEnd)
if err != nil { if err != nil {
return err return err
} }
@@ -4167,8 +4222,6 @@ GROUP BY
var host string var host string
var channel string var channel string
var eventID uint32 var eventID uint32
var hour int
var dayOfWeek int
var count int var count int
var avg float64 var avg float64
var stddev float64 var stddev float64
@@ -4178,8 +4231,6 @@ GROUP BY
&host, &host,
&channel, &channel,
&eventID, &eventID,
&hour,
&dayOfWeek,
&count, &count,
&avg, &avg,
&stddev, &stddev,
@@ -4769,9 +4820,6 @@ func (s *server) runDetectionsOnce() {
{"new_source_ip_for_user", s.detector.runNewSourceIPForUserRule}, {"new_source_ip_for_user", s.detector.runNewSourceIPForUserRule},
{"dynamic_rules", s.detector.runDynamicRules}, {"dynamic_rules", s.detector.runDynamicRules},
{"baseline_anomaly", s.detector.runBaselineAnomalyRule},
{"baseline_update", s.detector.runBaselineUpdate},
{"ueba_admin_new_host", s.detector.runAdminNewHostRule}, {"ueba_admin_new_host", s.detector.runAdminNewHostRule},
{"ueba_offhours_login", s.detector.runOffHoursLoginRule}, {"ueba_offhours_login", s.detector.runOffHoursLoginRule},
{"ueba_first_privileged_use", s.detector.runFirstTimePrivilegedRule}, {"ueba_first_privileged_use", s.detector.runFirstTimePrivilegedRule},