103 lines
4.3 KiB
Go
103 lines
4.3 KiB
Go
package query
|
|
|
|
import (
|
|
"context"
|
|
|
|
"git.ilapage.cn/ila/yovision/Bell/server/app/alert/model"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
type Service struct{ DB *pgxpool.Pool }
|
|
|
|
const base = `SELECT a.id::text,a.status,a.severity,a.summary,a.location,a.primary_rule_id::text,r.name,(SELECT count(*) FROM bell_alert_events ae WHERE ae.alert_id=a.id),a.acknowledged_by::text,ack_user.display_name,a.acknowledged_at::text,a.closed_by::text,close_user.display_name,a.closed_at::text,a.close_outcome,a.close_note,a.created_at::text,a.updated_at::text FROM bell_alerts a JOIN bell_rules r ON r.id=a.primary_rule_id LEFT JOIN bell_users ack_user ON ack_user.id=a.acknowledged_by LEFT JOIN bell_users close_user ON close_user.id=a.closed_by`
|
|
|
|
func scanAlert(row interface{ Scan(...any) error }) (model.Alert, error) {
|
|
var item model.Alert
|
|
err := row.Scan(&item.ID, &item.Status, &item.Severity, &item.Summary, &item.Location, &item.PrimaryRuleID, &item.RuleName, &item.EventCount, &item.AcknowledgedBy, &item.AcknowledgedByName, &item.AcknowledgedAt, &item.ClosedBy, &item.ClosedByName, &item.ClosedAt, &item.CloseOutcome, &item.CloseNote, &item.CreatedAt, &item.UpdatedAt)
|
|
return item, err
|
|
}
|
|
func (s Service) List(ctx context.Context, limit int, before string) ([]model.Alert, error) {
|
|
if limit < 1 || limit > 100 {
|
|
limit = 25
|
|
}
|
|
rows, err := s.DB.Query(ctx, base+` WHERE ($2='' OR (a.created_at,a.id)<((SELECT created_at FROM bell_alerts WHERE id=nullif($2,'')::uuid),nullif($2,'')::uuid)) ORDER BY a.created_at DESC,a.id DESC LIMIT $1`, limit, before)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
items := []model.Alert{}
|
|
for rows.Next() {
|
|
item, err := scanAlert(rows)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, item)
|
|
}
|
|
return items, rows.Err()
|
|
}
|
|
func (s Service) Get(ctx context.Context, id string) (model.Detail, error) {
|
|
item, err := scanAlert(s.DB.QueryRow(ctx, base+` WHERE a.id=$1`, id))
|
|
if err != nil {
|
|
return model.Detail{}, err
|
|
}
|
|
detail := model.Detail{Alert: item, Events: []model.LinkedEvent{}, Matches: []model.Match{}, Timeline: []model.TimelineEntry{}}
|
|
rows, err := s.DB.Query(ctx, `SELECT e.id::text,e.event_type,e.occurred_at::text,e.location,e.severity FROM bell_alert_events ae JOIN bell_events e ON e.id=ae.event_id WHERE ae.alert_id=$1 ORDER BY e.occurred_at,e.id`, id)
|
|
if err != nil {
|
|
return model.Detail{}, err
|
|
}
|
|
for rows.Next() {
|
|
var linked model.LinkedEvent
|
|
if err := rows.Scan(&linked.ID, &linked.EventType, &linked.OccurredAt, &linked.Location, &linked.Severity); err != nil {
|
|
rows.Close()
|
|
return model.Detail{}, err
|
|
}
|
|
detail.Events = append(detail.Events, linked)
|
|
}
|
|
rows.Close()
|
|
rows, err = s.DB.Query(ctx, `SELECT event_id::text,rule_id::text,rule_version,rule_snapshot,explanation,matched_at::text FROM bell_rule_matches WHERE alert_id=$1 ORDER BY matched_at,event_id`, id)
|
|
if err != nil {
|
|
return model.Detail{}, err
|
|
}
|
|
defer rows.Close()
|
|
for rows.Next() {
|
|
var match model.Match
|
|
if err := rows.Scan(&match.EventID, &match.RuleID, &match.RuleVersion, &match.RuleSnapshot, &match.Explanation, &match.MatchedAt); err != nil {
|
|
return model.Detail{}, err
|
|
}
|
|
detail.Matches = append(detail.Matches, match)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return model.Detail{}, err
|
|
}
|
|
rows.Close()
|
|
rows, err = s.DB.Query(ctx, `SELECT f.id,f.transition,f.actor_user_id::text,u.display_name,f.occurred_at::text,f.details FROM bell_alert_lifecycle_facts f JOIN bell_users u ON u.id=f.actor_user_id WHERE f.alert_id=$1 ORDER BY f.id`, id)
|
|
if err != nil {
|
|
return model.Detail{}, err
|
|
}
|
|
defer rows.Close()
|
|
for rows.Next() {
|
|
var entry model.TimelineEntry
|
|
if err := rows.Scan(&entry.ID, &entry.Transition, &entry.ActorUserID, &entry.ActorName, &entry.OccurredAt, &entry.Details); err != nil {
|
|
return model.Detail{}, err
|
|
}
|
|
detail.Timeline = append(detail.Timeline, entry)
|
|
}
|
|
return detail, rows.Err()
|
|
}
|
|
func (s Service) ForEvent(ctx context.Context, eventID string) ([]model.Alert, error) {
|
|
rows, err := s.DB.Query(ctx, base+` JOIN bell_alert_events link ON link.alert_id=a.id WHERE link.event_id=$1 ORDER BY a.created_at,a.id`, eventID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
items := []model.Alert{}
|
|
for rows.Next() {
|
|
item, err := scanAlert(rows)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, item)
|
|
}
|
|
return items, rows.Err()
|
|
}
|