Skip to content

Commit

Permalink
[ResponseOps] The count of consecutive active alerts should be availa…
Browse files Browse the repository at this point in the history
…ble on the alert (elastic#177522)

Resolves elastic#175998

## Summary
Follow on work from the alert creation delay feature. This PR adds
consecutive_matches, which is the count of active alerts that is used to
determine the alert delay, to the aad doc and to the action variables.

### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

### To verify

- Create a new rule with an alert delay
- Add the new `alert.consecutiveMatches` action variable to the action
message. Verify that when the alert fires the action variable is
populated in the message.
- To verify that the alert docs are as expected, go to [Dev
Tools](http://localhost:5601/app/dev_tools#/console) and run the
following `GET .internal.alerts-*/_search`
- Go back to the rule alerts table, and add the
`kibana.alert.consecutive_matches` field to the table. Verify that it is
populated and looks as expected.

(cherry picked from commit 3c2956c)
  • Loading branch information
doakalexi committed Mar 12, 2024
1 parent a23d453 commit 3504a57
Show file tree
Hide file tree
Showing 31 changed files with 679 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
ALERT_FLAPPING,
ALERT_FLAPPING_HISTORY,
ALERT_MAINTENANCE_WINDOW_IDS,
ALERT_CONSECUTIVE_MATCHES,
ALERT_INSTANCE_ID,
ALERT_LAST_DETECTED,
ALERT_REASON,
Expand Down Expand Up @@ -80,6 +81,11 @@ export const alertFieldMap = {
array: true,
required: false,
},
[ALERT_CONSECUTIVE_MATCHES]: {
type: 'long',
array: false,
required: false,
},
[ALERT_INSTANCE_ID]: {
type: 'keyword',
array: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ const AlertOptional = rt.partial({
'event.kind': schemaString,
'kibana.alert.action_group': schemaString,
'kibana.alert.case_ids': schemaStringArray,
'kibana.alert.consecutive_matches': schemaStringOrNumber,
'kibana.alert.duration.us': schemaStringOrNumber,
'kibana.alert.end': schemaDate,
'kibana.alert.flapping': schemaBoolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ const SecurityAlertOptional = rt.partial({
'kibana.alert.ancestors.rule': schemaString,
'kibana.alert.building_block_type': schemaString,
'kibana.alert.case_ids': schemaStringArray,
'kibana.alert.consecutive_matches': schemaStringOrNumber,
'kibana.alert.duration.us': schemaStringOrNumber,
'kibana.alert.end': schemaDate,
'kibana.alert.flapping': schemaBoolean,
Expand Down
5 changes: 5 additions & 0 deletions packages/kbn-rule-data-utils/src/default_alerts_as_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ const ALERT_FLAPPING_HISTORY = `${ALERT_NAMESPACE}.flapping_history` as const;
// kibana.alert.maintenance_window_ids - IDs of maintenance windows that are affecting this alert
const ALERT_MAINTENANCE_WINDOW_IDS = `${ALERT_NAMESPACE}.maintenance_window_ids` as const;

// kibana.alert.consecutive_matches - count of consecutive times the alert has been active
const ALERT_CONSECUTIVE_MATCHES = `${ALERT_NAMESPACE}.consecutive_matches` as const;

// kibana.alert.instance.id - alert ID, also known as alert instance ID
const ALERT_INSTANCE_ID = `${ALERT_NAMESPACE}.instance.id` as const;

Expand Down Expand Up @@ -120,6 +123,7 @@ const fields = {
ALERT_FLAPPING,
ALERT_FLAPPING_HISTORY,
ALERT_MAINTENANCE_WINDOW_IDS,
ALERT_CONSECUTIVE_MATCHES,
ALERT_INSTANCE_ID,
ALERT_LAST_DETECTED,
ALERT_REASON,
Expand Down Expand Up @@ -160,6 +164,7 @@ export {
ALERT_FLAPPING,
ALERT_FLAPPING_HISTORY,
ALERT_MAINTENANCE_WINDOW_IDS,
ALERT_CONSECUTIVE_MATCHES,
ALERT_INSTANCE_ID,
ALERT_LAST_DETECTED,
ALERT_REASON,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@ describe('mappingFromFieldMap', () => {
case_ids: {
type: 'keyword',
},
consecutive_matches: {
type: 'long',
},
duration: {
properties: {
us: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from '../types';
import {
ALERT_ACTION_GROUP,
ALERT_CONSECUTIVE_MATCHES,
ALERT_DURATION,
ALERT_END,
ALERT_FLAPPING,
Expand Down Expand Up @@ -154,6 +155,7 @@ const fetchedAlert1 = {
[EVENT_ACTION]: 'open',
[EVENT_KIND]: 'signal',
[ALERT_ACTION_GROUP]: 'default',
[ALERT_CONSECUTIVE_MATCHES]: 0,
[ALERT_DURATION]: 0,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [true],
Expand Down Expand Up @@ -184,6 +186,7 @@ const fetchedAlert2 = {
[EVENT_ACTION]: 'active',
[EVENT_KIND]: 'signal',
[ALERT_ACTION_GROUP]: 'default',
[ALERT_CONSECUTIVE_MATCHES]: 0,
[ALERT_DURATION]: 36000000000,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [true, false],
Expand Down Expand Up @@ -214,6 +217,7 @@ const getNewIndexedAlertDoc = (overrides = {}) => ({
[EVENT_ACTION]: 'open',
[EVENT_KIND]: 'signal',
[ALERT_ACTION_GROUP]: 'default',
[ALERT_CONSECUTIVE_MATCHES]: 1,
[ALERT_DURATION]: 0,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [true],
Expand Down Expand Up @@ -260,6 +264,7 @@ const getRecoveredIndexedAlertDoc = (overrides = {}) => ({
[ALERT_END]: date,
[ALERT_TIME_RANGE]: { gte: '2023-03-28T12:27:28.159Z', lte: date },
[ALERT_STATUS]: 'recovered',
[ALERT_CONSECUTIVE_MATCHES]: 0,
...overrides,
});

Expand Down Expand Up @@ -670,6 +675,7 @@ describe('Alerts Client', () => {
[TIMESTAMP]: date,
[EVENT_ACTION]: 'active',
[ALERT_ACTION_GROUP]: 'default',
[ALERT_CONSECUTIVE_MATCHES]: 1,
[ALERT_DURATION]: 36000000000,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [true, false],
Expand Down Expand Up @@ -777,7 +783,7 @@ describe('Alerts Client', () => {
},
},
// ongoing alert doc
getOngoingIndexedAlertDoc({ [ALERT_UUID]: 'abc' }),
getOngoingIndexedAlertDoc({ [ALERT_UUID]: 'abc', [ALERT_CONSECUTIVE_MATCHES]: 0 }),
],
});
});
Expand Down Expand Up @@ -950,6 +956,7 @@ describe('Alerts Client', () => {
[TIMESTAMP]: date,
[EVENT_ACTION]: 'active',
[ALERT_ACTION_GROUP]: 'default',
[ALERT_CONSECUTIVE_MATCHES]: 1,
[ALERT_DURATION]: 72000000000,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [true, false, false, false],
Expand Down Expand Up @@ -997,6 +1004,7 @@ describe('Alerts Client', () => {
[TIMESTAMP]: date,
[EVENT_ACTION]: 'close',
[ALERT_ACTION_GROUP]: 'recovered',
[ALERT_CONSECUTIVE_MATCHES]: 0,
[ALERT_DURATION]: 36000000000,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [true, true],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
TIMESTAMP,
VERSION,
ALERT_TIME_RANGE,
ALERT_CONSECUTIVE_MATCHES,
} from '@kbn/rule-data-utils';
import { alertRule } from './test_fixtures';

Expand All @@ -46,6 +47,7 @@ describe('buildNewAlert', () => {
[EVENT_ACTION]: 'open',
[EVENT_KIND]: 'signal',
[ALERT_ACTION_GROUP]: 'default',
[ALERT_CONSECUTIVE_MATCHES]: 0,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_INSTANCE_ID]: 'alert-A',
Expand Down Expand Up @@ -77,6 +79,7 @@ describe('buildNewAlert', () => {
[EVENT_ACTION]: 'open',
[EVENT_KIND]: 'signal',
[ALERT_ACTION_GROUP]: 'default',
[ALERT_CONSECUTIVE_MATCHES]: 0,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_INSTANCE_ID]: 'alert-A',
Expand Down Expand Up @@ -112,6 +115,7 @@ describe('buildNewAlert', () => {
[EVENT_ACTION]: 'open',
[EVENT_KIND]: 'signal',
[ALERT_ACTION_GROUP]: 'default',
[ALERT_CONSECUTIVE_MATCHES]: 0,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [true, false, false, false, true, true],
[ALERT_INSTANCE_ID]: 'alert-A',
Expand Down Expand Up @@ -152,6 +156,7 @@ describe('buildNewAlert', () => {
[EVENT_ACTION]: 'open',
[EVENT_KIND]: 'signal',
[ALERT_ACTION_GROUP]: 'default',
[ALERT_CONSECUTIVE_MATCHES]: 0,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_INSTANCE_ID]: 'alert-A',
Expand Down Expand Up @@ -197,6 +202,7 @@ describe('buildNewAlert', () => {
[EVENT_ACTION]: 'open',
[EVENT_KIND]: 'signal',
[ALERT_ACTION_GROUP]: 'default',
[ALERT_CONSECUTIVE_MATCHES]: 0,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_INSTANCE_ID]: 'alert-A',
Expand Down Expand Up @@ -247,6 +253,7 @@ describe('buildNewAlert', () => {
[EVENT_ACTION]: 'open',
[EVENT_KIND]: 'signal',
[ALERT_ACTION_GROUP]: 'default',
[ALERT_CONSECUTIVE_MATCHES]: 0,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_INSTANCE_ID]: 'alert-A',
Expand Down Expand Up @@ -299,6 +306,7 @@ describe('buildNewAlert', () => {
[EVENT_ACTION]: 'open',
[EVENT_KIND]: 'signal',
[ALERT_ACTION_GROUP]: 'default',
[ALERT_CONSECUTIVE_MATCHES]: 0,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_INSTANCE_ID]: 'alert-A',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
ALERT_FLAPPING_HISTORY,
ALERT_INSTANCE_ID,
ALERT_MAINTENANCE_WINDOW_IDS,
ALERT_CONSECUTIVE_MATCHES,
ALERT_RULE_TAGS,
ALERT_START,
ALERT_STATUS,
Expand Down Expand Up @@ -86,6 +87,7 @@ export const buildNewAlert = <
[ALERT_FLAPPING_HISTORY]: legacyAlert.getFlappingHistory(),
[ALERT_INSTANCE_ID]: legacyAlert.getId(),
[ALERT_MAINTENANCE_WINDOW_IDS]: legacyAlert.getMaintenanceWindowIds(),
[ALERT_CONSECUTIVE_MATCHES]: legacyAlert.getActiveCount(),
[ALERT_STATUS]: 'active',
[ALERT_UUID]: legacyAlert.getUuid(),
[ALERT_WORKFLOW_STATUS]: get(cleanedPayload, ALERT_WORKFLOW_STATUS, 'open'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
TIMESTAMP,
VERSION,
ALERT_TIME_RANGE,
ALERT_CONSECUTIVE_MATCHES,
} from '@kbn/rule-data-utils';
import { alertRule, existingFlattenedNewAlert, existingExpandedNewAlert } from './test_fixtures';

Expand Down Expand Up @@ -55,6 +56,7 @@ for (const flattened of [true, false]) {
[TIMESTAMP]: '2023-03-29T12:27:28.159Z',
[EVENT_ACTION]: 'active',
[ALERT_ACTION_GROUP]: 'warning',
[ALERT_CONSECUTIVE_MATCHES]: 0,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
Expand Down Expand Up @@ -114,6 +116,7 @@ for (const flattened of [true, false]) {
[TIMESTAMP]: '2023-03-29T12:27:28.159Z',
[EVENT_ACTION]: 'active',
[ALERT_ACTION_GROUP]: 'warning',
[ALERT_CONSECUTIVE_MATCHES]: 0,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
Expand Down Expand Up @@ -190,6 +193,7 @@ for (const flattened of [true, false]) {
[TIMESTAMP]: '2023-03-29T12:27:28.159Z',
[EVENT_ACTION]: 'active',
[ALERT_ACTION_GROUP]: 'error',
[ALERT_CONSECUTIVE_MATCHES]: 0,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [false, false, true, true],
[ALERT_MAINTENANCE_WINDOW_IDS]: ['maint-xyz'],
Expand Down Expand Up @@ -279,6 +283,7 @@ for (const flattened of [true, false]) {
[TIMESTAMP]: '2023-03-29T12:27:28.159Z',
[EVENT_ACTION]: 'active',
[ALERT_ACTION_GROUP]: 'warning',
[ALERT_CONSECUTIVE_MATCHES]: 0,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
Expand Down Expand Up @@ -375,6 +380,7 @@ for (const flattened of [true, false]) {
[TIMESTAMP]: '2023-03-29T12:27:28.159Z',
[EVENT_ACTION]: 'active',
[ALERT_ACTION_GROUP]: 'warning',
[ALERT_CONSECUTIVE_MATCHES]: 0,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
Expand Down Expand Up @@ -475,6 +481,7 @@ for (const flattened of [true, false]) {
[TIMESTAMP]: '2023-03-29T12:27:28.159Z',
[EVENT_ACTION]: 'active',
[ALERT_ACTION_GROUP]: 'warning',
[ALERT_CONSECUTIVE_MATCHES]: 0,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
Expand Down Expand Up @@ -555,6 +562,7 @@ for (const flattened of [true, false]) {
[TIMESTAMP]: '2023-03-29T12:27:28.159Z',
[EVENT_ACTION]: 'active',
[ALERT_ACTION_GROUP]: 'warning',
[ALERT_CONSECUTIVE_MATCHES]: 0,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
Expand Down Expand Up @@ -653,6 +661,7 @@ for (const flattened of [true, false]) {
[TIMESTAMP]: '2023-03-29T12:27:28.159Z',
[EVENT_ACTION]: 'active',
[ALERT_ACTION_GROUP]: 'warning',
[ALERT_CONSECUTIVE_MATCHES]: 0,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import deepmerge from 'deepmerge';
import type { Alert } from '@kbn/alerts-as-data-utils';
import {
ALERT_ACTION_GROUP,
ALERT_CONSECUTIVE_MATCHES,
ALERT_DURATION,
ALERT_FLAPPING,
ALERT_FLAPPING_HISTORY,
Expand Down Expand Up @@ -93,6 +94,8 @@ export const buildOngoingAlert = <
[ALERT_FLAPPING_HISTORY]: legacyAlert.getFlappingHistory(),
// Set latest maintenance window IDs
[ALERT_MAINTENANCE_WINDOW_IDS]: legacyAlert.getMaintenanceWindowIds(),
// Set latest match count
[ALERT_CONSECUTIVE_MATCHES]: legacyAlert.getActiveCount(),
// Set the time range
...(legacyAlert.getState().start
? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
VERSION,
ALERT_TIME_RANGE,
ALERT_END,
ALERT_CONSECUTIVE_MATCHES,
} from '@kbn/rule-data-utils';
import {
alertRule,
Expand Down Expand Up @@ -63,6 +64,7 @@ for (const flattened of [true, false]) {
[TIMESTAMP]: '2023-03-29T12:27:28.159Z',
[EVENT_ACTION]: 'close',
[ALERT_ACTION_GROUP]: 'recovered',
[ALERT_CONSECUTIVE_MATCHES]: 0,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
Expand Down Expand Up @@ -127,6 +129,7 @@ for (const flattened of [true, false]) {
[TIMESTAMP]: '2023-03-29T12:27:28.159Z',
[EVENT_ACTION]: 'close',
[ALERT_ACTION_GROUP]: 'NoLongerActive',
[ALERT_CONSECUTIVE_MATCHES]: 0,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_MAINTENANCE_WINDOW_IDS]: ['maint-1', 'maint-321'],
Expand Down Expand Up @@ -221,6 +224,7 @@ for (const flattened of [true, false]) {
[TIMESTAMP]: '2023-03-29T12:27:28.159Z',
[EVENT_ACTION]: 'close',
[ALERT_ACTION_GROUP]: 'NoLongerActive',
[ALERT_CONSECUTIVE_MATCHES]: 0,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_MAINTENANCE_WINDOW_IDS]: ['maint-1', 'maint-321'],
Expand Down Expand Up @@ -323,6 +327,7 @@ for (const flattened of [true, false]) {
[TIMESTAMP]: '2023-03-29T12:27:28.159Z',
[EVENT_ACTION]: 'close',
[ALERT_ACTION_GROUP]: 'NoLongerActive',
[ALERT_CONSECUTIVE_MATCHES]: 0,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_MAINTENANCE_WINDOW_IDS]: ['maint-1', 'maint-321'],
Expand Down Expand Up @@ -423,6 +428,7 @@ for (const flattened of [true, false]) {
[TIMESTAMP]: '2023-03-29T12:27:28.159Z',
[EVENT_ACTION]: 'close',
[ALERT_ACTION_GROUP]: 'NoLongerActive',
[ALERT_CONSECUTIVE_MATCHES]: 0,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_MAINTENANCE_WINDOW_IDS]: ['maint-1', 'maint-321'],
Expand Down Expand Up @@ -522,6 +528,7 @@ for (const flattened of [true, false]) {
[TIMESTAMP]: '2023-03-29T12:27:28.159Z',
[EVENT_ACTION]: 'close',
[ALERT_ACTION_GROUP]: 'NoLongerActive',
[ALERT_CONSECUTIVE_MATCHES]: 0,
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
ALERT_END,
ALERT_TIME_RANGE,
ALERT_START,
ALERT_CONSECUTIVE_MATCHES,
} from '@kbn/rule-data-utils';
import { DeepPartial } from '@kbn/utility-types';
import { Alert as LegacyAlert } from '../../alert/alert';
Expand Down Expand Up @@ -92,6 +93,8 @@ export const buildRecoveredAlert = <
[ALERT_FLAPPING_HISTORY]: legacyAlert.getFlappingHistory(),
// Set latest maintenance window IDs
[ALERT_MAINTENANCE_WINDOW_IDS]: legacyAlert.getMaintenanceWindowIds(),
// Set latest match count, should be 0
[ALERT_CONSECUTIVE_MATCHES]: legacyAlert.getActiveCount(),
// Set status to 'recovered'
[ALERT_STATUS]: 'recovered',
// Set latest duration as recovered alerts should have updated duration
Expand Down
Loading

0 comments on commit 3504a57

Please sign in to comment.