From 1fb21e140d4d34813f86498f8fce55edf8a992ce Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Thu, 17 Jun 2021 18:35:22 +0100 Subject: [PATCH 01/13] Add optimisations for executor / chart previews --- .../alerting/logs/log_threshold/types.ts | 58 ++++++- .../http_api/log_alerts/chart_preview_data.ts | 4 + .../criterion_preview_chart.tsx | 11 +- .../log_threshold_chart_preview.ts | 53 ++++-- .../log_threshold/log_threshold_executor.ts | 155 +++++++++++++----- 5 files changed, 223 insertions(+), 58 deletions(-) diff --git a/x-pack/plugins/infra/common/alerting/logs/log_threshold/types.ts b/x-pack/plugins/infra/common/alerting/logs/log_threshold/types.ts index f1e983fc34df8..55c450ac63063 100644 --- a/x-pack/plugins/infra/common/alerting/logs/log_threshold/types.ts +++ b/x-pack/plugins/infra/common/alerting/logs/log_threshold/types.ts @@ -100,7 +100,7 @@ export enum AlertStates { ERROR, } -const ThresholdRT = rt.type({ +export const ThresholdRT = rt.type({ comparator: ComparatorRT, value: rt.number, }); @@ -264,7 +264,7 @@ export const UngroupedSearchQueryResponseRT = rt.intersection([ export type UngroupedSearchQueryResponse = rt.TypeOf; -export const GroupedSearchQueryResponseRT = rt.intersection([ +export const UnoptimizedGroupedSearchQueryResponseRT = rt.intersection([ commonSearchSuccessResponseFieldsRT, rt.type({ aggregations: rt.type({ @@ -301,4 +301,58 @@ export const GroupedSearchQueryResponseRT = rt.intersection([ }), ]); +export type UnoptimizedGroupedSearchQueryResponse = rt.TypeOf< + typeof UnoptimizedGroupedSearchQueryResponseRT +>; + +export const OptimizedGroupedSearchQueryResponseRT = rt.intersection([ + commonSearchSuccessResponseFieldsRT, + rt.type({ + aggregations: rt.type({ + groups: rt.intersection([ + rt.type({ + buckets: rt.array( + rt.intersection([ + rt.type({ + key: rt.record(rt.string, rt.string), + doc_count: rt.number, + }), + // Chart preview buckets + rt.partial({ + histogramBuckets: rt.type({ + buckets: rt.array(chartPreviewHistogramBucket), + }), + }), + ]) + ), + }), + rt.partial({ + after_key: rt.record(rt.string, rt.string), + }), + ]), + }), + hits: rt.type({ + total: rt.type({ + value: rt.number, + }), + }), + }), +]); + +export type OptimizedGroupedSearchQueryResponse = rt.TypeOf< + typeof OptimizedGroupedSearchQueryResponseRT +>; + +export const GroupedSearchQueryResponseRT = rt.union([ + UnoptimizedGroupedSearchQueryResponseRT, + OptimizedGroupedSearchQueryResponseRT, +]); + export type GroupedSearchQueryResponse = rt.TypeOf; + +export const isOptimizedGroupedSearchQueryResponse = ( + response: GroupedSearchQueryResponse['aggregations']['groups']['buckets'] +): response is OptimizedGroupedSearchQueryResponse['aggregations']['groups']['buckets'] => { + const result = response[0]; + return result && !result.hasOwnProperty('filtered_results'); +}; diff --git a/x-pack/plugins/infra/common/http_api/log_alerts/chart_preview_data.ts b/x-pack/plugins/infra/common/http_api/log_alerts/chart_preview_data.ts index e6baca305508e..310a8b65577c6 100644 --- a/x-pack/plugins/infra/common/http_api/log_alerts/chart_preview_data.ts +++ b/x-pack/plugins/infra/common/http_api/log_alerts/chart_preview_data.ts @@ -7,6 +7,7 @@ import * as rt from 'io-ts'; import { + ThresholdRT, countCriteriaRT, timeUnitRT, timeSizeRT, @@ -58,6 +59,9 @@ export type GetLogAlertsChartPreviewDataSuccessResponsePayload = rt.TypeOf< export const getLogAlertsChartPreviewDataAlertParamsSubsetRT: any = rt.intersection([ rt.type({ criteria: countCriteriaRT, + count: rt.type({ + comparator: ThresholdRT.props.comparator, + }), timeUnit: timeUnitRT, timeSize: timeSizeRT, }), diff --git a/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/criterion_preview_chart.tsx b/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/criterion_preview_chart.tsx index 4e84cf0f9127c..701a6567f58df 100644 --- a/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/criterion_preview_chart.tsx +++ b/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/criterion_preview_chart.tsx @@ -68,6 +68,9 @@ export const CriterionPreview: React.FC = ({ const criteria = field && comparator && value ? [{ field, comparator, value }] : []; const params = { criteria, + count: { + comparator: alertParams.count.comparator, + }, timeSize: alertParams.timeSize, timeUnit: alertParams.timeUnit, groupBy: alertParams.groupBy, @@ -78,7 +81,13 @@ export const CriterionPreview: React.FC = ({ } catch (error) { return null; } - }, [alertParams.timeSize, alertParams.timeUnit, alertParams.groupBy, chartCriterion]); + }, [ + alertParams.timeSize, + alertParams.timeUnit, + alertParams.groupBy, + alertParams.count.comparator, + chartCriterion, + ]); // Check for the existence of properties that are necessary for a meaningful chart. if (chartAlertParams === null || chartAlertParams.criteria.length === 0) return null; diff --git a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_chart_preview.ts b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_chart_preview.ts index 321273c656216..bdf9e7fa95ed3 100644 --- a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_chart_preview.ts +++ b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_chart_preview.ts @@ -23,6 +23,7 @@ import { UngroupedSearchQueryResponse, GroupedSearchQueryResponse, GroupedSearchQueryResponseRT, + isOptimizedGroupedSearchQueryResponse, } from '../../../../common/alerting/logs/log_threshold/types'; import { decodeOrThrow } from '../../../../common/runtime_types'; import { ResolvedLogSourceConfiguration } from '../../../../common/log_sources'; @@ -97,10 +98,18 @@ const addHistogramAggregationToQuery = ( }; if (isGrouped) { - query.body.aggregations.groups.aggregations.filtered_results = { - ...query.body.aggregations.groups.aggregations.filtered_results, - aggregations: histogramAggregation, - }; + // Optimized + if (!query.body.aggregations.groups.aggregations?.filtered_results) { + query.body.aggregations.groups.aggregations = { + ...query.body.aggregations.groups.aggregations, + ...histogramAggregation, + }; + } else { + query.body.aggregations.groups.aggregations.filtered_results = { + ...query.body.aggregations.groups.aggregations.filtered_results, + aggregations: histogramAggregation, + }; + } } else { query.body = { ...query.body, @@ -151,18 +160,34 @@ const getGroupedResults = async ( const processGroupedResults = ( results: GroupedSearchQueryResponse['aggregations']['groups']['buckets'] ): Series => { - return results.reduce((series, group) => { - if (!group.filtered_results.histogramBuckets) return series; - const groupName = Object.values(group.key).join(', '); - const points = group.filtered_results.histogramBuckets.buckets.reduce( - (pointsAcc, bucket) => { + const getGroupName = ( + key: GroupedSearchQueryResponse['aggregations']['groups']['buckets'][0]['key'] + ) => Object.values(key).join(', '); + + if (isOptimizedGroupedSearchQueryResponse(results)) { + return results.reduce((series, group) => { + if (!group.histogramBuckets) return series; + const groupName = getGroupName(group.key); + const points = group.histogramBuckets.buckets.reduce((pointsAcc, bucket) => { const { key, doc_count: count } = bucket; return [...pointsAcc, { timestamp: key, value: count }]; - }, - [] - ); - return [...series, { id: groupName, points }]; - }, []); + }, []); + return [...series, { id: groupName, points }]; + }, []); + } else { + return results.reduce((series, group) => { + if (!group.filtered_results.histogramBuckets) return series; + const groupName = getGroupName(group.key); + const points = group.filtered_results.histogramBuckets.buckets.reduce( + (pointsAcc, bucket) => { + const { key, doc_count: count } = bucket; + return [...pointsAcc, { timestamp: key, value: count }]; + }, + [] + ); + return [...series, { id: groupName, points }]; + }, []); + } }; const processUngroupedResults = (results: UngroupedSearchQueryResponse): Series => { diff --git a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts index a537801202217..3d2d3b4a3e20a 100644 --- a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts +++ b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts @@ -36,6 +36,7 @@ import { CountCriteria, CountAlertParams, RatioAlertParams, + isOptimizedGroupedSearchQueryResponse, } from '../../../../common/alerting/logs/log_threshold/types'; import { InfraBackendLibs } from '../../infra_types'; import { getIntervalInSeconds } from '../../../utils/get_interval_in_seconds'; @@ -57,7 +58,7 @@ type LogThresholdAlertExecutorOptions = AlertExecutorOptions< LogThresholdActionGroups >; -const COMPOSITE_GROUP_SIZE = 40; +const COMPOSITE_GROUP_SIZE = 2000; const checkValueAgainstComparatorMap: { [key: string]: (a: number, b: number) => boolean; @@ -68,6 +69,10 @@ const checkValueAgainstComparatorMap: { [Comparator.LT_OR_EQ]: (a: number, b: number) => a <= b, }; +// The executor execution roughly follows a pattern of: +// ES Query generation -> fetching of results -> processing of results. +// With forks for group_by vs ungrouped, and ratio vs non-ratio. + export const createLogThresholdExecutor = (libs: InfraBackendLibs) => async function ({ services, params }: LogThresholdAlertExecutorOptions) { const { alertInstanceFactory, savedObjectsClient, scopedClusterClient } = services; @@ -277,11 +282,26 @@ type ReducedGroupByResults = ReducedGroupByResult[]; const getReducedGroupByResults = ( results: GroupedSearchQueryResponse['aggregations']['groups']['buckets'] ): ReducedGroupByResults => { - return results.reduce((acc, groupBucket) => { - const groupName = Object.values(groupBucket.key).join(', '); - const groupResult = { name: groupName, documentCount: groupBucket.filtered_results.doc_count }; - return [...acc, groupResult]; - }, []); + const getGroupName = ( + key: GroupedSearchQueryResponse['aggregations']['groups']['buckets'][0]['key'] + ) => Object.values(key).join(', '); + + if (isOptimizedGroupedSearchQueryResponse(results)) { + return results.reduce((acc, groupBucket) => { + const groupName = getGroupName(groupBucket.key); + const groupResult = { name: groupName, documentCount: groupBucket.doc_count }; + return [...acc, groupResult]; + }, []); + } else { + return results.reduce((acc, groupBucket) => { + const groupName = getGroupName(groupBucket.key); + const groupResult = { + name: groupName, + documentCount: groupBucket.filtered_results.doc_count, + }; + return [...acc, groupResult]; + }, []); + } }; export const processGroupByResults = ( @@ -430,12 +450,26 @@ export const buildFiltersFromCriteria = ( }; export const getGroupedESQuery = ( - params: Pick & { criteria: CountCriteria }, + params: Pick & { + criteria: CountCriteria; + count: Pick; + }, timestampField: string, index: string, runtimeMappings: estypes.MappingRuntimeFields ): estypes.SearchRequest | undefined => { - const { groupBy } = params; + // IMPORTANT: + // For the group by scenario we need to account for users utilizing "less than" configurations + // to attempt to match on "0", e.g. something has stopped reporting. We need to cast a wider net for these + // configurations to try and capture more documents, so that the filtering doesn't make the group "disappear". + // Due to this there are two forks in the group by code, one where we can optimize the filtering early, and one where + // it is an inner aggregation. "Less than" configurations with high cardinality group by fields can cause severe performance + // problems. + + const { + groupBy, + count: { comparator }, + } = params; if (!groupBy || !groupBy.length) { return; @@ -446,47 +480,86 @@ export const getGroupedESQuery = ( timestampField ); - const aggregations = { - groups: { - composite: { - size: COMPOSITE_GROUP_SIZE, - sources: groupBy.map((field, groupIndex) => ({ - [`group-${groupIndex}-${field}`]: { - terms: { field }, - }, - })), + const isOptimizableComparator = (selectedComparator: AlertParams['count']['comparator']) => { + const optimizableThresholdComparators = [Comparator.GT]; + return optimizableThresholdComparators.includes(selectedComparator); + }; + + if (isOptimizableComparator(comparator)) { + const aggregations = { + groups: { + composite: { + size: COMPOSITE_GROUP_SIZE, + sources: groupBy.map((field, groupIndex) => ({ + [`group-${groupIndex}-${field}`]: { + terms: { field }, + }, + })), + }, + }, + }; + + const body: estypes.SearchRequest['body'] = { + query: { + bool: { + filter: [rangeFilter, ...mustFilters], + ...(mustNotFilters.length > 0 && { must_not: mustNotFilters }), + }, }, - aggregations: { - filtered_results: { - filter: { - bool: { - // Scope the inner filtering back to the unpadded range - filter: [rangeFilter, ...mustFilters], - ...(mustNotFilters.length > 0 && { must_not: mustNotFilters }), + aggregations, + runtime_mappings: runtimeMappings, + size: 0, + }; + + return { + index, + allow_no_indices: true, + ignore_unavailable: true, + body, + }; + } else { + const aggregations = { + groups: { + composite: { + size: COMPOSITE_GROUP_SIZE, + sources: groupBy.map((field, groupIndex) => ({ + [`group-${groupIndex}-${field}`]: { + terms: { field }, + }, + })), + }, + aggregations: { + filtered_results: { + filter: { + bool: { + // Scope the inner filtering back to the unpadded range + filter: [rangeFilter, ...mustFilters], + ...(mustNotFilters.length > 0 && { must_not: mustNotFilters }), + }, }, }, }, }, - }, - }; + }; - const body: estypes.SearchRequest['body'] = { - query: { - bool: { - filter: [groupedRangeFilter], + const body: estypes.SearchRequest['body'] = { + query: { + bool: { + filter: [groupedRangeFilter], + }, }, - }, - aggregations, - runtime_mappings: runtimeMappings, - size: 0, - }; + aggregations, + runtime_mappings: runtimeMappings, + size: 0, + }; - return { - index, - allow_no_indices: true, - ignore_unavailable: true, - body, - }; + return { + index, + allow_no_indices: true, + ignore_unavailable: true, + body, + }; + } }; export const getUngroupedESQuery = ( From 1475a4b3c41fec2b907175e99d44e1317c87c327 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Fri, 18 Jun 2021 14:53:36 +0100 Subject: [PATCH 02/13] Amend / add unit tests --- .../log_threshold_executor.test.ts | 347 ++++++++++++------ 1 file changed, 241 insertions(+), 106 deletions(-) diff --git a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.test.ts b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.test.ts index ffabd7ba65f03..642f6755ff56f 100644 --- a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.test.ts +++ b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.test.ts @@ -194,7 +194,7 @@ describe('Log threshold executor', () => { describe('ES queries', () => { describe('Query generation', () => { - test('Correctly generates ungrouped queries', () => { + it('Correctly generates ungrouped queries', () => { const alertParams: AlertParams = { ...baseAlertParams, criteria: [...positiveCriteria, ...negativeCriteria], @@ -304,148 +304,283 @@ describe('Log threshold executor', () => { }); }); - test('Correctly generates grouped queries', () => { - const alertParams: AlertParams = { - ...baseAlertParams, - groupBy: ['host.name'], - criteria: [...positiveCriteria, ...negativeCriteria], - }; - const query = getGroupedESQuery( - alertParams, - TIMESTAMP_FIELD, - FILEBEAT_INDEX, - runtimeMappings - ); - expect(query).toEqual({ - index: 'filebeat-*', - allow_no_indices: true, - ignore_unavailable: true, - body: { - query: { - bool: { - filter: [ - { - range: { - '@timestamp': { - gte: expect.any(Number), - lte: expect.any(Number), - format: 'epoch_millis', + describe('Correctly generates grouped queries', () => { + it('When using an optimizable threshold comparator', () => { + const alertParams: AlertParams = { + ...baseAlertParams, + groupBy: ['host.name'], + criteria: [...positiveCriteria, ...negativeCriteria], + }; + const query = getGroupedESQuery( + alertParams, + TIMESTAMP_FIELD, + FILEBEAT_INDEX, + runtimeMappings + ); + + expect(query).toEqual({ + index: 'filebeat-*', + allow_no_indices: true, + ignore_unavailable: true, + body: { + query: { + bool: { + filter: [ + { + range: { + '@timestamp': { + gte: expect.any(Number), + lte: expect.any(Number), + format: 'epoch_millis', + }, + }, + }, + { + range: { + numericField: { + gt: 10, + }, + }, + }, + { + range: { + numericField: { + gte: 10, + }, + }, + }, + { + range: { + numericField: { + lt: 10, + }, + }, + }, + { + range: { + numericField: { + lte: 10, + }, + }, + }, + { + term: { + keywordField: { + value: 'error', + }, + }, + }, + { + match: { + textField: 'Something went wrong', + }, + }, + { + match_phrase: { + textField: 'Something went wrong', + }, + }, + ], + must_not: [ + { + term: { + keywordField: { + value: 'error', + }, + }, + }, + { + match: { + textField: 'Something went wrong', + }, + }, + { + match_phrase: { + textField: 'Something went wrong', }, }, + ], + }, + }, + aggregations: { + groups: { + composite: { + size: 2000, + sources: [ + { + 'group-0-host.name': { + terms: { + field: 'host.name', + }, + }, + }, + ], }, - ], + }, }, + runtime_mappings: { + runtime_field: { + type: 'keyword', + script: { + lang: 'painless', + source: 'emit("a runtime value")', + }, + }, + }, + size: 0, + }, + }); + }); + + it('When not using an optimizable threshold comparator', () => { + const alertParams: AlertParams = { + ...baseAlertParams, + count: { + ...baseAlertParams.count, + comparator: Comparator.LT, }, - aggregations: { - groups: { - composite: { - size: 40, - sources: [ + groupBy: ['host.name'], + criteria: [...positiveCriteria, ...negativeCriteria], + }; + + const query = getGroupedESQuery( + alertParams, + TIMESTAMP_FIELD, + FILEBEAT_INDEX, + runtimeMappings + ); + + expect(query).toEqual({ + index: 'filebeat-*', + allow_no_indices: true, + ignore_unavailable: true, + body: { + query: { + bool: { + filter: [ { - 'group-0-host.name': { - terms: { - field: 'host.name', + range: { + '@timestamp': { + gte: expect.any(Number), + lte: expect.any(Number), + format: 'epoch_millis', }, }, }, ], }, - aggregations: { - filtered_results: { - filter: { - bool: { - filter: [ - { - range: { - '@timestamp': { - gte: expect.any(Number), - lte: expect.any(Number), - format: 'epoch_millis', + }, + aggregations: { + groups: { + composite: { + size: 2000, + sources: [ + { + 'group-0-host.name': { + terms: { + field: 'host.name', + }, + }, + }, + ], + }, + aggregations: { + filtered_results: { + filter: { + bool: { + filter: [ + { + range: { + '@timestamp': { + gte: expect.any(Number), + lte: expect.any(Number), + format: 'epoch_millis', + }, }, }, - }, - { - range: { - numericField: { - gt: 10, + { + range: { + numericField: { + gt: 10, + }, }, }, - }, - { - range: { - numericField: { - gte: 10, + { + range: { + numericField: { + gte: 10, + }, }, }, - }, - { - range: { - numericField: { - lt: 10, + { + range: { + numericField: { + lt: 10, + }, }, }, - }, - { - range: { - numericField: { - lte: 10, + { + range: { + numericField: { + lte: 10, + }, }, }, - }, - { - term: { - keywordField: { - value: 'error', + { + term: { + keywordField: { + value: 'error', + }, }, }, - }, - { - match: { - textField: 'Something went wrong', + { + match: { + textField: 'Something went wrong', + }, }, - }, - { - match_phrase: { - textField: 'Something went wrong', + { + match_phrase: { + textField: 'Something went wrong', + }, }, - }, - ], - must_not: [ - { - term: { - keywordField: { - value: 'error', + ], + must_not: [ + { + term: { + keywordField: { + value: 'error', + }, }, }, - }, - { - match: { - textField: 'Something went wrong', + { + match: { + textField: 'Something went wrong', + }, }, - }, - { - match_phrase: { - textField: 'Something went wrong', + { + match_phrase: { + textField: 'Something went wrong', + }, }, - }, - ], + ], + }, }, }, }, }, }, - }, - runtime_mappings: { - runtime_field: { - type: 'keyword', - script: { - lang: 'painless', - source: 'emit("a runtime value")', + runtime_mappings: { + runtime_field: { + type: 'keyword', + script: { + lang: 'painless', + source: 'emit("a runtime value")', + }, }, }, + size: 0, }, - size: 0, - }, + }); }); }); }); From b15c6b26ec922c6a1072cda2456a37408b170208 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Fri, 18 Jun 2021 15:22:25 +0100 Subject: [PATCH 03/13] Add UI warning --- .../components/expression_editor/editor.tsx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/editor.tsx b/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/editor.tsx index ef533f63dc175..e88099805c997 100644 --- a/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/editor.tsx +++ b/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/editor.tsx @@ -255,6 +255,12 @@ export const Editor: React.FC< setHasSetDefaults(true); }); + const shouldShowGroupByOptimizationWarning = useMemo(() => { + const hasSetGroupBy = alertParams.groupBy && alertParams.groupBy.length > 0; + const hasSetOptimizableThresholdComparator = alertParams.count.comparator === Comparator.GT; + return hasSetGroupBy && !hasSetOptimizableThresholdComparator; + }, [alertParams]); + // Wait until the alert param defaults have been set if (!hasSetDefaults) return null; @@ -299,6 +305,17 @@ export const Editor: React.FC< {alertParams.criteria && isRatioAlert(alertParams.criteria) && criteriaComponent} + {shouldShowGroupByOptimizationWarning && ( + <> + + + {i18n.translate('xpack.infra.logs.alertFlyout.groupByOptimizationWarning', { + defaultMessage: `When setting a group by we highly recommend using the ${Comparator.GT} comparator for your threshold. This can lead to significant performance improvements.`, + })} + + + )} + ); From 1f76eea3ff7aa9ae2a2b5bff882b7654578e658f Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Fri, 18 Jun 2021 15:25:51 +0100 Subject: [PATCH 04/13] Check for property first --- .../log_threshold/components/expression_editor/editor.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/editor.tsx b/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/editor.tsx index e88099805c997..80fd1600fa0b3 100644 --- a/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/editor.tsx +++ b/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/editor.tsx @@ -257,7 +257,8 @@ export const Editor: React.FC< const shouldShowGroupByOptimizationWarning = useMemo(() => { const hasSetGroupBy = alertParams.groupBy && alertParams.groupBy.length > 0; - const hasSetOptimizableThresholdComparator = alertParams.count.comparator === Comparator.GT; + const hasSetOptimizableThresholdComparator = + alertParams.count && alertParams.count.comparator === Comparator.GT; return hasSetGroupBy && !hasSetOptimizableThresholdComparator; }, [alertParams]); From b19700f9b7aa29ddb850356cf5d1286dbecab1e3 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Mon, 21 Jun 2021 11:57:20 +0100 Subject: [PATCH 05/13] Fix syntax mistake --- .../log_threshold/components/expression_editor/editor.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/editor.tsx b/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/editor.tsx index 80fd1600fa0b3..5e90b373c0b52 100644 --- a/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/editor.tsx +++ b/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/editor.tsx @@ -311,7 +311,11 @@ export const Editor: React.FC< {i18n.translate('xpack.infra.logs.alertFlyout.groupByOptimizationWarning', { - defaultMessage: `When setting a group by we highly recommend using the ${Comparator.GT} comparator for your threshold. This can lead to significant performance improvements.`, + defaultMessage: + 'When setting a group by we highly recommend using the {comparator} comparator for your threshold. This can lead to significant performance improvements.', + values: { + comparator: Comparator.GT, + }, })} From c9b9fd4b83a1fbebf5b3584e791149cbd3391886 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Wed, 23 Jun 2021 10:10:04 +0100 Subject: [PATCH 06/13] Update x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/editor.tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Felix Stürmer --- .../log_threshold/components/expression_editor/editor.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/editor.tsx b/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/editor.tsx index 5e90b373c0b52..54f8987eb44f2 100644 --- a/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/editor.tsx +++ b/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/editor.tsx @@ -312,7 +312,7 @@ export const Editor: React.FC< {i18n.translate('xpack.infra.logs.alertFlyout.groupByOptimizationWarning', { defaultMessage: - 'When setting a group by we highly recommend using the {comparator} comparator for your threshold. This can lead to significant performance improvements.', + 'When setting a "group by" we highly recommend using the "{comparator}" comparator for your threshold. This can lead to significant performance improvements.', values: { comparator: Comparator.GT, }, From 12bb8642b58a7dbda255efc315220b1f2d9c65b2 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Wed, 23 Jun 2021 13:10:36 +0100 Subject: [PATCH 07/13] Optimise for GT_OR_EQ comparator --- .../http_api/log_alerts/chart_preview_data.ts | 11 ++++++--- .../criterion_preview_chart.tsx | 2 ++ .../log_threshold/log_threshold_executor.ts | 23 +++++++++++++++---- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/infra/common/http_api/log_alerts/chart_preview_data.ts b/x-pack/plugins/infra/common/http_api/log_alerts/chart_preview_data.ts index 310a8b65577c6..5f488dd532285 100644 --- a/x-pack/plugins/infra/common/http_api/log_alerts/chart_preview_data.ts +++ b/x-pack/plugins/infra/common/http_api/log_alerts/chart_preview_data.ts @@ -59,9 +59,14 @@ export type GetLogAlertsChartPreviewDataSuccessResponsePayload = rt.TypeOf< export const getLogAlertsChartPreviewDataAlertParamsSubsetRT: any = rt.intersection([ rt.type({ criteria: countCriteriaRT, - count: rt.type({ - comparator: ThresholdRT.props.comparator, - }), + count: rt.intersection([ + rt.type({ + comparator: ThresholdRT.props.comparator, + }), + rt.partial({ + value: ThresholdRT.props.value, + }), + ]), timeUnit: timeUnitRT, timeSize: timeSizeRT, }), diff --git a/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/criterion_preview_chart.tsx b/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/criterion_preview_chart.tsx index 701a6567f58df..4fa96ea6828d4 100644 --- a/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/criterion_preview_chart.tsx +++ b/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/criterion_preview_chart.tsx @@ -70,6 +70,7 @@ export const CriterionPreview: React.FC = ({ criteria, count: { comparator: alertParams.count.comparator, + value: alertParams.count.value, }, timeSize: alertParams.timeSize, timeUnit: alertParams.timeUnit, @@ -86,6 +87,7 @@ export const CriterionPreview: React.FC = ({ alertParams.timeUnit, alertParams.groupBy, alertParams.count.comparator, + alertParams.count.value, chartCriterion, ]); diff --git a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts index 3d2d3b4a3e20a..da23f60b8be7d 100644 --- a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts +++ b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts @@ -452,7 +452,10 @@ export const buildFiltersFromCriteria = ( export const getGroupedESQuery = ( params: Pick & { criteria: CountCriteria; - count: Pick; + count: { + comparator: AlertParams['count']['comparator']; + value?: AlertParams['count']['value']; + }; }, timestampField: string, index: string, @@ -480,9 +483,21 @@ export const getGroupedESQuery = ( timestampField ); - const isOptimizableComparator = (selectedComparator: AlertParams['count']['comparator']) => { - const optimizableThresholdComparators = [Comparator.GT]; - return optimizableThresholdComparators.includes(selectedComparator); + const isOptimizableComparator = ( + selectedComparator: AlertParams['count']['comparator'], + selectedValue?: AlertParams['count']['value'] + ) => { + if (selectedComparator === Comparator.GT) { + return true; + } else if ( + typeof selectedValue === 'number' && + selectedComparator === Comparator.GT_OR_EQ && + selectedValue > 0 + ) { + return true; + } else { + return false; + } }; if (isOptimizableComparator(comparator)) { From 15f578388feae162c857f16a20e119d5494a8e9e Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Wed, 23 Jun 2021 13:48:23 +0100 Subject: [PATCH 08/13] Make types a little cleaner / less repetitive --- .../alerting/logs/log_threshold/types.ts | 74 ++++++++----------- 1 file changed, 31 insertions(+), 43 deletions(-) diff --git a/x-pack/plugins/infra/common/alerting/logs/log_threshold/types.ts b/x-pack/plugins/infra/common/alerting/logs/log_threshold/types.ts index 55c450ac63063..1e2d3b8200fd5 100644 --- a/x-pack/plugins/infra/common/alerting/logs/log_threshold/types.ts +++ b/x-pack/plugins/infra/common/alerting/logs/log_threshold/types.ts @@ -240,24 +240,36 @@ const chartPreviewHistogramBucket = rt.type({ doc_count: rt.number, }); +const ChartPreviewBucketsRT = rt.partial({ + histogramBuckets: rt.type({ + buckets: rt.array(chartPreviewHistogramBucket), + }), +}); + // ES query responses // +const hitsRT = rt.type({ + total: rt.type({ + value: rt.number, + }), +}); + +const bucketFieldsRT = rt.type({ + key: rt.record(rt.string, rt.string), + doc_count: rt.number, +}); + +const afterKeyRT = rt.partial({ + after_key: rt.record(rt.string, rt.string), +}); + export const UngroupedSearchQueryResponseRT = rt.intersection([ commonSearchSuccessResponseFieldsRT, rt.intersection([ rt.type({ - hits: rt.type({ - total: rt.type({ - value: rt.number, - }), - }), + hits: hitsRT, }), - // Chart preview buckets rt.partial({ - aggregations: rt.type({ - histogramBuckets: rt.type({ - buckets: rt.array(chartPreviewHistogramBucket), - }), - }), + aggregations: ChartPreviewBucketsRT, }), ]), ]); @@ -272,32 +284,20 @@ export const UnoptimizedGroupedSearchQueryResponseRT = rt.intersection([ rt.type({ buckets: rt.array( rt.type({ - key: rt.record(rt.string, rt.string), - doc_count: rt.number, + ...bucketFieldsRT.props, filtered_results: rt.intersection([ rt.type({ doc_count: rt.number, }), - // Chart preview buckets - rt.partial({ - histogramBuckets: rt.type({ - buckets: rt.array(chartPreviewHistogramBucket), - }), - }), + ChartPreviewBucketsRT, ]), }) ), }), - rt.partial({ - after_key: rt.record(rt.string, rt.string), - }), + afterKeyRT, ]), }), - hits: rt.type({ - total: rt.type({ - value: rt.number, - }), - }), + hits: hitsRT, }), ]); @@ -314,28 +314,16 @@ export const OptimizedGroupedSearchQueryResponseRT = rt.intersection([ buckets: rt.array( rt.intersection([ rt.type({ - key: rt.record(rt.string, rt.string), - doc_count: rt.number, - }), - // Chart preview buckets - rt.partial({ - histogramBuckets: rt.type({ - buckets: rt.array(chartPreviewHistogramBucket), - }), + ...bucketFieldsRT.props, }), + ChartPreviewBucketsRT, ]) ), }), - rt.partial({ - after_key: rt.record(rt.string, rt.string), - }), + afterKeyRT, ]), }), - hits: rt.type({ - total: rt.type({ - value: rt.number, - }), - }), + hits: hitsRT, }), ]); From 702582acbd9616ba15886f744421e2087543f2a1 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Wed, 23 Jun 2021 16:10:30 +0100 Subject: [PATCH 09/13] Use predicate function for clarity --- .../alerting/log_threshold/log_threshold_chart_preview.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_chart_preview.ts b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_chart_preview.ts index bdf9e7fa95ed3..d162200ac8de7 100644 --- a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_chart_preview.ts +++ b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_chart_preview.ts @@ -98,8 +98,10 @@ const addHistogramAggregationToQuery = ( }; if (isGrouped) { - // Optimized - if (!query.body.aggregations.groups.aggregations?.filtered_results) { + const isOptimizedQuery = (groupedQuery: any) => + !groupedQuery.body.aggregations.groups.aggregations?.filtered_results ? true : false; + + if (isOptimizedQuery(query)) { query.body.aggregations.groups.aggregations = { ...query.body.aggregations.groups.aggregations, ...histogramAggregation, From 05349da4ccda6871a91faf9951b893913ce21618 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Wed, 23 Jun 2021 16:24:59 +0100 Subject: [PATCH 10/13] Use the same function for determing optizable threshold between executor and editor --- .../alerting/logs/log_threshold/types.ts | 17 ++++++++++++++ .../components/expression_editor/editor.tsx | 9 +++++--- .../log_threshold/log_threshold_executor.ts | 22 +++---------------- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/x-pack/plugins/infra/common/alerting/logs/log_threshold/types.ts b/x-pack/plugins/infra/common/alerting/logs/log_threshold/types.ts index 1e2d3b8200fd5..b3576a2ff8633 100644 --- a/x-pack/plugins/infra/common/alerting/logs/log_threshold/types.ts +++ b/x-pack/plugins/infra/common/alerting/logs/log_threshold/types.ts @@ -344,3 +344,20 @@ export const isOptimizedGroupedSearchQueryResponse = ( const result = response[0]; return result && !result.hasOwnProperty('filtered_results'); }; + +export const isOptimizableGroupedThreshold = ( + selectedComparator: AlertParams['count']['comparator'], + selectedValue?: AlertParams['count']['value'] +) => { + if (selectedComparator === Comparator.GT) { + return true; + } else if ( + typeof selectedValue === 'number' && + selectedComparator === Comparator.GT_OR_EQ && + selectedValue > 0 + ) { + return true; + } else { + return false; + } +}; diff --git a/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/editor.tsx b/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/editor.tsx index 5e90b373c0b52..e518c338b8016 100644 --- a/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/editor.tsx +++ b/x-pack/plugins/infra/public/alerting/log_threshold/components/expression_editor/editor.tsx @@ -23,6 +23,7 @@ import { PartialRatioAlertParams, ThresholdType, timeUnitRT, + isOptimizableGroupedThreshold, } from '../../../../../common/alerting/logs/log_threshold/types'; import { decodeOrThrow } from '../../../../../common/runtime_types'; import { ObjectEntries } from '../../../../../common/utility_types'; @@ -257,9 +258,11 @@ export const Editor: React.FC< const shouldShowGroupByOptimizationWarning = useMemo(() => { const hasSetGroupBy = alertParams.groupBy && alertParams.groupBy.length > 0; - const hasSetOptimizableThresholdComparator = - alertParams.count && alertParams.count.comparator === Comparator.GT; - return hasSetGroupBy && !hasSetOptimizableThresholdComparator; + return ( + hasSetGroupBy && + alertParams.count && + !isOptimizableGroupedThreshold(alertParams.count.comparator, alertParams.count.value) + ); }, [alertParams]); // Wait until the alert param defaults have been set diff --git a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts index da23f60b8be7d..f9d0b5575abfc 100644 --- a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts +++ b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts @@ -37,6 +37,7 @@ import { CountAlertParams, RatioAlertParams, isOptimizedGroupedSearchQueryResponse, + isOptimizableGroupedThreshold, } from '../../../../common/alerting/logs/log_threshold/types'; import { InfraBackendLibs } from '../../infra_types'; import { getIntervalInSeconds } from '../../../utils/get_interval_in_seconds'; @@ -471,7 +472,7 @@ export const getGroupedESQuery = ( const { groupBy, - count: { comparator }, + count: { comparator, value }, } = params; if (!groupBy || !groupBy.length) { @@ -483,24 +484,7 @@ export const getGroupedESQuery = ( timestampField ); - const isOptimizableComparator = ( - selectedComparator: AlertParams['count']['comparator'], - selectedValue?: AlertParams['count']['value'] - ) => { - if (selectedComparator === Comparator.GT) { - return true; - } else if ( - typeof selectedValue === 'number' && - selectedComparator === Comparator.GT_OR_EQ && - selectedValue > 0 - ) { - return true; - } else { - return false; - } - }; - - if (isOptimizableComparator(comparator)) { + if (isOptimizableGroupedThreshold(comparator, value)) { const aggregations = { groups: { composite: { From a5a2630fc5bce6618fd3f9afe93a02f917d6f3fb Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Thu, 24 Jun 2021 00:31:42 +0100 Subject: [PATCH 11/13] Cut down on executor unit test repetition --- .../log_threshold_executor.test.ts | 334 ++++-------------- 1 file changed, 76 insertions(+), 258 deletions(-) diff --git a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.test.ts b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.test.ts index 642f6755ff56f..55c66f0aabbfb 100644 --- a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.test.ts +++ b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.test.ts @@ -58,6 +58,74 @@ const negativeCriteria: Criterion[] = [ { ...textField, comparator: Comparator.NOT_MATCH_PHRASE }, ]; +const expectedPositiveFilterClauses = [ + { + range: { + numericField: { + gt: 10, + }, + }, + }, + { + range: { + numericField: { + gte: 10, + }, + }, + }, + { + range: { + numericField: { + lt: 10, + }, + }, + }, + { + range: { + numericField: { + lte: 10, + }, + }, + }, + { + term: { + keywordField: { + value: 'error', + }, + }, + }, + { + match: { + textField: 'Something went wrong', + }, + }, + { + match_phrase: { + textField: 'Something went wrong', + }, + }, +]; + +const expectedNegativeFilterClauses = [ + { + term: { + keywordField: { + value: 'error', + }, + }, + }, + { + match: { + textField: 'Something went wrong', + }, + }, + { + match_phrase: { + textField: 'Something went wrong', + }, + }, +]; + const baseAlertParams: Pick = { count: { comparator: Comparator.GT, @@ -102,53 +170,7 @@ describe('Log threshold executor', () => { criteria: positiveCriteria, }; const filters = buildFiltersFromCriteria(alertParams, TIMESTAMP_FIELD); - expect(filters.mustFilters).toEqual([ - { - range: { - numericField: { - gt: 10, - }, - }, - }, - { - range: { - numericField: { - gte: 10, - }, - }, - }, - { - range: { - numericField: { - lt: 10, - }, - }, - }, - { - range: { - numericField: { - lte: 10, - }, - }, - }, - { - term: { - keywordField: { - value: 'error', - }, - }, - }, - { - match: { - textField: 'Something went wrong', - }, - }, - { - match_phrase: { - textField: 'Something went wrong', - }, - }, - ]); + expect(filters.mustFilters).toEqual(expectedPositiveFilterClauses); }); test('Handles negative criteria', () => { @@ -158,25 +180,7 @@ describe('Log threshold executor', () => { }; const filters = buildFiltersFromCriteria(alertParams, TIMESTAMP_FIELD); - expect(filters.mustNotFilters).toEqual([ - { - term: { - keywordField: { - value: 'error', - }, - }, - }, - { - match: { - textField: 'Something went wrong', - }, - }, - { - match_phrase: { - textField: 'Something went wrong', - }, - }, - ]); + expect(filters.mustNotFilters).toEqual(expectedNegativeFilterClauses); }); test('Handles time range', () => { @@ -223,71 +227,9 @@ describe('Log threshold executor', () => { }, }, }, - { - range: { - numericField: { - gt: 10, - }, - }, - }, - { - range: { - numericField: { - gte: 10, - }, - }, - }, - { - range: { - numericField: { - lt: 10, - }, - }, - }, - { - range: { - numericField: { - lte: 10, - }, - }, - }, - { - term: { - keywordField: { - value: 'error', - }, - }, - }, - { - match: { - textField: 'Something went wrong', - }, - }, - { - match_phrase: { - textField: 'Something went wrong', - }, - }, - ], - must_not: [ - { - term: { - keywordField: { - value: 'error', - }, - }, - }, - { - match: { - textField: 'Something went wrong', - }, - }, - { - match_phrase: { - textField: 'Something went wrong', - }, - }, + ...expectedPositiveFilterClauses, ], + must_not: [...expectedNegativeFilterClauses], }, }, runtime_mappings: { @@ -335,71 +277,9 @@ describe('Log threshold executor', () => { }, }, }, - { - range: { - numericField: { - gt: 10, - }, - }, - }, - { - range: { - numericField: { - gte: 10, - }, - }, - }, - { - range: { - numericField: { - lt: 10, - }, - }, - }, - { - range: { - numericField: { - lte: 10, - }, - }, - }, - { - term: { - keywordField: { - value: 'error', - }, - }, - }, - { - match: { - textField: 'Something went wrong', - }, - }, - { - match_phrase: { - textField: 'Something went wrong', - }, - }, - ], - must_not: [ - { - term: { - keywordField: { - value: 'error', - }, - }, - }, - { - match: { - textField: 'Something went wrong', - }, - }, - { - match_phrase: { - textField: 'Something went wrong', - }, - }, + ...expectedPositiveFilterClauses, ], + must_not: [...expectedNegativeFilterClauses], }, }, aggregations: { @@ -498,71 +378,9 @@ describe('Log threshold executor', () => { }, }, }, - { - range: { - numericField: { - gt: 10, - }, - }, - }, - { - range: { - numericField: { - gte: 10, - }, - }, - }, - { - range: { - numericField: { - lt: 10, - }, - }, - }, - { - range: { - numericField: { - lte: 10, - }, - }, - }, - { - term: { - keywordField: { - value: 'error', - }, - }, - }, - { - match: { - textField: 'Something went wrong', - }, - }, - { - match_phrase: { - textField: 'Something went wrong', - }, - }, - ], - must_not: [ - { - term: { - keywordField: { - value: 'error', - }, - }, - }, - { - match: { - textField: 'Something went wrong', - }, - }, - { - match_phrase: { - textField: 'Something went wrong', - }, - }, + ...expectedPositiveFilterClauses, ], + must_not: [...expectedNegativeFilterClauses], }, }, }, From 9f48a7643a896932d54c5be80134a6e719bd5bd0 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Thu, 24 Jun 2021 17:28:21 +0100 Subject: [PATCH 12/13] Update x-pack/plugins/infra/common/alerting/logs/log_threshold/types.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Felix Stürmer --- .../plugins/infra/common/alerting/logs/log_threshold/types.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/x-pack/plugins/infra/common/alerting/logs/log_threshold/types.ts b/x-pack/plugins/infra/common/alerting/logs/log_threshold/types.ts index b3576a2ff8633..41e4b58b16484 100644 --- a/x-pack/plugins/infra/common/alerting/logs/log_threshold/types.ts +++ b/x-pack/plugins/infra/common/alerting/logs/log_threshold/types.ts @@ -313,9 +313,7 @@ export const OptimizedGroupedSearchQueryResponseRT = rt.intersection([ rt.type({ buckets: rt.array( rt.intersection([ - rt.type({ - ...bucketFieldsRT.props, - }), + bucketFieldsRT, ChartPreviewBucketsRT, ]) ), From 22d5945785c914e2d8ec87121311508a1d94e932 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Date: Thu, 24 Jun 2021 17:40:02 +0100 Subject: [PATCH 13/13] Remove function to avoid extra any --- .../infra/common/alerting/logs/log_threshold/types.ts | 7 +------ .../alerting/log_threshold/log_threshold_chart_preview.ts | 5 ++--- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/infra/common/alerting/logs/log_threshold/types.ts b/x-pack/plugins/infra/common/alerting/logs/log_threshold/types.ts index 41e4b58b16484..6da0bb58e4e85 100644 --- a/x-pack/plugins/infra/common/alerting/logs/log_threshold/types.ts +++ b/x-pack/plugins/infra/common/alerting/logs/log_threshold/types.ts @@ -311,12 +311,7 @@ export const OptimizedGroupedSearchQueryResponseRT = rt.intersection([ aggregations: rt.type({ groups: rt.intersection([ rt.type({ - buckets: rt.array( - rt.intersection([ - bucketFieldsRT, - ChartPreviewBucketsRT, - ]) - ), + buckets: rt.array(rt.intersection([bucketFieldsRT, ChartPreviewBucketsRT])), }), afterKeyRT, ]), diff --git a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_chart_preview.ts b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_chart_preview.ts index d162200ac8de7..7bf2cb5ea3394 100644 --- a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_chart_preview.ts +++ b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_chart_preview.ts @@ -98,10 +98,9 @@ const addHistogramAggregationToQuery = ( }; if (isGrouped) { - const isOptimizedQuery = (groupedQuery: any) => - !groupedQuery.body.aggregations.groups.aggregations?.filtered_results ? true : false; + const isOptimizedQuery = !query.body.aggregations.groups.aggregations?.filtered_results; - if (isOptimizedQuery(query)) { + if (isOptimizedQuery) { query.body.aggregations.groups.aggregations = { ...query.body.aggregations.groups.aggregations, ...histogramAggregation,