[Metrics UI] Display Too Many Buckets error when previewing Inventory Alerts (#70508)

* [Metrics UI] Display Too Many Buckets error when previewing Inventory Alerts

* Fix typecheck
This commit is contained in:
Zacqary Adam Xeper 2020-07-07 10:05:50 -05:00 committed by GitHub
parent e7c54d3684
commit 5e869b0e77
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 103 additions and 74 deletions

View file

@ -5,6 +5,10 @@
*/ */
import { mapValues, last, first } from 'lodash'; import { mapValues, last, first } from 'lodash';
import moment from 'moment'; import moment from 'moment';
import {
isTooManyBucketsPreviewException,
TOO_MANY_BUCKETS_PREVIEW_EXCEPTION,
} from '../../../../common/alerting/metrics';
import { import {
InfraDatabaseSearchResponse, InfraDatabaseSearchResponse,
CallWithRequestParams, CallWithRequestParams,
@ -57,18 +61,23 @@ export const evaluateCondition = async (
const comparisonFunction = comparatorMap[comparator]; const comparisonFunction = comparatorMap[comparator];
return mapValues(currentValues, (value) => ({ const result = mapValues(currentValues, (value) => {
if (isTooManyBucketsPreviewException(value)) throw value;
return {
...condition, ...condition,
shouldFire: shouldFire:
value !== undefined && value !== undefined &&
value !== null && value !== null &&
(Array.isArray(value) (Array.isArray(value)
? value.map((v) => comparisonFunction(Number(v), threshold)) ? value.map((v) => comparisonFunction(Number(v), threshold))
: comparisonFunction(value, threshold)), : comparisonFunction(value as number, threshold)),
isNoData: value === null, isNoData: value === null,
isError: value === undefined, isError: value === undefined,
currentValue: getCurrentValue(value), currentValue: getCurrentValue(value),
})); };
}) as unknown; // Typescript doesn't seem to know what `throw` is doing
return result as Record<string, ConditionResult>;
}; };
const getCurrentValue: (value: any) => number = (value) => { const getCurrentValue: (value: any) => number = (value) => {
@ -99,7 +108,7 @@ const getData = async (
timerange, timerange,
includeTimeseries: Boolean(timerange.lookbackSize), includeTimeseries: Boolean(timerange.lookbackSize),
}; };
try {
const { nodes } = await snapshot.getNodes(esClient, options); const { nodes } = await snapshot.getNodes(esClient, options);
return nodes.reduce((acc, n) => { return nodes.reduce((acc, n) => {
@ -114,6 +123,21 @@ const getData = async (
} }
return acc; return acc;
}, {} as Record<string, number | Array<number | string | null | undefined> | undefined | null>); }, {} as Record<string, number | Array<number | string | null | undefined> | undefined | null>);
} catch (e) {
if (timerange.lookbackSize) {
// This code should only ever be reached when previewing the alert, not executing it
const causedByType = e.body?.error?.caused_by?.type;
if (causedByType === 'too_many_buckets_exception') {
return {
'*': {
[TOO_MANY_BUCKETS_PREVIEW_EXCEPTION]: true,
maxBuckets: e.body.error.caused_by.max_buckets,
},
};
}
}
return { '*': undefined };
}
}; };
const comparatorMap = { const comparatorMap = {

View file

@ -6,6 +6,10 @@
import { Unit } from '@elastic/datemath'; import { Unit } from '@elastic/datemath';
import { first } from 'lodash'; import { first } from 'lodash';
import { InventoryMetricConditions } from './types'; import { InventoryMetricConditions } from './types';
import {
TOO_MANY_BUCKETS_PREVIEW_EXCEPTION,
isTooManyBucketsPreviewException,
} from '../../../../common/alerting/metrics';
import { ILegacyScopedClusterClient } from '../../../../../../../src/core/server'; import { ILegacyScopedClusterClient } from '../../../../../../../src/core/server';
import { InfraSource } from '../../../../common/http_api/source_api'; import { InfraSource } from '../../../../common/http_api/source_api';
import { getIntervalInSeconds } from '../../../utils/get_interval_in_seconds'; import { getIntervalInSeconds } from '../../../utils/get_interval_in_seconds';
@ -46,7 +50,7 @@ export const previewInventoryMetricThresholdAlert = async ({
const alertIntervalInSeconds = getIntervalInSeconds(alertInterval); const alertIntervalInSeconds = getIntervalInSeconds(alertInterval);
const alertResultsPerExecution = alertIntervalInSeconds / bucketIntervalInSeconds; const alertResultsPerExecution = alertIntervalInSeconds / bucketIntervalInSeconds;
try {
const results = await Promise.all( const results = await Promise.all(
criteria.map((c) => criteria.map((c) =>
evaluateCondition(c, nodeType, config, callCluster, filterQuery, lookbackSize) evaluateCondition(c, nodeType, config, callCluster, filterQuery, lookbackSize)
@ -80,4 +84,9 @@ export const previewInventoryMetricThresholdAlert = async ({
}); });
return previewResults; return previewResults;
} catch (e) {
if (!isTooManyBucketsPreviewException(e)) throw e;
const { maxBuckets } = e;
throw new Error(`${TOO_MANY_BUCKETS_PREVIEW_EXCEPTION}:${maxBuckets}`);
}
}; };

View file

@ -6,7 +6,6 @@
import { mapValues, first, last, isNaN } from 'lodash'; import { mapValues, first, last, isNaN } from 'lodash';
import { import {
TooManyBucketsPreviewExceptionMetadata,
isTooManyBucketsPreviewException, isTooManyBucketsPreviewException,
TOO_MANY_BUCKETS_PREVIEW_EXCEPTION, TOO_MANY_BUCKETS_PREVIEW_EXCEPTION,
} from '../../../../../common/alerting/metrics'; } from '../../../../../common/alerting/metrics';
@ -58,9 +57,7 @@ export const evaluateAlert = (
); );
const { threshold, comparator } = criterion; const { threshold, comparator } = criterion;
const comparisonFunction = comparatorMap[comparator]; const comparisonFunction = comparatorMap[comparator];
return mapValues( return mapValues(currentValues, (values: number | number[] | null) => {
currentValues,
(values: number | number[] | null | TooManyBucketsPreviewExceptionMetadata) => {
if (isTooManyBucketsPreviewException(values)) throw values; if (isTooManyBucketsPreviewException(values)) throw values;
return { return {
...criterion, ...criterion,
@ -72,8 +69,7 @@ export const evaluateAlert = (
isNoData: values === null, isNoData: values === null,
isError: isNaN(values), isError: isNaN(values),
}; };
} });
);
}) })
); );
}; };