Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(monitors): added missing monitor fields to client lib #355

Merged
merged 2 commits into from
Feb 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 26 additions & 7 deletions axiom/monitors.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,17 @@ type MonitorType uint8

// All available [MonitorTypes]s.
const (
MonitorTypeThreshold MonitorType = iota // Threshold
MonitorTypeMatchEvent // MatchEvent
MonitorTypeThreshold MonitorType = iota // Threshold
MonitorTypeMatchEvent // MatchEvent
MonitorTypeAnonalyDetection // AnomalyDetection
)

func typeFromString(s string) (c MonitorType) {
switch s {
case MonitorTypeMatchEvent.String():
return MonitorTypeMatchEvent
case MonitorTypeAnonalyDetection.String():
return MonitorTypeAnonalyDetection
default:
return MonitorTypeThreshold
}
Expand Down Expand Up @@ -135,16 +138,30 @@ type Monitor struct {
// Resolvable determines whether the events triggered by the monitor are resolvable. This has no effect on threshold monitors.
Resolvable bool `json:"resolvable"`
// NotifierIDs attached to the monitor.
NotifierIDs []string `json:"NotifierIDs"`
NotifierIDs []string `json:"notifierIDs"`

// Interval is the interval in minutes in which the monitor will run.
Interval time.Duration `json:"IntervalMinutes"`
// Range the monitor goes back in time and looks at the data it acts on.
Range time.Duration `json:"RangeMinutes"`
// Interval is the interval in minutes in which the monitor will run. The lowest resolution is 1 minute.
Interval time.Duration `json:"intervalMinutes"`
// Range the monitor goes back in time and looks at the data it acts on. The lowest resolution is 1 minute.
Range time.Duration `json:"rangeMinutes"`
// Disabled sets whether the monitor is disabled or not.
Disabled bool `json:"disabled"`
// DisabledUntil is the time that the monitor will be disabled until.
DisabledUntil time.Time `json:"disabledUntil"`
// SecondDelay is the delay in seconds after the end time that the monitor runs. The lowest resolution is 1 second.
SecondDelay time.Duration `json:"secondDelay,omitempty"`
// NotifyEveryRun indicates whether to notify on every trigger.
NotifyEveryRun bool `json:"notifyEveryRun,omitempty"`
// SkipResolved indicates whether to skip resolved alerts.
SkipResolved bool `json:"skipResolved,omitempty"`
// Tolerance is the acceptable tolerance for an anomaly detection monitor.
Tolerance float64 `json:"tolerance,omitempty"`
// TriggerFromNRuns indicates the number of runs to consider when determining whether the current run should notify.
TriggerFromNRuns int64 `json:"triggerFromNRuns,omitempty"`
// TriggerAfterNPositiveResults indicates the number of positive results required to trigger a notification (can be from a larger set of TriggerFromNRuns)
TriggerAfterNPositiveResults int64 `json:"triggerAfterNPositiveResults,omitempty"`
// CompareDays indicates the number of days to compare for anomaly detection only.
CompareDays int64 `json:"compareDays,omitempty"`
}

// MarshalJSON implements [json.Marshaler]. It is in place to marshal the
Expand All @@ -156,6 +173,7 @@ func (m Monitor) MarshalJSON() ([]byte, error) {
// Set to the value in minutes.
m.Range = time.Duration(m.Range.Minutes())
m.Interval = time.Duration(m.Interval.Minutes())
m.SecondDelay = time.Duration(m.SecondDelay.Seconds())

return json.Marshal(localMonitor(m))
}
Expand All @@ -179,6 +197,7 @@ func (m *Monitor) UnmarshalJSON(b []byte) error {
// value in seconds.
m.Range *= time.Minute
m.Interval *= time.Minute
m.SecondDelay *= time.Second

return nil
}
Expand Down
43 changes: 35 additions & 8 deletions axiom/monitors_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,24 @@ func (s *MonitorsTestSuite) SetupTest() {
var err error
s.monitor, err = s.client.Monitors.Create(s.ctx, axiom.MonitorCreateRequest{
Monitor: axiom.Monitor{
AlertOnNoData: false,
APLQuery: fmt.Sprintf("['%s'] | summarize count() by bin_auto(_time)", s.datasetID),
Description: "A test monitor",
Interval: time.Minute,
Name: "Test Monitor",
Operator: axiom.BelowOrEqual,
Range: time.Minute * 5,
Threshold: 1,
AlertOnNoData: false,
APLQuery: fmt.Sprintf("['%s'] | summarize count() by bin_auto(_time)", s.datasetID),
Description: "A test monitor",
Interval: time.Minute,
Name: "Test Monitor",
Operator: axiom.BelowOrEqual,
Range: time.Minute * 5,
Threshold: 1,
SecondDelay: 10 * time.Second,
NotifyEveryRun: true,
SkipResolved: false,
TriggerFromNRuns: 3,
TriggerAfterNPositiveResults: 2,
},
})
s.Require().NoError(err)
s.Require().NotNil(s.monitor)
s.Equal(10*time.Second, s.monitor.SecondDelay)
}

func (s *MonitorsTestSuite) TearDownTest() {
Expand Down Expand Up @@ -170,3 +176,24 @@ func (s *MonitorsTestSuite) TestCreateMatchMonitor() {
s.Require().NotNil(monitor)
s.False(monitor.Disabled, "monitor should be enabled")
}

func (s *MonitorsTestSuite) TestCreateAnomalyDetectionMonitor() {
// Create the monitor
monitor, err := s.client.Monitors.Create(s.ctx, axiom.MonitorCreateRequest{
Monitor: axiom.Monitor{
AlertOnNoData: false,
APLQuery: fmt.Sprintf("['%s'] | summarize count() by bin(_time, 5m)", s.datasetID),
Description: "A very good test monitor",
Interval: time.Minute,
Name: "Test Monitor",
Operator: axiom.Below,
Range: time.Minute * 10,
Tolerance: 5,
CompareDays: 7,
Type: axiom.MonitorTypeAnonalyDetection,
},
})
s.Require().NoError(err)
s.Require().NotNil(monitor)
s.Equal(axiom.MonitorTypeAnonalyDetection.String(), monitor.Type.String())
}
5 changes: 3 additions & 2 deletions axiom/monitors_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

70 changes: 44 additions & 26 deletions axiom/monitors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ func TestMonitorsService_List(t *testing.T) {
"description": "test",
"disabledUntil": "2024-03-12T18:43:37Z",
"id": "test",
"IntervalMinutes": 0,
"intervalMinutes": 0,
"name": "test",
"NotifierIDs": null,
"notifierIDs": null,
"operator": "Above",
"RangeMinutes": 1,
"rangeMinutes": 1,
"threshold": 1
}]`)
assert.NoError(t, err)
Expand Down Expand Up @@ -78,11 +78,11 @@ func TestMonitorsService_Get(t *testing.T) {
"aplQuery": "['dataset'] | summarize count() by bin_auto(_time)",
"description": "test",
"id": "testID",
"IntervalMinutes": 0,
"intervalMinutes": 0,
"name": "test",
"NotifierIDs": null,
"notifierIDs": null,
"operator": "Above",
"RangeMinutes": 1,
"rangeMinutes": 1,
"threshold": 1,
"type": "Threshold"
}`)
Expand Down Expand Up @@ -120,11 +120,11 @@ func TestMonitorsService_Create(t *testing.T) {
"aplQuery": "['dataset'] | summarize count() by bin_auto(_time)",
"description": "test",
"id": "testID",
"IntervalMinutes": 0,
"intervalMinutes": 0,
"name": "test",
"NotifierIDs": null,
"notifierIDs": null,
"operator": "Above",
"RangeMinutes": 1,
"rangeMinutes": 1,
"threshold": 1
}`)
assert.NoError(t, err)
Expand All @@ -151,17 +151,25 @@ func TestMonitorsService_Create(t *testing.T) {

func TestMonitorsService_Update(t *testing.T) {
exp := &Monitor{
AlertOnNoData: false,
APLQuery: "['dataset'] | summarize count() by bin_auto(_time)",
Description: "test",
DisabledUntil: parseTimeOrPanic("2024-05-12T18:43:37Z"),
ID: "testID",
Interval: 0,
Name: "test",
NotifierIDs: nil,
Operator: Above,
Range: time.Minute,
Threshold: 1,
AlertOnNoData: false,
APLQuery: "['dataset'] | summarize count() by bin_auto(_time)",
Description: "test",
DisabledUntil: parseTimeOrPanic("2024-05-12T18:43:37Z"),
ID: "testID",
Interval: 0,
Name: "newTest",
NotifierIDs: nil,
Operator: Above,
Range: time.Minute,
Threshold: 1,
SecondDelay: 10 * time.Second,
NotifyEveryRun: true,
SkipResolved: false,
TriggerFromNRuns: 5,
TriggerAfterNPositiveResults: 3,
Type: MonitorTypeThreshold,
Tolerance: 4,
CompareDays: 8,
}
hf := func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodPut, r.Method)
Expand All @@ -174,12 +182,20 @@ func TestMonitorsService_Update(t *testing.T) {
"description": "test",
"disabledUntil": "2024-05-12T18:43:37Z",
"id": "testID",
"IntervalMinutes": 0,
"name": "test",
"NotifierIDs": null,
"intervalMinutes": 0,
"name": "newTest",
"notifierIDs": null,
"operator": "Above",
"RangeMinutes": 1,
"threshold": 1
"rangeMinutes": 1,
"threshold": 1,
"secondDelay": 10,
"notifyEveryRun": true,
"skipResolved": false,
"triggerFromNRuns": 5,
"triggerAfterNPositiveResults": 3,
"type": "Threshold",
"tolerance": 4,
"compareDays": 8
}`)
assert.NoError(t, err)
}
Expand All @@ -192,15 +208,17 @@ func TestMonitorsService_Update(t *testing.T) {
DisabledUntil: parseTimeOrPanic("2024-05-12T18:43:37Z"),
ID: "testID",
Interval: 0,
Name: "test",
Name: "newTest",
NotifierIDs: nil,
Operator: Above,
Range: time.Minute,
Threshold: 1,
SecondDelay: 10 * time.Second,
}})
require.NoError(t, err)

assert.Equal(t, exp, res)
assert.Equal(t, 10*time.Second, res.SecondDelay)
}

func TestMonitorsService_Delete(t *testing.T) {
Expand Down
Loading