Skip to content

Commit 9cbedab

Browse files
denar50kibanamachine
authored andcommitted
Add global execution summary endpoint to alerting API (elastic#216477)
## Summary Added an internal endpoint `GET /internal/alerting/_global_execution_summary` to fetch an execution summary with the following shape: ``` { "executions": { "total": 18, "success": 18 }, "latestExecutionSummary": { "success": 2, "failure": 0, "warning": 0 } } ``` The `latestExecutionSummary` contains a counter of the outcome of the latest execution of each individual rule. ## How was this tested? I ran the Kibana locally, created two rules in two different spaces and called the endpoint for each space. ## Why not using the existing endpoint `GET /internal/alerting/_global_execution_kpi`? The existing endpoint has a [hard limit](https://github.com/elastic/kibana/blob/main/x-pack/platform/plugins/shared/alerting/server/lib/get_execution_log_aggregation.ts#L619) of 10k which can be easily hit in real scenarios. The limit exists because the results returned in the aggregations grow linearly with the amount of executions of a rule. In our use case we are only returning counters and the status of the last execution of each rule. Extending the existing endpoint won't give us the flexibility of having a longer time range (up to 3 days) which we need to implement the following summary in the frontend: ![image](https://github.com/user-attachments/assets/9cd8f331-1d0c-44b3-8c99-ef513a66b541) --------- Co-authored-by: kibanamachine <[email protected]>
1 parent a8c7bd0 commit 9cbedab

File tree

20 files changed

+712
-2
lines changed

20 files changed

+712
-2
lines changed

x-pack/platform/plugins/shared/alerting/common/execution_log_types.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,18 @@ export const EMPTY_EXECUTION_KPI_RESULT = {
3838
triggeredActions: 0,
3939
};
4040

41+
export const EMPTY_EXECUTION_SUMMARY_RESULT = {
42+
executions: {
43+
total: 0,
44+
success: 0,
45+
},
46+
latestExecutionSummary: {
47+
success: 0,
48+
failure: 0,
49+
warning: 0,
50+
},
51+
};
52+
4153
export type ExecutionLogSortFields = (typeof executionLogSortableColumns)[number];
4254

4355
export type ActionErrorLogSortFields = (typeof actionErrorLogSortableColumns)[number];

x-pack/platform/plugins/shared/alerting/common/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ export {
150150
executionLogSortableColumns,
151151
actionErrorLogSortableColumns,
152152
EMPTY_EXECUTION_KPI_RESULT,
153+
EMPTY_EXECUTION_SUMMARY_RESULT,
153154
} from './execution_log_types';
154155
export type { RuleSnoozeSchedule, RuleSnooze } from './rule_snooze_type';
155156
export type { RRuleParams, RRuleRecord } from './rrule_type';
@@ -246,6 +247,9 @@ export const INTERNAL_ALERTING_GAPS_GET_SUMMARY_BY_RULE_IDS_API_PATH =
246247
export const INTERNAL_ALERTING_GAPS_FILL_BY_ID_API_PATH =
247248
`${INTERNAL_ALERTING_GAPS_API_PATH}/_fill_by_id` as const;
248249

250+
export const INTERNAL_ALERTING_GET_GLOBAL_RULE_EXECUTION_SUMMARY_API_PATH =
251+
`${INTERNAL_BASE_ALERTING_API_PATH}/_global_execution_summary` as const;
252+
249253
// External
250254
export const ARCHIVE_MAINTENANCE_WINDOW_API_PATH = `${BASE_MAINTENANCE_WINDOW_API_PATH}/{id}/_archive`;
251255
export const UNARCHIVE_MAINTENANCE_WINDOW_API_PATH = `${BASE_MAINTENANCE_WINDOW_API_PATH}/{id}/_unarchive`;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
export {
9+
getGlobalExecutionSummarySchema,
10+
getGlobalExecutionSummaryResponseBodySchema,
11+
} from './schemas/latest';
12+
export type {
13+
GetGlobalExecutionSummary,
14+
GetGlobalExecutionSummaryResponseBody,
15+
GetGlobalExecutionSummaryResponse,
16+
} from './types/latest';
17+
18+
export {
19+
getGlobalExecutionSummarySchema as getGlobalExecutionSummarySchemaV1,
20+
getGlobalExecutionSummaryResponseBodySchema as getGlobalExecutionSummaryResponseBodySchemaV1,
21+
} from './schemas/v1';
22+
23+
export type {
24+
GetGlobalExecutionSummary as GetGlobalExecutionSummaryV1,
25+
GetGlobalExecutionSummaryResponse as GetGlobalExecutionSummaryResponseV1,
26+
GetGlobalExecutionSummaryResponseBody as GetGlobalExecutionSummaryResponseBodyV1,
27+
} from './types/v1';
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
export * from './v1';
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
import { schema } from '@kbn/config-schema';
8+
9+
export const getGlobalExecutionSummarySchema = schema.object(
10+
{
11+
date_start: schema.string(),
12+
date_end: schema.string(),
13+
},
14+
{
15+
validate({ date_start: start, date_end: end }) {
16+
const parsedStart = Date.parse(start);
17+
if (isNaN(parsedStart)) {
18+
return `[start]: query start must be valid date`;
19+
}
20+
21+
const parsedEnd = Date.parse(end);
22+
if (isNaN(parsedEnd)) {
23+
return `[end]: query end must be valid date`;
24+
}
25+
26+
if (parsedStart >= parsedEnd) {
27+
return `[start]: query start must be before end`;
28+
}
29+
},
30+
}
31+
);
32+
33+
const positiveNumber = schema.number({ min: 0 });
34+
35+
export const getGlobalExecutionSummaryResponseBodySchema = schema.object({
36+
executions: schema.object({
37+
total: positiveNumber,
38+
success: positiveNumber,
39+
}),
40+
latestExecutionSummary: schema.object({
41+
success: positiveNumber,
42+
failure: positiveNumber,
43+
warning: positiveNumber,
44+
}),
45+
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
export * from './v1';
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
import type { TypeOf } from '@kbn/config-schema';
9+
import type {
10+
getGlobalExecutionSummarySchema,
11+
getGlobalExecutionSummaryResponseBodySchema,
12+
} from '..';
13+
14+
export type GetGlobalExecutionSummary = TypeOf<typeof getGlobalExecutionSummarySchema>;
15+
export type GetGlobalExecutionSummaryResponseBody = TypeOf<
16+
typeof getGlobalExecutionSummaryResponseBodySchema
17+
>;
18+
19+
export interface GetGlobalExecutionSummaryResponse {
20+
body: GetGlobalExecutionSummaryResponseBody;
21+
}

x-pack/platform/plugins/shared/alerting/server/lib/__snapshots__/get_execution_log_aggregation.test.ts.snap

Lines changed: 54 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

x-pack/platform/plugins/shared/alerting/server/lib/get_execution_log_aggregation.test.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import {
1616
formatSortForTermSort,
1717
getExecutionKPIAggregation,
1818
formatExecutionKPIResult,
19+
getExecutionSummaryAggregation,
20+
formatExecutionSummaryResult,
1921
} from './get_execution_log_aggregation';
2022

2123
describe('formatSortForBucketSort', () => {
@@ -2979,3 +2981,70 @@ describe('formatExecutionKPIAggBuckets', () => {
29792981
);
29802982
});
29812983
});
2984+
2985+
describe('getExecutionSummaryAggregation', () => {
2986+
test('should correctly generate the aggregation', () => {
2987+
expect(getExecutionSummaryAggregation()).toMatchSnapshot();
2988+
});
2989+
});
2990+
2991+
describe('formatExecutionSummary', () => {
2992+
it('should format the latest execution summary correctly', () => {
2993+
const results = {
2994+
aggregations: {
2995+
executionsCount: { doc_count: 18 },
2996+
latestExecutionOutcome: {
2997+
doc_count: 18,
2998+
by_rule_id: {
2999+
buckets: [
3000+
{
3001+
key: '89b2e1a0-1282-4601-97e4-2a3b1a2ef43b',
3002+
doc_count: 12,
3003+
latest_execution: {
3004+
hits: {
3005+
total: { value: 12, relation: 'eq' },
3006+
hits: [
3007+
{
3008+
_source: { event: { outcome: 'success' } },
3009+
sort: [1742893715888],
3010+
},
3011+
],
3012+
},
3013+
},
3014+
},
3015+
{
3016+
key: 'e1e5eddc-5251-4bb4-8aa4-a76943dd82e1',
3017+
doc_count: 6,
3018+
latest_execution: {
3019+
hits: {
3020+
total: { value: 6, relation: 'eq' },
3021+
hits: [
3022+
{
3023+
_source: { event: { outcome: 'failure' } },
3024+
sort: [1742893718878],
3025+
},
3026+
],
3027+
},
3028+
},
3029+
},
3030+
],
3031+
},
3032+
},
3033+
successfulExecutionsCount: { doc_count: 17 },
3034+
},
3035+
hits: {
3036+
total: { value: 36, relation: 'eq' },
3037+
hits: [],
3038+
} as estypes.SearchHitsMetadata<unknown>,
3039+
};
3040+
3041+
expect(formatExecutionSummaryResult(results)).toEqual({
3042+
executions: { total: 18, success: 17 },
3043+
latestExecutionSummary: {
3044+
success: 1,
3045+
failure: 1,
3046+
warning: 0,
3047+
},
3048+
});
3049+
});
3050+
});

0 commit comments

Comments
 (0)