Skip to content

Commit d3a61f9

Browse files
authored
feat: Add additional alert threshold types (#2122)
## Summary This PR adds new types of alert thresholds: >, <=, =, and !=. ### Screenshots or video https://github.com/user-attachments/assets/159bffc4-87e5-41af-b59b-51d4bc88d6ed ### How to test locally or on Vercel This must be tested locally, since alerts are not supported in the preview environment. To see the notification content, run an echo server locally and create a webhook that targets it (http://localhost:3000): ```bash npx http-echo-server ``` ### References - Linear Issue: Closes HDX-3988 - Related PRs:
1 parent 71e1441 commit d3a61f9

22 files changed

Lines changed: 1972 additions & 91 deletions

File tree

.changeset/polite-grapes-cross.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"@hyperdx/common-utils": patch
3+
"@hyperdx/api": patch
4+
"@hyperdx/app": patch
5+
"@hyperdx/cli": patch
6+
---
7+
8+
feat: Add additional alert threshold types

packages/api/openapi.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,11 @@
7070
"type": "string",
7171
"enum": [
7272
"above",
73-
"below"
73+
"below",
74+
"above_exclusive",
75+
"below_or_equal",
76+
"equal",
77+
"not_equal"
7478
],
7579
"description": "Threshold comparison direction."
7680
},

packages/api/src/controllers/alerts.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
validateRawSqlForAlert,
44
} from '@hyperdx/common-utils/dist/core/utils';
55
import { isRawSqlSavedChartConfig } from '@hyperdx/common-utils/dist/guards';
6+
import { AlertThresholdType } from '@hyperdx/common-utils/dist/types';
67
import { sign, verify } from 'jsonwebtoken';
78
import { groupBy } from 'lodash';
89
import ms from 'ms';
@@ -13,7 +14,6 @@ import Alert, {
1314
AlertChannel,
1415
AlertInterval,
1516
AlertSource,
16-
AlertThresholdType,
1717
IAlert,
1818
} from '@/models/alert';
1919
import Dashboard, { IDashboard } from '@/models/dashboard';

packages/api/src/fixtures.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { createNativeClient } from '@hyperdx/common-utils/dist/clickhouse/node';
22
import {
3+
AlertThresholdType,
34
BuilderSavedChartConfig,
45
DisplayType,
56
RawSqlSavedChartConfig,
@@ -15,7 +16,7 @@ import { AlertInput } from '@/controllers/alerts';
1516
import { getTeam } from '@/controllers/team';
1617
import { findUserByEmail } from '@/controllers/user';
1718
import { mongooseConnection } from '@/models';
18-
import { AlertInterval, AlertSource, AlertThresholdType } from '@/models/alert';
19+
import { AlertInterval, AlertSource } from '@/models/alert';
1920
import Server from '@/server';
2021
import logger from '@/utils/logger';
2122
import { MetricModel } from '@/utils/logParser';

packages/api/src/models/alert.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
import { ALERT_INTERVAL_TO_MINUTES } from '@hyperdx/common-utils/dist/types';
1+
import {
2+
ALERT_INTERVAL_TO_MINUTES,
3+
AlertThresholdType,
4+
} from '@hyperdx/common-utils/dist/types';
5+
export { AlertThresholdType } from '@hyperdx/common-utils/dist/types';
26
import mongoose, { Schema } from 'mongoose';
37

48
import type { ObjectId } from '.';
59
import Team from './team';
610

7-
export enum AlertThresholdType {
8-
ABOVE = 'above',
9-
BELOW = 'below',
10-
}
11-
1211
export enum AlertState {
1312
ALERT = 'ALERT',
1413
DISABLED = 'DISABLED',

packages/api/src/routers/api/__tests__/alerts.test.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import { DisplayType } from '@hyperdx/common-utils/dist/types';
1+
import {
2+
AlertThresholdType,
3+
DisplayType,
4+
} from '@hyperdx/common-utils/dist/types';
25

36
import {
47
getLoggedInAgent,
@@ -11,11 +14,7 @@ import {
1114
randomMongoId,
1215
RAW_SQL_ALERT_TEMPLATE,
1316
} from '@/fixtures';
14-
import Alert, {
15-
AlertSource,
16-
AlertState,
17-
AlertThresholdType,
18-
} from '@/models/alert';
17+
import Alert, { AlertSource, AlertState } from '@/models/alert';
1918
import AlertHistory from '@/models/alertHistory';
2019
import Webhook, { WebhookDocument, WebhookService } from '@/models/webhook';
2120

packages/api/src/routers/external-api/v2/alerts.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import { alertSchema, objectIdSchema } from '@/utils/zod';
3434
* description: Evaluation interval.
3535
* AlertThresholdType:
3636
* type: string
37-
* enum: [above, below]
37+
* enum: [above, below, above_exclusive, below_or_equal, equal, not_equal]
3838
* description: Threshold comparison direction.
3939
* AlertSource:
4040
* type: string
Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
2+
3+
exports[`buildAlertMessageTemplateTitle saved search alerts ALERT state above threshold=5 alertValue=10 1`] = `"🚨 Alert for "My Search" - 10 lines found"`;
4+
5+
exports[`buildAlertMessageTemplateTitle saved search alerts ALERT state above_exclusive threshold=5 alertValue=10 1`] = `"🚨 Alert for "My Search" - 10 lines found"`;
6+
7+
exports[`buildAlertMessageTemplateTitle saved search alerts ALERT state below threshold=5 alertValue=2 1`] = `"🚨 Alert for "My Search" - 2 lines found"`;
8+
9+
exports[`buildAlertMessageTemplateTitle saved search alerts ALERT state below_or_equal threshold=5 alertValue=3 1`] = `"🚨 Alert for "My Search" - 3 lines found"`;
10+
11+
exports[`buildAlertMessageTemplateTitle saved search alerts ALERT state equal threshold=5 alertValue=5 1`] = `"🚨 Alert for "My Search" - 5 lines found"`;
12+
13+
exports[`buildAlertMessageTemplateTitle saved search alerts ALERT state not_equal threshold=5 alertValue=10 1`] = `"🚨 Alert for "My Search" - 10 lines found"`;
14+
15+
exports[`buildAlertMessageTemplateTitle saved search alerts OK state (resolved) above threshold=5 okValue=3 1`] = `"✅ Alert for "My Search" - 3 lines found"`;
16+
17+
exports[`buildAlertMessageTemplateTitle saved search alerts OK state (resolved) above_exclusive threshold=5 okValue=3 1`] = `"✅ Alert for "My Search" - 3 lines found"`;
18+
19+
exports[`buildAlertMessageTemplateTitle saved search alerts OK state (resolved) below threshold=5 okValue=10 1`] = `"✅ Alert for "My Search" - 10 lines found"`;
20+
21+
exports[`buildAlertMessageTemplateTitle saved search alerts OK state (resolved) below_or_equal threshold=5 okValue=10 1`] = `"✅ Alert for "My Search" - 10 lines found"`;
22+
23+
exports[`buildAlertMessageTemplateTitle saved search alerts OK state (resolved) equal threshold=5 okValue=10 1`] = `"✅ Alert for "My Search" - 10 lines found"`;
24+
25+
exports[`buildAlertMessageTemplateTitle saved search alerts OK state (resolved) not_equal threshold=5 okValue=5 1`] = `"✅ Alert for "My Search" - 5 lines found"`;
26+
27+
exports[`buildAlertMessageTemplateTitle tile alerts ALERT state above threshold=5 alertValue=10 1`] = `"🚨 Alert for "Test Chart" in "My Dashboard" - 10 meets or exceeds 5"`;
28+
29+
exports[`buildAlertMessageTemplateTitle tile alerts ALERT state above_exclusive threshold=5 alertValue=10 1`] = `"🚨 Alert for "Test Chart" in "My Dashboard" - 10 exceeds 5"`;
30+
31+
exports[`buildAlertMessageTemplateTitle tile alerts ALERT state below threshold=5 alertValue=2 1`] = `"🚨 Alert for "Test Chart" in "My Dashboard" - 2 falls below 5"`;
32+
33+
exports[`buildAlertMessageTemplateTitle tile alerts ALERT state below_or_equal threshold=5 alertValue=3 1`] = `"🚨 Alert for "Test Chart" in "My Dashboard" - 3 falls to or below 5"`;
34+
35+
exports[`buildAlertMessageTemplateTitle tile alerts ALERT state decimal threshold 1`] = `"🚨 Alert for "Test Chart" in "My Dashboard" - 10.1 meets or exceeds 1.5"`;
36+
37+
exports[`buildAlertMessageTemplateTitle tile alerts ALERT state equal threshold=5 alertValue=5 1`] = `"🚨 Alert for "Test Chart" in "My Dashboard" - 5 equals 5"`;
38+
39+
exports[`buildAlertMessageTemplateTitle tile alerts ALERT state integer threshold rounds value 1`] = `"🚨 Alert for "Test Chart" in "My Dashboard" - 11 meets or exceeds 5"`;
40+
41+
exports[`buildAlertMessageTemplateTitle tile alerts ALERT state not_equal threshold=5 alertValue=10 1`] = `"🚨 Alert for "Test Chart" in "My Dashboard" - 10 does not equal 5"`;
42+
43+
exports[`buildAlertMessageTemplateTitle tile alerts OK state (resolved) above threshold=5 okValue=3 1`] = `"✅ Alert for "Test Chart" in "My Dashboard" - 3 falls below 5"`;
44+
45+
exports[`buildAlertMessageTemplateTitle tile alerts OK state (resolved) above_exclusive threshold=5 okValue=3 1`] = `"✅ Alert for "Test Chart" in "My Dashboard" - 3 falls to or below 5"`;
46+
47+
exports[`buildAlertMessageTemplateTitle tile alerts OK state (resolved) below threshold=5 okValue=10 1`] = `"✅ Alert for "Test Chart" in "My Dashboard" - 10 meets or exceeds 5"`;
48+
49+
exports[`buildAlertMessageTemplateTitle tile alerts OK state (resolved) below_or_equal threshold=5 okValue=10 1`] = `"✅ Alert for "Test Chart" in "My Dashboard" - 10 exceeds 5"`;
50+
51+
exports[`buildAlertMessageTemplateTitle tile alerts OK state (resolved) equal threshold=5 okValue=10 1`] = `"✅ Alert for "Test Chart" in "My Dashboard" - 10 does not equal 5"`;
52+
53+
exports[`buildAlertMessageTemplateTitle tile alerts OK state (resolved) not_equal threshold=5 okValue=5 1`] = `"✅ Alert for "Test Chart" in "My Dashboard" - 5 equals 5"`;
54+
55+
exports[`renderAlertTemplate saved search alerts ALERT state above threshold=5 alertValue=10 1`] = `
56+
"
57+
10 lines found, which meets or exceeds the threshold of 5 lines
58+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
59+
60+
\`\`\`
61+
"2023-03-17 22:14:01","error","Failed to connect to database"
62+
"2023-03-17 22:13:45","error","Connection timeout after 30s"
63+
"2023-03-17 22:12:30","error","Retry limit exceeded"
64+
\`\`\`"
65+
`;
66+
67+
exports[`renderAlertTemplate saved search alerts ALERT state above_exclusive threshold=5 alertValue=10 1`] = `
68+
"
69+
10 lines found, which exceeds the threshold of 5 lines
70+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
71+
72+
\`\`\`
73+
"2023-03-17 22:14:01","error","Failed to connect to database"
74+
"2023-03-17 22:13:45","error","Connection timeout after 30s"
75+
"2023-03-17 22:12:30","error","Retry limit exceeded"
76+
\`\`\`"
77+
`;
78+
79+
exports[`renderAlertTemplate saved search alerts ALERT state below threshold=5 alertValue=2 1`] = `
80+
"
81+
2 lines found, which falls below the threshold of 5 lines
82+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
83+
84+
\`\`\`
85+
"2023-03-17 22:14:01","error","Failed to connect to database"
86+
"2023-03-17 22:13:45","error","Connection timeout after 30s"
87+
"2023-03-17 22:12:30","error","Retry limit exceeded"
88+
\`\`\`"
89+
`;
90+
91+
exports[`renderAlertTemplate saved search alerts ALERT state below_or_equal threshold=5 alertValue=3 1`] = `
92+
"
93+
3 lines found, which falls to or below the threshold of 5 lines
94+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
95+
96+
\`\`\`
97+
"2023-03-17 22:14:01","error","Failed to connect to database"
98+
"2023-03-17 22:13:45","error","Connection timeout after 30s"
99+
"2023-03-17 22:12:30","error","Retry limit exceeded"
100+
\`\`\`"
101+
`;
102+
103+
exports[`renderAlertTemplate saved search alerts ALERT state equal threshold=5 alertValue=5 1`] = `
104+
"
105+
5 lines found, which equals the threshold of 5 lines
106+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
107+
108+
\`\`\`
109+
"2023-03-17 22:14:01","error","Failed to connect to database"
110+
"2023-03-17 22:13:45","error","Connection timeout after 30s"
111+
"2023-03-17 22:12:30","error","Retry limit exceeded"
112+
\`\`\`"
113+
`;
114+
115+
exports[`renderAlertTemplate saved search alerts ALERT state not_equal threshold=5 alertValue=10 1`] = `
116+
"
117+
10 lines found, which does not equal the threshold of 5 lines
118+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
119+
120+
\`\`\`
121+
"2023-03-17 22:14:01","error","Failed to connect to database"
122+
"2023-03-17 22:13:45","error","Connection timeout after 30s"
123+
"2023-03-17 22:12:30","error","Retry limit exceeded"
124+
\`\`\`"
125+
`;
126+
127+
exports[`renderAlertTemplate saved search alerts ALERT state with group 1`] = `
128+
"Group: "http"
129+
10 lines found, which meets or exceeds the threshold of 5 lines
130+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
131+
132+
\`\`\`
133+
"2023-03-17 22:14:01","error","Failed to connect to database"
134+
"2023-03-17 22:13:45","error","Connection timeout after 30s"
135+
"2023-03-17 22:12:30","error","Retry limit exceeded"
136+
\`\`\`"
137+
`;
138+
139+
exports[`renderAlertTemplate saved search alerts OK state (resolved) above threshold=5 okValue=3 1`] = `
140+
"The alert has been resolved.
141+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
142+
"
143+
`;
144+
145+
exports[`renderAlertTemplate saved search alerts OK state (resolved) above_exclusive threshold=5 okValue=3 1`] = `
146+
"The alert has been resolved.
147+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
148+
"
149+
`;
150+
151+
exports[`renderAlertTemplate saved search alerts OK state (resolved) below threshold=5 okValue=10 1`] = `
152+
"The alert has been resolved.
153+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
154+
"
155+
`;
156+
157+
exports[`renderAlertTemplate saved search alerts OK state (resolved) below_or_equal threshold=5 okValue=10 1`] = `
158+
"The alert has been resolved.
159+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
160+
"
161+
`;
162+
163+
exports[`renderAlertTemplate saved search alerts OK state (resolved) equal threshold=5 okValue=10 1`] = `
164+
"The alert has been resolved.
165+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
166+
"
167+
`;
168+
169+
exports[`renderAlertTemplate saved search alerts OK state (resolved) not_equal threshold=5 okValue=5 1`] = `
170+
"The alert has been resolved.
171+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
172+
"
173+
`;
174+
175+
exports[`renderAlertTemplate saved search alerts OK state (resolved) with group 1`] = `
176+
"Group: "http" - The alert has been resolved.
177+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
178+
"
179+
`;
180+
181+
exports[`renderAlertTemplate tile alerts ALERT state above threshold=5 alertValue=10 1`] = `
182+
"
183+
10 meets or exceeds 5
184+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
185+
"
186+
`;
187+
188+
exports[`renderAlertTemplate tile alerts ALERT state above_exclusive threshold=5 alertValue=10 1`] = `
189+
"
190+
10 exceeds 5
191+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
192+
"
193+
`;
194+
195+
exports[`renderAlertTemplate tile alerts ALERT state below threshold=5 alertValue=2 1`] = `
196+
"
197+
2 falls below 5
198+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
199+
"
200+
`;
201+
202+
exports[`renderAlertTemplate tile alerts ALERT state below_or_equal threshold=5 alertValue=3 1`] = `
203+
"
204+
3 falls to or below 5
205+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
206+
"
207+
`;
208+
209+
exports[`renderAlertTemplate tile alerts ALERT state decimal threshold 1`] = `
210+
"
211+
10.1 meets or exceeds 1.5
212+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
213+
"
214+
`;
215+
216+
exports[`renderAlertTemplate tile alerts ALERT state equal threshold=5 alertValue=5 1`] = `
217+
"
218+
5 equals 5
219+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
220+
"
221+
`;
222+
223+
exports[`renderAlertTemplate tile alerts ALERT state integer threshold rounds value 1`] = `
224+
"
225+
11 meets or exceeds 5
226+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
227+
"
228+
`;
229+
230+
exports[`renderAlertTemplate tile alerts ALERT state not_equal threshold=5 alertValue=10 1`] = `
231+
"
232+
10 does not equal 5
233+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
234+
"
235+
`;
236+
237+
exports[`renderAlertTemplate tile alerts ALERT state with group 1`] = `
238+
"Group: "us-east-1"
239+
10 meets or exceeds 5
240+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
241+
"
242+
`;
243+
244+
exports[`renderAlertTemplate tile alerts OK state (resolved) above threshold=5 okValue=3 1`] = `
245+
"The alert has been resolved.
246+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
247+
"
248+
`;
249+
250+
exports[`renderAlertTemplate tile alerts OK state (resolved) above_exclusive threshold=5 okValue=3 1`] = `
251+
"The alert has been resolved.
252+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
253+
"
254+
`;
255+
256+
exports[`renderAlertTemplate tile alerts OK state (resolved) below threshold=5 okValue=10 1`] = `
257+
"The alert has been resolved.
258+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
259+
"
260+
`;
261+
262+
exports[`renderAlertTemplate tile alerts OK state (resolved) below_or_equal threshold=5 okValue=10 1`] = `
263+
"The alert has been resolved.
264+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
265+
"
266+
`;
267+
268+
exports[`renderAlertTemplate tile alerts OK state (resolved) equal threshold=5 okValue=10 1`] = `
269+
"The alert has been resolved.
270+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
271+
"
272+
`;
273+
274+
exports[`renderAlertTemplate tile alerts OK state (resolved) not_equal threshold=5 okValue=5 1`] = `
275+
"The alert has been resolved.
276+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
277+
"
278+
`;
279+
280+
exports[`renderAlertTemplate tile alerts OK state (resolved) with group 1`] = `
281+
"Group: "us-east-1" - The alert has been resolved.
282+
Time Range (UTC): [Mar 17 10:10:00 PM - Mar 17 10:15:00 PM)
283+
"
284+
`;

0 commit comments

Comments
 (0)