Skip to content

Commit

Permalink
Merge pull request #1002 from SiaFoundation/chris/alerts-filter-severity
Browse files Browse the repository at this point in the history
Allow for filtering paginated alerts by severity
  • Loading branch information
ChrisSchinnerl authored Feb 27, 2024
2 parents fc72fa9 + 6db1e38 commit fc3625a
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 17 deletions.
55 changes: 39 additions & 16 deletions alerts/alerts.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,27 @@ type (
}

AlertsOpts struct {
Offset int
Limit int
Offset int
Limit int
Severity Severity
}

AlertsResponse struct {
Alerts []Alert `json:"alerts"`
HasMore bool `json:"hasMore"`
Total int `json:"total"`
Totals struct {
Info int `json:"info"`
Warning int `json:"warning"`
Error int `json:"error"`
Critical int `json:"critical"`
} `json:"totals"`
}
)

func (ar AlertsResponse) Total() int {
return ar.Totals.Info + ar.Totals.Warning + ar.Totals.Error + ar.Totals.Critical
}

// String implements the fmt.Stringer interface.
func (s Severity) String() string {
switch s {
Expand All @@ -93,15 +103,8 @@ func (s Severity) String() string {
}
}

// MarshalJSON implements the json.Marshaler interface.
func (s Severity) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`%q`, s.String())), nil
}

// UnmarshalJSON implements the json.Unmarshaler interface.
func (s *Severity) UnmarshalJSON(b []byte) error {
status := strings.Trim(string(b), `"`)
switch status {
func (s *Severity) LoadString(str string) error {
switch str {
case severityInfoStr:
*s = SeverityInfo
case severityWarningStr:
Expand All @@ -111,11 +114,21 @@ func (s *Severity) UnmarshalJSON(b []byte) error {
case severityCriticalStr:
*s = SeverityCritical
default:
return fmt.Errorf("unrecognized severity: %v", status)
return fmt.Errorf("unrecognized severity: %v", str)
}
return nil
}

// MarshalJSON implements the json.Marshaler interface.
func (s Severity) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`%q`, s.String())), nil
}

// UnmarshalJSON implements the json.Unmarshaler interface.
func (s *Severity) UnmarshalJSON(b []byte) error {
return s.LoadString(strings.Trim(string(b), `"`))
}

// RegisterAlert implements the Alerter interface.
func (m *Manager) RegisterAlert(ctx context.Context, alert Alert) error {
if alert.ID == (types.Hash256{}) {
Expand Down Expand Up @@ -176,9 +189,7 @@ func (m *Manager) Alerts(_ context.Context, opts AlertsOpts) (AlertsResponse, er
defer m.mu.Unlock()

offset, limit := opts.Offset, opts.Limit
resp := AlertsResponse{
Total: len(m.alerts),
}
resp := AlertsResponse{}

if offset >= len(m.alerts) {
return resp, nil
Expand All @@ -188,6 +199,18 @@ func (m *Manager) Alerts(_ context.Context, opts AlertsOpts) (AlertsResponse, er

alerts := make([]Alert, 0, len(m.alerts))
for _, a := range m.alerts {
if a.Severity == SeverityInfo {
resp.Totals.Info++
} else if a.Severity == SeverityWarning {
resp.Totals.Warning++
} else if a.Severity == SeverityError {
resp.Totals.Error++
} else if a.Severity == SeverityCritical {
resp.Totals.Critical++
}
if opts.Severity != 0 && a.Severity != opts.Severity {
continue // filter by severity
}
alerts = append(alerts, a)
}
sort.Slice(alerts, func(i, j int) bool {
Expand Down
9 changes: 8 additions & 1 deletion bus/bus.go
Original file line number Diff line number Diff line change
Expand Up @@ -1741,15 +1741,22 @@ func (b *bus) handleGETAlerts(jc jape.Context) {
return
}
offset, limit := 0, -1
var severity alerts.Severity
if jc.DecodeForm("offset", &offset) != nil {
return
} else if jc.DecodeForm("limit", &limit) != nil {
return
} else if offset < 0 {
jc.Error(errors.New("offset must be non-negative"), http.StatusBadRequest)
return
} else if jc.DecodeForm("severity", &severity) != nil {
return
}
ar, err := b.alertMgr.Alerts(jc.Request.Context(), alerts.AlertsOpts{Offset: offset, Limit: limit})
ar, err := b.alertMgr.Alerts(jc.Request.Context(), alerts.AlertsOpts{
Offset: offset,
Limit: limit,
Severity: severity,
})
if jc.Check("failed to fetch alerts", err) != nil {
return
}
Expand Down
3 changes: 3 additions & 0 deletions bus/client/alerts.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ func (c *Client) Alerts(ctx context.Context, opts alerts.AlertsOpts) (resp alert
if opts.Limit != 0 {
values.Set("limit", fmt.Sprint(opts.Limit))
}
if opts.Severity != 0 {
values.Set("severity", opts.Severity.String())
}
err = c.c.WithContext(ctx).GET("/alerts?"+values.Encode(), &resp)
return
}
Expand Down
38 changes: 38 additions & 0 deletions internal/testing/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1974,6 +1974,44 @@ func TestAlerts(t *testing.T) {
if len(foundAlerts) != 1 || foundAlerts[0].ID != alert2.ID {
t.Fatal("wrong alert")
}

// register more alerts
for severity := alerts.SeverityInfo; severity <= alerts.SeverityCritical; severity++ {
for j := 0; j < 3*int(severity); j++ {
tt.OK(b.RegisterAlert(context.Background(), alerts.Alert{
ID: frand.Entropy256(),
Severity: severity,
Message: "test",
Data: map[string]interface{}{
"origin": "test",
},
Timestamp: time.Now(),
}))
}
}
for severity := alerts.SeverityInfo; severity <= alerts.SeverityCritical; severity++ {
ar, err = b.Alerts(context.Background(), alerts.AlertsOpts{Severity: severity})
tt.OK(err)
if ar.Total() != 32 {
t.Fatal("expected 32 alerts", ar.Total())
} else if ar.Totals.Info != 3 {
t.Fatal("expected 3 info alerts", ar.Totals.Info)
} else if ar.Totals.Warning != 6 {
t.Fatal("expected 6 warning alerts", ar.Totals.Warning)
} else if ar.Totals.Error != 9 {
t.Fatal("expected 9 error alerts", ar.Totals.Error)
} else if ar.Totals.Critical != 14 {
t.Fatal("expected 14 critical alerts", ar.Totals.Critical)
} else if severity == alerts.SeverityInfo && len(ar.Alerts) != ar.Totals.Info {
t.Fatalf("expected %v info alerts, got %v", ar.Totals.Info, len(ar.Alerts))
} else if severity == alerts.SeverityWarning && len(ar.Alerts) != ar.Totals.Warning {
t.Fatalf("expected %v warning alerts, got %v", ar.Totals.Warning, len(ar.Alerts))
} else if severity == alerts.SeverityError && len(ar.Alerts) != ar.Totals.Error {
t.Fatalf("expected %v error alerts, got %v", ar.Totals.Error, len(ar.Alerts))
} else if severity == alerts.SeverityCritical && len(ar.Alerts) != ar.Totals.Critical {
t.Fatalf("expected %v critical alerts, got %v", ar.Totals.Critical, len(ar.Alerts))
}
}
}

func TestMultipartUploads(t *testing.T) {
Expand Down

0 comments on commit fc3625a

Please sign in to comment.