mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Metrics UI] Add context.reason and alertOnNoData to Inventory alerts (#70260)
This commit is contained in:
parent
893525c74c
commit
0047eeded6
14 changed files with 352 additions and 264 deletions
|
@ -6,6 +6,7 @@
|
|||
|
||||
import React, { useMemo } from 'react';
|
||||
import { EuiFlexItem } from '@elastic/eui';
|
||||
import { toMetricOpt } from '../../../snapshot_metric_i18n';
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import { WaffleSortControls } from '../../../../public/pages/metrics/inventory_view/components/waffle/waffle_sort_controls';
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
|
@ -16,7 +17,6 @@ import { WaffleMetricControls } from '../../../../public/pages/metrics/inventory
|
|||
import { WaffleGroupByControls } from '../../../../public/pages/metrics/inventory_view/components/waffle/waffle_group_by_controls';
|
||||
import {
|
||||
toGroupByOpt,
|
||||
toMetricOpt,
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
} from '../../../../public/pages/metrics/inventory_view/components/toolbars/toolbar_wrapper';
|
||||
import { SnapshotMetricType } from '../../types';
|
||||
|
|
208
x-pack/plugins/infra/common/snapshot_metric_i18n.ts
Normal file
208
x-pack/plugins/infra/common/snapshot_metric_i18n.ts
Normal file
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { SnapshotMetricType } from './inventory_models/types';
|
||||
|
||||
const Translations = {
|
||||
CPUUsage: i18n.translate('xpack.infra.waffle.metricOptions.cpuUsageText', {
|
||||
defaultMessage: 'CPU usage',
|
||||
}),
|
||||
|
||||
MemoryUsage: i18n.translate('xpack.infra.waffle.metricOptions.memoryUsageText', {
|
||||
defaultMessage: 'Memory usage',
|
||||
}),
|
||||
|
||||
InboundTraffic: i18n.translate('xpack.infra.waffle.metricOptions.inboundTrafficText', {
|
||||
defaultMessage: 'Inbound traffic',
|
||||
}),
|
||||
|
||||
OutboundTraffic: i18n.translate('xpack.infra.waffle.metricOptions.outboundTrafficText', {
|
||||
defaultMessage: 'Outbound traffic',
|
||||
}),
|
||||
|
||||
LogRate: i18n.translate('xpack.infra.waffle.metricOptions.hostLogRateText', {
|
||||
defaultMessage: 'Log rate',
|
||||
}),
|
||||
|
||||
Load: i18n.translate('xpack.infra.waffle.metricOptions.loadText', {
|
||||
defaultMessage: 'Load',
|
||||
}),
|
||||
|
||||
Count: i18n.translate('xpack.infra.waffle.metricOptions.countText', {
|
||||
defaultMessage: 'Count',
|
||||
}),
|
||||
DiskIOReadBytes: i18n.translate('xpack.infra.waffle.metricOptions.diskIOReadBytes', {
|
||||
defaultMessage: 'Disk Reads',
|
||||
}),
|
||||
DiskIOWriteBytes: i18n.translate('xpack.infra.waffle.metricOptions.diskIOWriteBytes', {
|
||||
defaultMessage: 'Disk Writes',
|
||||
}),
|
||||
s3BucketSize: i18n.translate('xpack.infra.waffle.metricOptions.s3BucketSize', {
|
||||
defaultMessage: 'Bucket Size',
|
||||
}),
|
||||
s3TotalRequests: i18n.translate('xpack.infra.waffle.metricOptions.s3TotalRequests', {
|
||||
defaultMessage: 'Total Requests',
|
||||
}),
|
||||
s3NumberOfObjects: i18n.translate('xpack.infra.waffle.metricOptions.s3NumberOfObjects', {
|
||||
defaultMessage: 'Number of Objects',
|
||||
}),
|
||||
s3DownloadBytes: i18n.translate('xpack.infra.waffle.metricOptions.s3DownloadBytes', {
|
||||
defaultMessage: 'Downloads (Bytes)',
|
||||
}),
|
||||
s3UploadBytes: i18n.translate('xpack.infra.waffle.metricOptions.s3UploadBytes', {
|
||||
defaultMessage: 'Uploads (Bytes)',
|
||||
}),
|
||||
rdsConnections: i18n.translate('xpack.infra.waffle.metricOptions.rdsConnections', {
|
||||
defaultMessage: 'Connections',
|
||||
}),
|
||||
rdsQueriesExecuted: i18n.translate('xpack.infra.waffle.metricOptions.rdsQueriesExecuted', {
|
||||
defaultMessage: 'Queries Executed',
|
||||
}),
|
||||
rdsActiveTransactions: i18n.translate('xpack.infra.waffle.metricOptions.rdsActiveTransactions', {
|
||||
defaultMessage: 'Active Transactions',
|
||||
}),
|
||||
rdsLatency: i18n.translate('xpack.infra.waffle.metricOptions.rdsLatency', {
|
||||
defaultMessage: 'Latency',
|
||||
}),
|
||||
sqsMessagesVisible: i18n.translate('xpack.infra.waffle.metricOptions.sqsMessagesVisible', {
|
||||
defaultMessage: 'Messages Available',
|
||||
}),
|
||||
sqsMessagesDelayed: i18n.translate('xpack.infra.waffle.metricOptions.sqsMessagesDelayed', {
|
||||
defaultMessage: 'Messages Delayed',
|
||||
}),
|
||||
sqsMessagesSent: i18n.translate('xpack.infra.waffle.metricOptions.sqsMessagesSent', {
|
||||
defaultMessage: 'Messages Added',
|
||||
}),
|
||||
sqsMessagesEmpty: i18n.translate('xpack.infra.waffle.metricOptions.sqsMessagesEmpty', {
|
||||
defaultMessage: 'Messages Returned Empty',
|
||||
}),
|
||||
sqsOldestMessage: i18n.translate('xpack.infra.waffle.metricOptions.sqsOldestMessage', {
|
||||
defaultMessage: 'Oldest Message',
|
||||
}),
|
||||
};
|
||||
|
||||
export const toMetricOpt = (
|
||||
metric: SnapshotMetricType
|
||||
): { text: string; value: SnapshotMetricType } | undefined => {
|
||||
switch (metric) {
|
||||
case 'cpu':
|
||||
return {
|
||||
text: Translations.CPUUsage,
|
||||
value: 'cpu',
|
||||
};
|
||||
case 'memory':
|
||||
return {
|
||||
text: Translations.MemoryUsage,
|
||||
value: 'memory',
|
||||
};
|
||||
case 'rx':
|
||||
return {
|
||||
text: Translations.InboundTraffic,
|
||||
value: 'rx',
|
||||
};
|
||||
case 'tx':
|
||||
return {
|
||||
text: Translations.OutboundTraffic,
|
||||
value: 'tx',
|
||||
};
|
||||
case 'logRate':
|
||||
return {
|
||||
text: Translations.LogRate,
|
||||
value: 'logRate',
|
||||
};
|
||||
case 'load':
|
||||
return {
|
||||
text: Translations.Load,
|
||||
value: 'load',
|
||||
};
|
||||
|
||||
case 'count':
|
||||
return {
|
||||
text: Translations.Count,
|
||||
value: 'count',
|
||||
};
|
||||
case 'diskIOReadBytes':
|
||||
return {
|
||||
text: Translations.DiskIOReadBytes,
|
||||
value: 'diskIOReadBytes',
|
||||
};
|
||||
case 'diskIOWriteBytes':
|
||||
return {
|
||||
text: Translations.DiskIOWriteBytes,
|
||||
value: 'diskIOWriteBytes',
|
||||
};
|
||||
case 's3BucketSize':
|
||||
return {
|
||||
text: Translations.s3BucketSize,
|
||||
value: 's3BucketSize',
|
||||
};
|
||||
case 's3TotalRequests':
|
||||
return {
|
||||
text: Translations.s3TotalRequests,
|
||||
value: 's3TotalRequests',
|
||||
};
|
||||
case 's3NumberOfObjects':
|
||||
return {
|
||||
text: Translations.s3NumberOfObjects,
|
||||
value: 's3NumberOfObjects',
|
||||
};
|
||||
case 's3DownloadBytes':
|
||||
return {
|
||||
text: Translations.s3DownloadBytes,
|
||||
value: 's3DownloadBytes',
|
||||
};
|
||||
case 's3UploadBytes':
|
||||
return {
|
||||
text: Translations.s3UploadBytes,
|
||||
value: 's3UploadBytes',
|
||||
};
|
||||
case 'rdsConnections':
|
||||
return {
|
||||
text: Translations.rdsConnections,
|
||||
value: 'rdsConnections',
|
||||
};
|
||||
case 'rdsQueriesExecuted':
|
||||
return {
|
||||
text: Translations.rdsQueriesExecuted,
|
||||
value: 'rdsQueriesExecuted',
|
||||
};
|
||||
case 'rdsActiveTransactions':
|
||||
return {
|
||||
text: Translations.rdsActiveTransactions,
|
||||
value: 'rdsActiveTransactions',
|
||||
};
|
||||
case 'rdsLatency':
|
||||
return {
|
||||
text: Translations.rdsLatency,
|
||||
value: 'rdsLatency',
|
||||
};
|
||||
case 'sqsMessagesVisible':
|
||||
return {
|
||||
text: Translations.sqsMessagesVisible,
|
||||
value: 'sqsMessagesVisible',
|
||||
};
|
||||
case 'sqsMessagesDelayed':
|
||||
return {
|
||||
text: Translations.sqsMessagesDelayed,
|
||||
value: 'sqsMessagesDelayed',
|
||||
};
|
||||
case 'sqsMessagesSent':
|
||||
return {
|
||||
text: Translations.sqsMessagesSent,
|
||||
value: 'sqsMessagesSent',
|
||||
};
|
||||
case 'sqsMessagesEmpty':
|
||||
return {
|
||||
text: Translations.sqsMessagesEmpty,
|
||||
value: 'sqsMessagesEmpty',
|
||||
};
|
||||
case 'sqsOldestMessage':
|
||||
return {
|
||||
text: Translations.sqsOldestMessage,
|
||||
value: 'sqsOldestMessage',
|
||||
};
|
||||
}
|
||||
};
|
|
@ -16,9 +16,13 @@ import {
|
|||
EuiFormRow,
|
||||
EuiButtonEmpty,
|
||||
EuiFieldSearch,
|
||||
EuiCheckbox,
|
||||
EuiToolTip,
|
||||
EuiIcon,
|
||||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { toMetricOpt } from '../../../../common/snapshot_metric_i18n';
|
||||
import { AlertPreview } from '../../common';
|
||||
import { METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID } from '../../../../common/alerting/metrics';
|
||||
import {
|
||||
|
@ -38,7 +42,6 @@ import { AlertsContextValue } from '../../../../../triggers_actions_ui/public/ap
|
|||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import { MetricsExplorerKueryBar } from '../../../pages/metrics/metrics_explorer/components/kuery_bar';
|
||||
import { useSourceViaHttp } from '../../../containers/source/use_source_via_http';
|
||||
import { toMetricOpt } from '../../../pages/metrics/inventory_view/components/toolbars/toolbar_wrapper';
|
||||
import { sqsMetricTypes } from '../../../../common/inventory_models/aws_sqs/toolbar_items';
|
||||
import { ec2MetricTypes } from '../../../../common/inventory_models/aws_ec2/toolbar_items';
|
||||
import { s3MetricTypes } from '../../../../common/inventory_models/aws_s3/toolbar_items';
|
||||
|
@ -73,6 +76,7 @@ interface Props {
|
|||
filterQuery?: string;
|
||||
filterQueryText?: string;
|
||||
sourceId?: string;
|
||||
alertOnNoData?: boolean;
|
||||
};
|
||||
alertInterval: string;
|
||||
alertsContext: AlertsContextValue<AlertContextMeta>;
|
||||
|
@ -306,6 +310,28 @@ export const Expressions: React.FC<Props> = (props) => {
|
|||
</EuiButtonEmpty>
|
||||
</div>
|
||||
|
||||
<EuiSpacer size={'m'} />
|
||||
<EuiCheckbox
|
||||
id="metrics-alert-no-data-toggle"
|
||||
label={
|
||||
<>
|
||||
{i18n.translate('xpack.infra.metrics.alertFlyout.alertOnNoData', {
|
||||
defaultMessage: "Alert me if there's no data",
|
||||
})}{' '}
|
||||
<EuiToolTip
|
||||
content={i18n.translate('xpack.infra.metrics.alertFlyout.noDataHelpText', {
|
||||
defaultMessage:
|
||||
'Enable this to trigger the action if the metric(s) do not report any data over the expected time period, or if the alert fails to query Elasticsearch',
|
||||
})}
|
||||
>
|
||||
<EuiIcon type="questionInCircle" color="subdued" />
|
||||
</EuiToolTip>
|
||||
</>
|
||||
}
|
||||
checked={alertParams.alertOnNoData}
|
||||
onChange={(e) => setAlertParams('alertOnNoData', e.target.checked)}
|
||||
/>
|
||||
|
||||
<EuiSpacer size={'m'} />
|
||||
|
||||
<EuiFormRow
|
||||
|
|
|
@ -24,10 +24,10 @@ export function createInventoryMetricAlertType(): AlertTypeModel {
|
|||
defaultActionMessage: i18n.translate(
|
||||
'xpack.infra.metrics.alerting.inventory.threshold.defaultActionMessage',
|
||||
{
|
||||
defaultMessage: `\\{\\{alertName\\}\\} - \\{\\{context.group\\}\\}
|
||||
defaultMessage: `\\{\\{alertName\\}\\} - \\{\\{context.group\\}\\} is in a state of \\{\\{context.alertState\\}\\}
|
||||
|
||||
\\{\\{context.metricOf.condition0\\}\\} has crossed a threshold of \\{\\{context.thresholdOf.condition0\\}\\}
|
||||
Current value is \\{\\{context.valueOf.condition0\\}\\}
|
||||
Reason:
|
||||
\\{\\{context.reason\\}\\}
|
||||
`,
|
||||
}
|
||||
),
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
|
||||
import React from 'react';
|
||||
import { EuiFlexItem } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { SnapshotMetricType } from '../../../../../../common/inventory_models/types';
|
||||
import { fieldToName } from '../../lib/field_to_display_name';
|
||||
import { useSourceContext } from '../../../../../containers/source';
|
||||
import { useWaffleOptionsContext } from '../../hooks/use_waffle_options';
|
||||
|
@ -68,208 +66,7 @@ export const ToolbarWrapper = (props: Props) => {
|
|||
);
|
||||
};
|
||||
|
||||
const ToolbarTranslations = {
|
||||
CPUUsage: i18n.translate('xpack.infra.waffle.metricOptions.cpuUsageText', {
|
||||
defaultMessage: 'CPU usage',
|
||||
}),
|
||||
|
||||
MemoryUsage: i18n.translate('xpack.infra.waffle.metricOptions.memoryUsageText', {
|
||||
defaultMessage: 'Memory usage',
|
||||
}),
|
||||
|
||||
InboundTraffic: i18n.translate('xpack.infra.waffle.metricOptions.inboundTrafficText', {
|
||||
defaultMessage: 'Inbound traffic',
|
||||
}),
|
||||
|
||||
OutboundTraffic: i18n.translate('xpack.infra.waffle.metricOptions.outboundTrafficText', {
|
||||
defaultMessage: 'Outbound traffic',
|
||||
}),
|
||||
|
||||
LogRate: i18n.translate('xpack.infra.waffle.metricOptions.hostLogRateText', {
|
||||
defaultMessage: 'Log rate',
|
||||
}),
|
||||
|
||||
Load: i18n.translate('xpack.infra.waffle.metricOptions.loadText', {
|
||||
defaultMessage: 'Load',
|
||||
}),
|
||||
|
||||
Count: i18n.translate('xpack.infra.waffle.metricOptions.countText', {
|
||||
defaultMessage: 'Count',
|
||||
}),
|
||||
DiskIOReadBytes: i18n.translate('xpack.infra.waffle.metricOptions.diskIOReadBytes', {
|
||||
defaultMessage: 'Disk Reads',
|
||||
}),
|
||||
DiskIOWriteBytes: i18n.translate('xpack.infra.waffle.metricOptions.diskIOWriteBytes', {
|
||||
defaultMessage: 'Disk Writes',
|
||||
}),
|
||||
s3BucketSize: i18n.translate('xpack.infra.waffle.metricOptions.s3BucketSize', {
|
||||
defaultMessage: 'Bucket Size',
|
||||
}),
|
||||
s3TotalRequests: i18n.translate('xpack.infra.waffle.metricOptions.s3TotalRequests', {
|
||||
defaultMessage: 'Total Requests',
|
||||
}),
|
||||
s3NumberOfObjects: i18n.translate('xpack.infra.waffle.metricOptions.s3NumberOfObjects', {
|
||||
defaultMessage: 'Number of Objects',
|
||||
}),
|
||||
s3DownloadBytes: i18n.translate('xpack.infra.waffle.metricOptions.s3DownloadBytes', {
|
||||
defaultMessage: 'Downloads (Bytes)',
|
||||
}),
|
||||
s3UploadBytes: i18n.translate('xpack.infra.waffle.metricOptions.s3UploadBytes', {
|
||||
defaultMessage: 'Uploads (Bytes)',
|
||||
}),
|
||||
rdsConnections: i18n.translate('xpack.infra.waffle.metricOptions.rdsConnections', {
|
||||
defaultMessage: 'Connections',
|
||||
}),
|
||||
rdsQueriesExecuted: i18n.translate('xpack.infra.waffle.metricOptions.rdsQueriesExecuted', {
|
||||
defaultMessage: 'Queries Executed',
|
||||
}),
|
||||
rdsActiveTransactions: i18n.translate('xpack.infra.waffle.metricOptions.rdsActiveTransactions', {
|
||||
defaultMessage: 'Active Transactions',
|
||||
}),
|
||||
rdsLatency: i18n.translate('xpack.infra.waffle.metricOptions.rdsLatency', {
|
||||
defaultMessage: 'Latency',
|
||||
}),
|
||||
sqsMessagesVisible: i18n.translate('xpack.infra.waffle.metricOptions.sqsMessagesVisible', {
|
||||
defaultMessage: 'Messages Available',
|
||||
}),
|
||||
sqsMessagesDelayed: i18n.translate('xpack.infra.waffle.metricOptions.sqsMessagesDelayed', {
|
||||
defaultMessage: 'Messages Delayed',
|
||||
}),
|
||||
sqsMessagesSent: i18n.translate('xpack.infra.waffle.metricOptions.sqsMessagesSent', {
|
||||
defaultMessage: 'Messages Added',
|
||||
}),
|
||||
sqsMessagesEmpty: i18n.translate('xpack.infra.waffle.metricOptions.sqsMessagesEmpty', {
|
||||
defaultMessage: 'Messages Returned Empty',
|
||||
}),
|
||||
sqsOldestMessage: i18n.translate('xpack.infra.waffle.metricOptions.sqsOldestMessage', {
|
||||
defaultMessage: 'Oldest Message',
|
||||
}),
|
||||
};
|
||||
|
||||
export const toGroupByOpt = (field: string) => ({
|
||||
text: fieldToName(field),
|
||||
field,
|
||||
});
|
||||
|
||||
export const toMetricOpt = (
|
||||
metric: SnapshotMetricType
|
||||
): { text: string; value: SnapshotMetricType } | undefined => {
|
||||
switch (metric) {
|
||||
case 'cpu':
|
||||
return {
|
||||
text: ToolbarTranslations.CPUUsage,
|
||||
value: 'cpu',
|
||||
};
|
||||
case 'memory':
|
||||
return {
|
||||
text: ToolbarTranslations.MemoryUsage,
|
||||
value: 'memory',
|
||||
};
|
||||
case 'rx':
|
||||
return {
|
||||
text: ToolbarTranslations.InboundTraffic,
|
||||
value: 'rx',
|
||||
};
|
||||
case 'tx':
|
||||
return {
|
||||
text: ToolbarTranslations.OutboundTraffic,
|
||||
value: 'tx',
|
||||
};
|
||||
case 'logRate':
|
||||
return {
|
||||
text: ToolbarTranslations.LogRate,
|
||||
value: 'logRate',
|
||||
};
|
||||
case 'load':
|
||||
return {
|
||||
text: ToolbarTranslations.Load,
|
||||
value: 'load',
|
||||
};
|
||||
|
||||
case 'count':
|
||||
return {
|
||||
text: ToolbarTranslations.Count,
|
||||
value: 'count',
|
||||
};
|
||||
case 'diskIOReadBytes':
|
||||
return {
|
||||
text: ToolbarTranslations.DiskIOReadBytes,
|
||||
value: 'diskIOReadBytes',
|
||||
};
|
||||
case 'diskIOWriteBytes':
|
||||
return {
|
||||
text: ToolbarTranslations.DiskIOWriteBytes,
|
||||
value: 'diskIOWriteBytes',
|
||||
};
|
||||
case 's3BucketSize':
|
||||
return {
|
||||
text: ToolbarTranslations.s3BucketSize,
|
||||
value: 's3BucketSize',
|
||||
};
|
||||
case 's3TotalRequests':
|
||||
return {
|
||||
text: ToolbarTranslations.s3TotalRequests,
|
||||
value: 's3TotalRequests',
|
||||
};
|
||||
case 's3NumberOfObjects':
|
||||
return {
|
||||
text: ToolbarTranslations.s3NumberOfObjects,
|
||||
value: 's3NumberOfObjects',
|
||||
};
|
||||
case 's3DownloadBytes':
|
||||
return {
|
||||
text: ToolbarTranslations.s3DownloadBytes,
|
||||
value: 's3DownloadBytes',
|
||||
};
|
||||
case 's3UploadBytes':
|
||||
return {
|
||||
text: ToolbarTranslations.s3UploadBytes,
|
||||
value: 's3UploadBytes',
|
||||
};
|
||||
case 'rdsConnections':
|
||||
return {
|
||||
text: ToolbarTranslations.rdsConnections,
|
||||
value: 'rdsConnections',
|
||||
};
|
||||
case 'rdsQueriesExecuted':
|
||||
return {
|
||||
text: ToolbarTranslations.rdsQueriesExecuted,
|
||||
value: 'rdsQueriesExecuted',
|
||||
};
|
||||
case 'rdsActiveTransactions':
|
||||
return {
|
||||
text: ToolbarTranslations.rdsActiveTransactions,
|
||||
value: 'rdsActiveTransactions',
|
||||
};
|
||||
case 'rdsLatency':
|
||||
return {
|
||||
text: ToolbarTranslations.rdsLatency,
|
||||
value: 'rdsLatency',
|
||||
};
|
||||
case 'sqsMessagesVisible':
|
||||
return {
|
||||
text: ToolbarTranslations.sqsMessagesVisible,
|
||||
value: 'sqsMessagesVisible',
|
||||
};
|
||||
case 'sqsMessagesDelayed':
|
||||
return {
|
||||
text: ToolbarTranslations.sqsMessagesDelayed,
|
||||
value: 'sqsMessagesDelayed',
|
||||
};
|
||||
case 'sqsMessagesSent':
|
||||
return {
|
||||
text: ToolbarTranslations.sqsMessagesSent,
|
||||
value: 'sqsMessagesSent',
|
||||
};
|
||||
case 'sqsMessagesEmpty':
|
||||
return {
|
||||
text: ToolbarTranslations.sqsMessagesEmpty,
|
||||
value: 'sqsMessagesEmpty',
|
||||
};
|
||||
case 'sqsOldestMessage':
|
||||
return {
|
||||
text: ToolbarTranslations.sqsOldestMessage,
|
||||
value: 'sqsOldestMessage',
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
33
x-pack/plugins/infra/server/lib/alerting/common/types.ts
Normal file
33
x-pack/plugins/infra/server/lib/alerting/common/types.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export enum Comparator {
|
||||
GT = '>',
|
||||
LT = '<',
|
||||
GT_OR_EQ = '>=',
|
||||
LT_OR_EQ = '<=',
|
||||
BETWEEN = 'between',
|
||||
OUTSIDE_RANGE = 'outside',
|
||||
}
|
||||
|
||||
export enum Aggregators {
|
||||
COUNT = 'count',
|
||||
AVERAGE = 'avg',
|
||||
SUM = 'sum',
|
||||
MIN = 'min',
|
||||
MAX = 'max',
|
||||
RATE = 'rate',
|
||||
CARDINALITY = 'cardinality',
|
||||
P95 = 'p95',
|
||||
P99 = 'p99',
|
||||
}
|
||||
|
||||
export enum AlertStates {
|
||||
OK,
|
||||
ALERT,
|
||||
NO_DATA,
|
||||
ERROR,
|
||||
}
|
|
@ -17,13 +17,12 @@ import { InventoryItemType, SnapshotMetricType } from '../../../../common/invent
|
|||
import { InfraTimerangeInput } from '../../../../common/http_api/snapshot_api';
|
||||
import { InfraSourceConfiguration } from '../../sources';
|
||||
|
||||
interface ConditionResult {
|
||||
type ConditionResult = InventoryMetricConditions & {
|
||||
shouldFire: boolean | boolean[];
|
||||
currentValue?: number | null;
|
||||
metric: string;
|
||||
currentValue: number;
|
||||
isNoData: boolean;
|
||||
isError: boolean;
|
||||
}
|
||||
};
|
||||
|
||||
export const evaluateCondition = async (
|
||||
condition: InventoryMetricConditions,
|
||||
|
@ -59,19 +58,25 @@ export const evaluateCondition = async (
|
|||
const comparisonFunction = comparatorMap[comparator];
|
||||
|
||||
return mapValues(currentValues, (value) => ({
|
||||
...condition,
|
||||
shouldFire:
|
||||
value !== undefined &&
|
||||
value !== null &&
|
||||
(Array.isArray(value)
|
||||
? value.map((v) => comparisonFunction(Number(v), threshold))
|
||||
: comparisonFunction(value, threshold)),
|
||||
metric,
|
||||
isNoData: value === null,
|
||||
isError: value === undefined,
|
||||
...(!Array.isArray(value) ? { currentValue: value } : {}),
|
||||
currentValue: getCurrentValue(value),
|
||||
}));
|
||||
};
|
||||
|
||||
const getCurrentValue: (value: any) => number = (value) => {
|
||||
if (Array.isArray(value)) return getCurrentValue(last(value));
|
||||
if (value !== null) return Number(value);
|
||||
return NaN;
|
||||
};
|
||||
|
||||
const getData = async (
|
||||
callCluster: AlertServices['callCluster'],
|
||||
nodeType: InventoryItemType,
|
||||
|
|
|
@ -5,12 +5,20 @@
|
|||
*/
|
||||
import { first, get } from 'lodash';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import moment from 'moment';
|
||||
import { toMetricOpt } from '../../../../common/snapshot_metric_i18n';
|
||||
import { AlertStates, InventoryMetricConditions } from './types';
|
||||
import { AlertExecutorOptions } from '../../../../../alerts/server';
|
||||
import { InventoryItemType, SnapshotMetricType } from '../../../../common/inventory_models/types';
|
||||
import { InfraBackendLibs } from '../../infra_types';
|
||||
import { METRIC_FORMATTERS } from '../../../../common/formatters/snapshot_metric_formats';
|
||||
import { createFormatter } from '../../../../common/formatters';
|
||||
import {
|
||||
buildErrorAlertReason,
|
||||
buildFiredAlertReason,
|
||||
buildNoDataAlertReason,
|
||||
stateToAlertMessage,
|
||||
} from '../common/messages';
|
||||
import { evaluateCondition } from './evaluate_condition';
|
||||
|
||||
interface InventoryMetricThresholdParams {
|
||||
|
@ -18,13 +26,20 @@ interface InventoryMetricThresholdParams {
|
|||
filterQuery: string | undefined;
|
||||
nodeType: InventoryItemType;
|
||||
sourceId?: string;
|
||||
alertOnNoData?: boolean;
|
||||
}
|
||||
|
||||
export const createInventoryMetricThresholdExecutor = (
|
||||
libs: InfraBackendLibs,
|
||||
alertId: string
|
||||
) => async ({ services, params }: AlertExecutorOptions) => {
|
||||
const { criteria, filterQuery, sourceId, nodeType } = params as InventoryMetricThresholdParams;
|
||||
const {
|
||||
criteria,
|
||||
filterQuery,
|
||||
sourceId,
|
||||
nodeType,
|
||||
alertOnNoData,
|
||||
} = params as InventoryMetricThresholdParams;
|
||||
|
||||
const source = await libs.sources.getSourceConfiguration(
|
||||
services.savedObjectsClient,
|
||||
|
@ -48,26 +63,56 @@ export const createInventoryMetricThresholdExecutor = (
|
|||
const isNoData = results.some((result) => result[item].isNoData);
|
||||
const isError = results.some((result) => result[item].isError);
|
||||
|
||||
if (shouldAlertFire) {
|
||||
const nextState = isError
|
||||
? AlertStates.ERROR
|
||||
: isNoData
|
||||
? AlertStates.NO_DATA
|
||||
: shouldAlertFire
|
||||
? AlertStates.ALERT
|
||||
: AlertStates.OK;
|
||||
|
||||
let reason;
|
||||
if (nextState === AlertStates.ALERT) {
|
||||
reason = results
|
||||
.map((result) => {
|
||||
if (!result[item]) return '';
|
||||
const resultWithVerboseMetricName = {
|
||||
...result[item],
|
||||
metric: toMetricOpt(result[item].metric)?.text || result[item].metric,
|
||||
};
|
||||
return buildFiredAlertReason(resultWithVerboseMetricName);
|
||||
})
|
||||
.join('\n');
|
||||
}
|
||||
if (alertOnNoData) {
|
||||
if (nextState === AlertStates.NO_DATA) {
|
||||
reason = results
|
||||
.filter((result) => result[item].isNoData)
|
||||
.map((result) => buildNoDataAlertReason(result[item]))
|
||||
.join('\n');
|
||||
} else if (nextState === AlertStates.ERROR) {
|
||||
reason = results
|
||||
.filter((result) => result[item].isError)
|
||||
.map((result) => buildErrorAlertReason(result[item].metric))
|
||||
.join('\n');
|
||||
}
|
||||
}
|
||||
if (reason) {
|
||||
alertInstance.scheduleActions(FIRED_ACTIONS.id, {
|
||||
group: item,
|
||||
item,
|
||||
valueOf: mapToConditionsLookup(results, (result) =>
|
||||
alertState: stateToAlertMessage[nextState],
|
||||
reason,
|
||||
timestamp: moment().toISOString(),
|
||||
value: mapToConditionsLookup(results, (result) =>
|
||||
formatMetric(result[item].metric, result[item].currentValue)
|
||||
),
|
||||
thresholdOf: mapToConditionsLookup(criteria, (c) => c.threshold),
|
||||
metricOf: mapToConditionsLookup(criteria, (c) => c.metric),
|
||||
threshold: mapToConditionsLookup(criteria, (c) => c.threshold),
|
||||
metric: mapToConditionsLookup(criteria, (c) => c.metric),
|
||||
});
|
||||
}
|
||||
|
||||
alertInstance.replaceState({
|
||||
alertState: isError
|
||||
? AlertStates.ERROR
|
||||
: isNoData
|
||||
? AlertStates.NO_DATA
|
||||
: shouldAlertFire
|
||||
? AlertStates.ALERT
|
||||
: AlertStates.OK,
|
||||
alertState: nextState,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -35,6 +35,7 @@ export const registerMetricInventoryThresholdAlertType = (libs: InfraBackendLibs
|
|||
schema.string({ validate: validateIsStringElasticsearchJSONFilter })
|
||||
),
|
||||
sourceId: schema.string(),
|
||||
alertOnNoData: schema.maybe(schema.boolean()),
|
||||
},
|
||||
{ unknowns: 'allow' }
|
||||
),
|
||||
|
|
|
@ -5,25 +5,12 @@
|
|||
*/
|
||||
import { Unit } from '@elastic/datemath';
|
||||
import { SnapshotMetricType } from '../../../../common/inventory_models/types';
|
||||
import { Comparator, AlertStates } from '../common/types';
|
||||
|
||||
export { Comparator, AlertStates };
|
||||
|
||||
export const METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID = 'metrics.alert.inventory.threshold';
|
||||
|
||||
export enum Comparator {
|
||||
GT = '>',
|
||||
LT = '<',
|
||||
GT_OR_EQ = '>=',
|
||||
LT_OR_EQ = '<=',
|
||||
BETWEEN = 'between',
|
||||
OUTSIDE_RANGE = 'outside',
|
||||
}
|
||||
|
||||
export enum AlertStates {
|
||||
OK,
|
||||
ALERT,
|
||||
NO_DATA,
|
||||
ERROR,
|
||||
}
|
||||
|
||||
export interface InventoryMetricConditions {
|
||||
metric: SnapshotMetricType;
|
||||
timeSize: number;
|
||||
|
|
|
@ -15,8 +15,8 @@ import { InfraDatabaseSearchResponse } from '../../../adapters/framework/adapter
|
|||
import { createAfterKeyHandler } from '../../../../utils/create_afterkey_handler';
|
||||
import { AlertServices, AlertExecutorOptions } from '../../../../../../alerts/server';
|
||||
import { getAllCompositeData } from '../../../../utils/get_all_composite_data';
|
||||
import { DOCUMENT_COUNT_I18N } from '../../common/messages';
|
||||
import { MetricExpressionParams, Comparator, Aggregators } from '../types';
|
||||
import { DOCUMENT_COUNT_I18N } from '../messages';
|
||||
import { getElasticsearchMetricQuery } from './metric_query';
|
||||
|
||||
interface Aggregation {
|
||||
|
|
|
@ -8,14 +8,14 @@ import { i18n } from '@kbn/i18n';
|
|||
import moment from 'moment';
|
||||
import { AlertExecutorOptions } from '../../../../../alerts/server';
|
||||
import { InfraBackendLibs } from '../../infra_types';
|
||||
import { AlertStates } from './types';
|
||||
import { evaluateAlert } from './lib/evaluate_alert';
|
||||
import {
|
||||
buildErrorAlertReason,
|
||||
buildFiredAlertReason,
|
||||
buildNoDataAlertReason,
|
||||
stateToAlertMessage,
|
||||
} from './messages';
|
||||
} from '../common/messages';
|
||||
import { AlertStates } from './types';
|
||||
import { evaluateAlert } from './lib/evaluate_alert';
|
||||
|
||||
export const createMetricThresholdExecutor = (libs: InfraBackendLibs, alertId: string) =>
|
||||
async function (options: AlertExecutorOptions) {
|
||||
|
|
|
@ -3,18 +3,11 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { Unit } from '@elastic/datemath';
|
||||
export const METRIC_THRESHOLD_ALERT_TYPE_ID = 'metrics.alert.threshold';
|
||||
import { Comparator, AlertStates } from '../common/types';
|
||||
|
||||
export enum Comparator {
|
||||
GT = '>',
|
||||
LT = '<',
|
||||
GT_OR_EQ = '>=',
|
||||
LT_OR_EQ = '<=',
|
||||
BETWEEN = 'between',
|
||||
OUTSIDE_RANGE = 'outside',
|
||||
}
|
||||
export { Comparator, AlertStates };
|
||||
export const METRIC_THRESHOLD_ALERT_TYPE_ID = 'metrics.alert.threshold';
|
||||
|
||||
export enum Aggregators {
|
||||
COUNT = 'count',
|
||||
|
@ -28,13 +21,6 @@ export enum Aggregators {
|
|||
P99 = 'p99',
|
||||
}
|
||||
|
||||
export enum AlertStates {
|
||||
OK,
|
||||
ALERT,
|
||||
NO_DATA,
|
||||
ERROR,
|
||||
}
|
||||
|
||||
interface BaseMetricExpressionParams {
|
||||
timeSize: number;
|
||||
timeUnit: Unit;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue