mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Metric threshold] Stop reporting no data alert for missing groups that are untracked (#179374)
Fixes #161621 ## Summary This PR removes untracked alerts from the missing group array in the rule state and as a result, those no data alerts will not be reported again. ### 🧪 How to test - Create some metric threshold alerts for different groups - Stop sending data for `group-1` (You should see a no data alert for it) - Untrack no data alert related to `group-1`, after the next rule execution, you should not see any no data alert for this group. - Again send data for `group-1` to meet the threshold, you should see an alert for it as before.
This commit is contained in:
parent
fc17526a1d
commit
39379a2e9e
3 changed files with 150 additions and 2 deletions
|
@ -35,6 +35,7 @@ const createPublicAlertsClientMock = () => {
|
|||
return {
|
||||
create: jest.fn(),
|
||||
report: jest.fn(),
|
||||
isTrackedAlert: jest.fn(),
|
||||
getAlertLimitValue: jest.fn().mockReturnValue(1000),
|
||||
setAlertLimitReached: jest.fn(),
|
||||
getRecoveredAlerts: jest.fn().mockReturnValue([]),
|
||||
|
|
|
@ -87,7 +87,7 @@ const mockOptions = {
|
|||
};
|
||||
|
||||
const setEvaluationResults = (response: Array<Record<string, Evaluation>>) => {
|
||||
jest.requireMock('./lib/evaluate_rule').evaluateRule.mockImplementation(() => response);
|
||||
return jest.requireMock('./lib/evaluate_rule').evaluateRule.mockImplementation(() => response);
|
||||
};
|
||||
|
||||
describe('The metric threshold rule type', () => {
|
||||
|
@ -733,6 +733,148 @@ describe('The metric threshold rule type', () => {
|
|||
);
|
||||
expect(stateResult3.missingGroups).toEqual(expect.arrayContaining([]));
|
||||
});
|
||||
|
||||
test('should remove a group from previous missing groups if the related alert is untracked', async () => {
|
||||
setEvaluationResults([
|
||||
{
|
||||
a: {
|
||||
...baseNonCountCriterion,
|
||||
comparator: Comparator.GT,
|
||||
threshold: [0.75],
|
||||
metric: 'test.metric.2',
|
||||
currentValue: 1.0,
|
||||
timestamp: new Date().toISOString(),
|
||||
shouldFire: true,
|
||||
shouldWarn: false,
|
||||
isNoData: false,
|
||||
bucketKey: { groupBy0: 'a' },
|
||||
},
|
||||
b: {
|
||||
...baseNonCountCriterion,
|
||||
comparator: Comparator.GT,
|
||||
threshold: [0.75],
|
||||
metric: 'test.metric.2',
|
||||
currentValue: 3,
|
||||
timestamp: new Date().toISOString(),
|
||||
shouldFire: true,
|
||||
shouldWarn: false,
|
||||
isNoData: false,
|
||||
bucketKey: { groupBy0: 'b' },
|
||||
},
|
||||
c: {
|
||||
...baseNonCountCriterion,
|
||||
comparator: Comparator.GT,
|
||||
threshold: [0.75],
|
||||
metric: 'test.metric.2',
|
||||
currentValue: 3,
|
||||
timestamp: new Date().toISOString(),
|
||||
shouldFire: true,
|
||||
shouldWarn: false,
|
||||
isNoData: false,
|
||||
bucketKey: { groupBy0: 'c' },
|
||||
},
|
||||
},
|
||||
]);
|
||||
const { state: stateResult1 } = await executeWithFilter(
|
||||
Comparator.GT,
|
||||
[0.75],
|
||||
JSON.stringify({ query: 'q' }),
|
||||
'test.metric.2'
|
||||
);
|
||||
expect(stateResult1.missingGroups).toEqual(expect.arrayContaining([]));
|
||||
setEvaluationResults([
|
||||
{
|
||||
a: {
|
||||
...baseNonCountCriterion,
|
||||
comparator: Comparator.GT,
|
||||
threshold: [0.75],
|
||||
metric: 'test.metric.1',
|
||||
currentValue: 1.0,
|
||||
timestamp: new Date().toISOString(),
|
||||
shouldFire: true,
|
||||
shouldWarn: false,
|
||||
isNoData: false,
|
||||
bucketKey: { groupBy0: 'a' },
|
||||
},
|
||||
b: {
|
||||
...baseNonCountCriterion,
|
||||
comparator: Comparator.GT,
|
||||
threshold: [0.75],
|
||||
metric: 'test.metric.1',
|
||||
currentValue: null,
|
||||
timestamp: new Date().toISOString(),
|
||||
shouldFire: true,
|
||||
shouldWarn: false,
|
||||
isNoData: true,
|
||||
bucketKey: { groupBy0: 'b' },
|
||||
},
|
||||
c: {
|
||||
...baseNonCountCriterion,
|
||||
comparator: Comparator.GT,
|
||||
threshold: [0.75],
|
||||
metric: 'test.metric.1',
|
||||
currentValue: null,
|
||||
timestamp: new Date().toISOString(),
|
||||
shouldFire: false,
|
||||
shouldWarn: false,
|
||||
isNoData: true,
|
||||
bucketKey: { groupBy0: 'c' },
|
||||
},
|
||||
},
|
||||
]);
|
||||
const { state: stateResult2 } = await executeWithFilter(
|
||||
Comparator.GT,
|
||||
[0.75],
|
||||
JSON.stringify({ query: 'q' }),
|
||||
'test.metric.1',
|
||||
stateResult1
|
||||
);
|
||||
expect(stateResult2.missingGroups).toEqual([
|
||||
{ key: 'b', bucketKey: { groupBy0: 'b' } },
|
||||
{ key: 'c', bucketKey: { groupBy0: 'c' } },
|
||||
]);
|
||||
const mockedEvaluateRule = setEvaluationResults([
|
||||
{
|
||||
a: {
|
||||
...baseNonCountCriterion,
|
||||
comparator: Comparator.GT,
|
||||
threshold: [0.75],
|
||||
metric: 'test.metric.1',
|
||||
currentValue: 1.0,
|
||||
timestamp: new Date().toISOString(),
|
||||
shouldFire: true,
|
||||
shouldWarn: false,
|
||||
isNoData: false,
|
||||
bucketKey: { groupBy0: 'a' },
|
||||
},
|
||||
b: {
|
||||
...baseNonCountCriterion,
|
||||
comparator: Comparator.GT,
|
||||
threshold: [0.75],
|
||||
metric: 'test.metric.1',
|
||||
currentValue: null,
|
||||
timestamp: new Date().toISOString(),
|
||||
shouldFire: true,
|
||||
shouldWarn: false,
|
||||
isNoData: true,
|
||||
bucketKey: { groupBy0: 'b' },
|
||||
},
|
||||
},
|
||||
]);
|
||||
// Consider c as untracked
|
||||
services.alertsClient.isTrackedAlert.mockImplementation((id: string) => id !== 'c');
|
||||
const { state: stateResult3 } = await executeWithFilter(
|
||||
Comparator.GT,
|
||||
[0.75],
|
||||
JSON.stringify({ query: 'q' }),
|
||||
'test.metric.1',
|
||||
stateResult2
|
||||
);
|
||||
expect(stateResult3.missingGroups).toEqual([{ key: 'b', bucketKey: { groupBy0: 'b' } }]);
|
||||
expect(mockedEvaluateRule.mock.calls[2][8]).toEqual([
|
||||
{ bucketKey: { groupBy0: 'b' }, key: 'b' },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('querying with a groupBy parameter host.name and rule tags', () => {
|
||||
|
|
|
@ -224,7 +224,12 @@ export const createMetricThresholdExecutor =
|
|||
const groupByIsSame = isEqual(state.groupBy, params.groupBy);
|
||||
const previousMissingGroups =
|
||||
alertOnGroupDisappear && filterQueryIsSame && groupByIsSame && state.missingGroups
|
||||
? state.missingGroups
|
||||
? state.missingGroups.filter((missingGroup) =>
|
||||
// We use isTrackedAlert to remove missing groups that are untracked by the user
|
||||
typeof missingGroup === 'string'
|
||||
? alertsClient.isTrackedAlert(missingGroup)
|
||||
: alertsClient.isTrackedAlert(missingGroup.key)
|
||||
)
|
||||
: [];
|
||||
|
||||
const alertResults = await evaluateRule(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue