From f11efeb2029d68c4df33ecea0a0e3d75e1a77a4e Mon Sep 17 00:00:00 2001 From: Mykola Harmash Date: Wed, 4 Oct 2023 12:24:52 +0200 Subject: [PATCH 1/3] [Infra UI] Disable Infrastructure and Metrics alerts in Serverless --- .../test_suites/core_plugins/rendering.ts | 24 +- ...type_registry_deprecated_consumers.test.ts | 1 - ...rule_type_registry_deprecated_consumers.ts | 1 - .../infra/common/alerting/metrics/types.ts | 3 - .../infra/common/plugin_config_types.ts | 3 + .../components/metrics_alert_dropdown.tsx | 241 ++++++++------ .../components/alert_flyout.tsx | 9 + .../components/alert_flyout.tsx | 53 ---- .../components/expression.test.tsx | 86 ----- .../metric_anomaly/components/expression.tsx | 298 ------------------ .../components/influencer_filter.tsx | 193 ------------ .../metric_anomaly/components/node_type.tsx | 118 ------- .../components/severity_threshold.tsx | 141 --------- .../metric_anomaly/components/validation.tsx | 34 -- .../public/alerting/metric_anomaly/index.ts | 45 --- .../asset_details/tabs/overview/alerts.tsx | 27 +- .../containers/plugin_config_context.test.tsx | 3 + ...er_inventory_metric_threshold_rule_type.ts | 10 +- .../register_log_threshold_rule_type.ts | 8 +- .../metric_anomaly/evaluate_condition.ts | 51 --- .../metric_anomaly/metric_anomaly_executor.ts | 142 --------- .../preview_metric_anomaly_alert.ts | 132 -------- .../register_metric_anomaly_rule_type.ts | 125 -------- .../metric_threshold_executor.test.ts | 3 + .../register_metric_threshold_rule_type.ts | 8 +- .../lib/alerting/register_rule_types.ts | 13 +- .../infra/server/lib/sources/sources.test.ts | 3 + x-pack/plugins/infra/server/plugin.ts | 14 +- .../common/custom_threshold_rule/types.ts | 1 - .../lib/rules/custom_threshold/types.ts | 1 - .../translations/translations/fr-FR.json | 30 -- .../translations/translations/ja-JP.json | 30 -- .../translations/translations/zh-CN.json | 30 -- .../group4/check_registered_rule_types.ts | 1 - .../check_registered_task_types.ts | 1 - 35 files changed, 231 insertions(+), 1652 deletions(-) delete mode 100644 x-pack/plugins/infra/public/alerting/metric_anomaly/components/alert_flyout.tsx delete mode 100644 x-pack/plugins/infra/public/alerting/metric_anomaly/components/expression.test.tsx delete mode 100644 x-pack/plugins/infra/public/alerting/metric_anomaly/components/expression.tsx delete mode 100644 x-pack/plugins/infra/public/alerting/metric_anomaly/components/influencer_filter.tsx delete mode 100644 x-pack/plugins/infra/public/alerting/metric_anomaly/components/node_type.tsx delete mode 100644 x-pack/plugins/infra/public/alerting/metric_anomaly/components/severity_threshold.tsx delete mode 100644 x-pack/plugins/infra/public/alerting/metric_anomaly/components/validation.tsx delete mode 100644 x-pack/plugins/infra/public/alerting/metric_anomaly/index.ts delete mode 100644 x-pack/plugins/infra/server/lib/alerting/metric_anomaly/evaluate_condition.ts delete mode 100644 x-pack/plugins/infra/server/lib/alerting/metric_anomaly/metric_anomaly_executor.ts delete mode 100644 x-pack/plugins/infra/server/lib/alerting/metric_anomaly/preview_metric_anomaly_alert.ts delete mode 100644 x-pack/plugins/infra/server/lib/alerting/metric_anomaly/register_metric_anomaly_rule_type.ts diff --git a/test/plugin_functional/test_suites/core_plugins/rendering.ts b/test/plugin_functional/test_suites/core_plugins/rendering.ts index 441f506bd2552..91d0a918670fa 100644 --- a/test/plugin_functional/test_suites/core_plugins/rendering.ts +++ b/test/plugin_functional/test_suites/core_plugins/rendering.ts @@ -268,25 +268,17 @@ export default function ({ getService }: PluginFunctionalProviderContext) { 'xpack.index_management.enableIndexStats (any)', 'xpack.infra.sources.default.fields.message (array)', /** - * xpack.infra.featureFlags.customThresholdAlertsEnabled is conditional based on traditional/serverless offering - * and will resolve to (boolean) - */ - 'xpack.infra.featureFlags.customThresholdAlertsEnabled (any)', - /** - * xpack.infra.featureFlags.logsUIEnabled is conditional based on traditional/serverless offering - * and will resolve to (boolean) - */ - 'xpack.infra.featureFlags.logsUIEnabled (any)', - /** - * xpack.infra.featureFlags.metricsExplorerEnabled is conditional based on traditional/serverless offering - * and will resolve to (boolean) + * Feature flags bellow are conditional based on traditional/serverless offering + * and will all resolve to xpack.infra.featureFlags.* (boolean) */ 'xpack.infra.featureFlags.metricsExplorerEnabled (any)', - /** - * xpack.infra.featureFlags.osqueryEnabled is conditional based on traditional/serverless offering - * and will resolve to (boolean) - */ + 'xpack.infra.featureFlags.customThresholdAlertsEnabled (any)', 'xpack.infra.featureFlags.osqueryEnabled (any)', + 'xpack.infra.featureFlags.inventoryThresholdAlertRuleEnabled (any)', + 'xpack.infra.featureFlags.metricThresholdAlertRuleEnabled (any)', + 'xpack.infra.featureFlags.logThresholdAlertRuleEnabled (any)', + 'xpack.infra.featureFlags.logsUIEnabled (any)', + 'xpack.license_management.ui.enabled (boolean)', 'xpack.maps.preserveDrawingBuffer (boolean)', 'xpack.maps.showMapsInspectorAdapter (boolean)', diff --git a/x-pack/plugins/alerting/server/rule_type_registry_deprecated_consumers.test.ts b/x-pack/plugins/alerting/server/rule_type_registry_deprecated_consumers.test.ts index e1a7828d85042..94d8aa923ea19 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry_deprecated_consumers.test.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry_deprecated_consumers.test.ts @@ -37,7 +37,6 @@ describe('rule_type_registry_deprecated_consumers', () => { "siem.newTermsRule", "siem.notifications", "slo.rules.burnRate", - "metrics.alert.anomaly", "logs.alert.document.count", "metrics.alert.inventory.threshold", "metrics.alert.threshold", diff --git a/x-pack/plugins/alerting/server/rule_type_registry_deprecated_consumers.ts b/x-pack/plugins/alerting/server/rule_type_registry_deprecated_consumers.ts index d6a238c414243..7394736968609 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry_deprecated_consumers.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry_deprecated_consumers.ts @@ -30,7 +30,6 @@ export const ruleTypeIdWithValidLegacyConsumers: Record = { 'siem.newTermsRule': [ALERTS_FEATURE_ID], 'siem.notifications': [ALERTS_FEATURE_ID], 'slo.rules.burnRate': [ALERTS_FEATURE_ID], - 'metrics.alert.anomaly': [ALERTS_FEATURE_ID], 'logs.alert.document.count': [ALERTS_FEATURE_ID], 'metrics.alert.inventory.threshold': [ALERTS_FEATURE_ID], 'metrics.alert.threshold': [ALERTS_FEATURE_ID], diff --git a/x-pack/plugins/infra/common/alerting/metrics/types.ts b/x-pack/plugins/infra/common/alerting/metrics/types.ts index 151c804bf413f..7ca0e9e64ca34 100644 --- a/x-pack/plugins/infra/common/alerting/metrics/types.ts +++ b/x-pack/plugins/infra/common/alerting/metrics/types.ts @@ -12,18 +12,15 @@ import { InventoryItemType, SnapshotMetricType } from '../../inventory_models/ty export const METRIC_THRESHOLD_ALERT_TYPE_ID = 'metrics.alert.threshold'; export const METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID = 'metrics.alert.inventory.threshold'; -export const METRIC_ANOMALY_ALERT_TYPE_ID = 'metrics.alert.anomaly'; export enum InfraRuleType { MetricThreshold = 'metrics.alert.threshold', InventoryThreshold = 'metrics.alert.inventory.threshold', - Anomaly = 'metrics.alert.anomaly', } export interface InfraRuleTypeParams { [InfraRuleType.MetricThreshold]: MetricThresholdParams; [InfraRuleType.InventoryThreshold]: InventoryMetricConditions; - [InfraRuleType.Anomaly]: MetricAnomalyParams; } export enum Comparator { diff --git a/x-pack/plugins/infra/common/plugin_config_types.ts b/x-pack/plugins/infra/common/plugin_config_types.ts index dd915e39cdec0..c5fada95e5a83 100644 --- a/x-pack/plugins/infra/common/plugin_config_types.ts +++ b/x-pack/plugins/infra/common/plugin_config_types.ts @@ -30,6 +30,9 @@ export interface InfraConfig { logsUIEnabled: boolean; metricsExplorerEnabled: boolean; osqueryEnabled: boolean; + inventoryThresholdAlertRuleEnabled: boolean; + metricThresholdAlertRuleEnabled: boolean; + logThresholdAlertRuleEnabled: boolean; }; } diff --git a/x-pack/plugins/infra/public/alerting/common/components/metrics_alert_dropdown.tsx b/x-pack/plugins/infra/public/alerting/common/components/metrics_alert_dropdown.tsx index e80da08fc082e..e4284d154c104 100644 --- a/x-pack/plugins/infra/public/alerting/common/components/metrics_alert_dropdown.tsx +++ b/x-pack/plugins/infra/public/alerting/common/components/metrics_alert_dropdown.tsx @@ -7,11 +7,10 @@ import { i18n } from '@kbn/i18n'; import React, { useState, useCallback, useMemo } from 'react'; -import { - EuiPopover, - EuiHeaderLink, - EuiContextMenu, +import { EuiPopover, EuiHeaderLink, EuiContextMenu } from '@elastic/eui'; +import type { EuiContextMenuPanelDescriptor, + EuiContextMenuPanelItemDescriptor, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { useKibana } from '@kbn/kibana-react-plugin/public'; @@ -23,6 +22,118 @@ import { InfraClientStartDeps } from '../../../types'; type VisibleFlyoutType = 'inventory' | 'metricThreshold' | 'customThreshold'; +interface ContextMenuEntries { + items: EuiContextMenuPanelItemDescriptor[]; + panels: EuiContextMenuPanelDescriptor[]; +} + +function useInfrastructureMenu( + onCreateRuleClick: (flyoutType: VisibleFlyoutType) => void +): ContextMenuEntries { + const { featureFlags } = usePluginConfig(); + + return useMemo(() => { + if (!featureFlags.inventoryThresholdAlertRuleEnabled) { + return { items: [], panels: [] }; + } + + return { + items: [ + { + 'data-test-subj': 'inventory-alerts-menu-option', + name: i18n.translate('xpack.infra.alerting.infrastructureDropdownMenu', { + defaultMessage: 'Infrastructure', + }), + panel: 1, + }, + ], + panels: [ + { + id: 1, + title: i18n.translate('xpack.infra.alerting.infrastructureDropdownTitle', { + defaultMessage: 'Infrastructure rules', + }), + items: [ + { + 'data-test-subj': 'inventory-alerts-create-rule', + name: i18n.translate('xpack.infra.alerting.createInventoryRuleButton', { + defaultMessage: 'Create inventory rule', + }), + onClick: () => onCreateRuleClick('inventory'), + }, + ], + }, + ], + }; + }, [featureFlags.inventoryThresholdAlertRuleEnabled, onCreateRuleClick]); +} + +function useMetricsMenu( + onCreateRuleClick: (flyoutType: VisibleFlyoutType) => void +): ContextMenuEntries { + const { featureFlags } = usePluginConfig(); + + return useMemo(() => { + if (!featureFlags.metricThresholdAlertRuleEnabled) { + return { items: [], panels: [] }; + } + + return { + items: [ + { + 'data-test-subj': 'metrics-threshold-alerts-menu-option', + name: i18n.translate('xpack.infra.alerting.metricsDropdownMenu', { + defaultMessage: 'Metrics', + }), + panel: 2, + }, + ], + panels: [ + { + id: 2, + title: i18n.translate('xpack.infra.alerting.metricsDropdownTitle', { + defaultMessage: 'Metrics rules', + }), + items: [ + { + 'data-test-subj': 'metrics-threshold-alerts-create-rule', + name: i18n.translate('xpack.infra.alerting.createThresholdRuleButton', { + defaultMessage: 'Create threshold rule', + }), + onClick: () => onCreateRuleClick('metricThreshold'), + }, + ], + }, + ], + }; + }, [featureFlags.metricThresholdAlertRuleEnabled, onCreateRuleClick]); +} + +function useCustomThresholdMenu( + onCreateRuleClick: (flyoutType: VisibleFlyoutType) => void +): ContextMenuEntries { + const { featureFlags } = usePluginConfig(); + + return useMemo(() => { + if (!featureFlags.customThresholdAlertsEnabled) { + return { items: [], panels: [] }; + } + + return { + items: [ + { + 'data-test-subj': 'custom-threshold-alerts-menu-option', + name: i18n.translate('xpack.infra.alerting.customThresholdDropdownMenu', { + defaultMessage: 'Create custom threshold rule', + }), + onClick: () => onCreateRuleClick('customThreshold'), + }, + ], + panels: [], + }; + }, [featureFlags.customThresholdAlertsEnabled, onCreateRuleClick]); +} + export const MetricsAlertDropdown = () => { const [popoverOpen, setPopoverOpen] = useState(false); const [visibleFlyoutType, setVisibleFlyoutType] = useState(null); @@ -34,8 +145,6 @@ export const MetricsAlertDropdown = () => { () => Boolean(uiCapabilities?.infrastructure?.save), [uiCapabilities] ); - const { featureFlags } = usePluginConfig(); - const closeFlyout = useCallback(() => setVisibleFlyoutType(null), [setVisibleFlyoutType]); const closePopover = useCallback(() => { @@ -45,50 +154,19 @@ export const MetricsAlertDropdown = () => { const togglePopover = useCallback(() => { setPopoverOpen(!popoverOpen); }, [setPopoverOpen, popoverOpen]); - const infrastructureAlertsPanel = useMemo( - () => ({ - id: 1, - title: i18n.translate('xpack.infra.alerting.infrastructureDropdownTitle', { - defaultMessage: 'Infrastructure rules', - }), - items: [ - { - 'data-test-subj': 'inventory-alerts-create-rule', - name: i18n.translate('xpack.infra.alerting.createInventoryRuleButton', { - defaultMessage: 'Create inventory rule', - }), - onClick: () => { - closePopover(); - setVisibleFlyoutType('inventory'); - }, - }, - ], - }), - [setVisibleFlyoutType, closePopover] - ); - const metricsAlertsPanel = useMemo( - () => ({ - id: 2, - title: i18n.translate('xpack.infra.alerting.metricsDropdownTitle', { - defaultMessage: 'Metrics rules', - }), - items: [ - { - 'data-test-subj': 'metrics-threshold-alerts-create-rule', - name: i18n.translate('xpack.infra.alerting.createThresholdRuleButton', { - defaultMessage: 'Create threshold rule', - }), - onClick: () => { - closePopover(); - setVisibleFlyoutType('metricThreshold'); - }, - }, - ], - }), - [setVisibleFlyoutType, closePopover] + const onCreateRuleClick = useCallback( + (flyoutType: VisibleFlyoutType) => { + closePopover(); + setVisibleFlyoutType(flyoutType); + }, + [closePopover] ); + const infrastructureMenu = useInfrastructureMenu(onCreateRuleClick); + const metricsMenu = useMetricsMenu(onCreateRuleClick); + const customThresholdMenu = useCustomThresholdMenu(onCreateRuleClick); + const manageRulesLinkProps = observability.useRulesLink(); const manageAlertsMenuItem = useMemo( @@ -102,56 +180,27 @@ export const MetricsAlertDropdown = () => { [manageRulesLinkProps] ); - const firstPanelMenuItems: EuiContextMenuPanelDescriptor['items'] = useMemo( - () => - canCreateAlerts - ? [ - { - 'data-test-subj': 'inventory-alerts-menu-option', - name: i18n.translate('xpack.infra.alerting.infrastructureDropdownMenu', { - defaultMessage: 'Infrastructure', - }), - panel: 1, - }, - { - 'data-test-subj': 'metrics-threshold-alerts-menu-option', - name: i18n.translate('xpack.infra.alerting.metricsDropdownMenu', { - defaultMessage: 'Metrics', - }), - panel: 2, - }, - ...(featureFlags.customThresholdAlertsEnabled - ? [ - { - 'data-test-subj': 'custom-threshold-alerts-menu-option', - name: i18n.translate('xpack.infra.alerting.customThresholdDropdownMenu', { - defaultMessage: 'Create custom threshold rule', - }), - onClick: () => { - closePopover(); - setVisibleFlyoutType('customThreshold'); - }, - }, - ] - : []), - manageAlertsMenuItem, - ] - : [manageAlertsMenuItem], - [canCreateAlerts, closePopover, featureFlags.customThresholdAlertsEnabled, manageAlertsMenuItem] - ); - const panels: EuiContextMenuPanelDescriptor[] = useMemo( - () => - [ - { - id: 0, - title: i18n.translate('xpack.infra.alerting.alertDropdownTitle', { - defaultMessage: 'Alerts and rules', - }), - items: firstPanelMenuItems, - }, - ].concat(canCreateAlerts ? [infrastructureAlertsPanel, metricsAlertsPanel] : []), - [infrastructureAlertsPanel, metricsAlertsPanel, firstPanelMenuItems, canCreateAlerts] + () => [ + { + id: 0, + title: i18n.translate('xpack.infra.alerting.alertDropdownTitle', { + defaultMessage: 'Alerts and rules', + }), + items: canCreateAlerts + ? [ + ...infrastructureMenu.items, + ...metricsMenu.items, + ...customThresholdMenu.items, + manageAlertsMenuItem, + ] + : [manageAlertsMenuItem], + }, + ...(canCreateAlerts + ? [...infrastructureMenu.panels, ...metricsMenu.panels, ...customThresholdMenu.panels] + : []), + ], + [canCreateAlerts, infrastructureMenu, metricsMenu, customThresholdMenu, manageAlertsMenuItem] ); return ( diff --git a/x-pack/plugins/infra/public/alerting/custom_threshold/components/alert_flyout.tsx b/x-pack/plugins/infra/public/alerting/custom_threshold/components/alert_flyout.tsx index 3e064d26159e4..19e60e43fd877 100644 --- a/x-pack/plugins/infra/public/alerting/custom_threshold/components/alert_flyout.tsx +++ b/x-pack/plugins/infra/public/alerting/custom_threshold/components/alert_flyout.tsx @@ -27,6 +27,15 @@ export function AlertFlyout({ onClose }: Props) { onClose, canChangeTrigger: false, ruleTypeId: OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, + metadata: { + currentOptions: { + /* + Setting the groupBy is currently required in custom threshold + rule for it to populate the rule with additional host context. + */ + groupBy: 'host.name', + }, + }, }); }, [onClose, triggersActionsUI]); diff --git a/x-pack/plugins/infra/public/alerting/metric_anomaly/components/alert_flyout.tsx b/x-pack/plugins/infra/public/alerting/metric_anomaly/components/alert_flyout.tsx deleted file mode 100644 index a2b0284708459..0000000000000 --- a/x-pack/plugins/infra/public/alerting/metric_anomaly/components/alert_flyout.tsx +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useCallback, useContext, useMemo } from 'react'; - -import { TriggerActionsContext } from '../../../utils/triggers_actions_context'; -import { METRIC_ANOMALY_ALERT_TYPE_ID } from '../../../../common/alerting/metrics'; -import { InfraWaffleMapOptions } from '../../../lib/lib'; -import { InventoryItemType } from '../../../../common/inventory_models/types'; -import { useAlertPrefillContext } from '../../use_alert_prefill'; - -interface Props { - visible?: boolean; - metric?: InfraWaffleMapOptions['metric']; - nodeType?: InventoryItemType; - filter?: string; - setVisible(val: boolean): void; -} - -export const AlertFlyout = ({ metric, nodeType, visible, setVisible }: Props) => { - const { triggersActionsUI } = useContext(TriggerActionsContext); - - const onCloseFlyout = useCallback(() => setVisible(false), [setVisible]); - const AddAlertFlyout = useMemo( - () => - triggersActionsUI && - triggersActionsUI.getAddRuleFlyout({ - consumer: 'infrastructure', - onClose: onCloseFlyout, - canChangeTrigger: false, - ruleTypeId: METRIC_ANOMALY_ALERT_TYPE_ID, - metadata: { - metric, - nodeType, - }, - }), - // eslint-disable-next-line react-hooks/exhaustive-deps - [triggersActionsUI, visible] - ); - - return <>{visible && AddAlertFlyout}; -}; - -export const PrefilledAnomalyAlertFlyout = ({ onClose }: { onClose(): void }) => { - const { inventoryPrefill } = useAlertPrefillContext(); - const { nodeType, metric } = inventoryPrefill; - - return ; -}; diff --git a/x-pack/plugins/infra/public/alerting/metric_anomaly/components/expression.test.tsx b/x-pack/plugins/infra/public/alerting/metric_anomaly/components/expression.test.tsx deleted file mode 100644 index de3fcd03df675..0000000000000 --- a/x-pack/plugins/infra/public/alerting/metric_anomaly/components/expression.test.tsx +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { mountWithIntl, nextTick } from '@kbn/test-jest-helpers'; -// We are using this inside a `jest.mock` call. Jest requires dynamic dependencies to be prefixed with `mock` -import { coreMock as mockCoreMock } from '@kbn/core/public/mocks'; -import React from 'react'; -import { Expression, AlertContextMeta } from './expression'; -import { act } from 'react-dom/test-utils'; -import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; - -jest.mock('../../../containers/metrics_source/source', () => ({ - withSourceProvider: () => jest.fn, - useSourceContext: () => ({ - source: { id: 'default' }, - createDerivedIndexPattern: () => ({ fields: [], title: 'metricbeat-*' }), - }), -})); - -jest.mock('../../../hooks/use_kibana', () => ({ - useKibanaContextForPlugin: () => ({ - services: mockCoreMock.createStart(), - }), -})); - -jest.mock('../../../hooks/use_kibana_space', () => ({ - useActiveKibanaSpace: () => ({ - space: { id: 'default' }, - }), -})); - -jest.mock('../../../containers/ml/infra_ml_capabilities', () => ({ - useInfraMLCapabilities: () => ({ - isLoading: false, - hasInfraMLCapabilities: true, - }), -})); - -const dataViewMock = dataViewPluginMocks.createStartContract(); - -describe('Expression', () => { - async function setup(currentOptions: AlertContextMeta) { - const ruleParams = { - metric: undefined, - nodeType: undefined, - threshold: 50, - }; - const wrapper = mountWithIntl( - Reflect.set(ruleParams, key, value)} - setRuleProperty={() => {}} - metadata={currentOptions} - dataViews={dataViewMock} - /> - ); - - const update = async () => - await act(async () => { - await nextTick(); - wrapper.update(); - }); - - await update(); - - return { wrapper, update, ruleParams }; - } - - it('should prefill the alert using the context metadata', async () => { - const currentOptions = { - nodeType: 'pod', - metric: { type: 'tx' }, - }; - const { ruleParams } = await setup(currentOptions as AlertContextMeta); - expect(ruleParams.nodeType).toBe('k8s'); - expect(ruleParams.metric).toBe('network_out'); - }); -}); diff --git a/x-pack/plugins/infra/public/alerting/metric_anomaly/components/expression.tsx b/x-pack/plugins/infra/public/alerting/metric_anomaly/components/expression.tsx deleted file mode 100644 index 76dbac0b8821b..0000000000000 --- a/x-pack/plugins/infra/public/alerting/metric_anomaly/components/expression.tsx +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiFlexGroup, EuiSkeletonText, EuiSpacer, EuiText } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; -import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { euiStyled, EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; -import { - RuleTypeParams, - RuleTypeParamsExpressionProps, - WhenExpression, -} from '@kbn/triggers-actions-ui-plugin/public'; -import { ML_ANOMALY_THRESHOLD } from '@kbn/ml-anomaly-utils/anomaly_threshold'; -import { useSourceContext, withSourceProvider } from '../../../containers/metrics_source'; -import { MetricAnomalyParams } from '../../../../common/alerting/metrics'; -import { findInventoryModel } from '../../../../common/inventory_models'; -import { InventoryItemType, SnapshotMetricType } from '../../../../common/inventory_models/types'; -import { SubscriptionSplashPrompt } from '../../../components/subscription_splash_content'; -import { useInfraMLCapabilities } from '../../../containers/ml/infra_ml_capabilities'; -import { useActiveKibanaSpace } from '../../../hooks/use_kibana_space'; -import { InfraWaffleMapOptions } from '../../../lib/lib'; -import { InfluencerFilter } from './influencer_filter'; -import { NodeTypeExpression } from './node_type'; -import { SeverityThresholdExpression } from './severity_threshold'; - -export interface AlertContextMeta { - metric?: InfraWaffleMapOptions['metric']; - nodeType?: InventoryItemType; -} - -type AlertParams = RuleTypeParams & - MetricAnomalyParams & { sourceId: string; spaceId: string; hasInfraMLCapabilities: boolean }; - -type Props = Omit< - RuleTypeParamsExpressionProps, - 'defaultActionGroupId' | 'actionGroups' | 'charts' | 'data' | 'unifiedSearch' | 'onChangeMetaData' ->; - -export const defaultExpression = { - metric: 'memory_usage' as MetricAnomalyParams['metric'], - threshold: ML_ANOMALY_THRESHOLD.MAJOR as MetricAnomalyParams['threshold'], - nodeType: 'hosts' as MetricAnomalyParams['nodeType'], - influencerFilter: undefined, -}; - -export const Expression: React.FC = (props) => { - const { hasInfraMLCapabilities, isLoading: isLoadingMLCapabilities } = useInfraMLCapabilities(); - const { space } = useActiveKibanaSpace(); - - const { setRuleParams, ruleParams, ruleInterval, metadata } = props; - const { source, createDerivedIndexPattern } = useSourceContext(); - - const derivedIndexPattern = useMemo( - () => createDerivedIndexPattern(), - [createDerivedIndexPattern] - ); - - const [influencerFieldName, updateInfluencerFieldName] = useState( - ruleParams.influencerFilter?.fieldName ?? 'host.name' - ); - - useEffect(() => { - setRuleParams('hasInfraMLCapabilities', hasInfraMLCapabilities); - }, [setRuleParams, hasInfraMLCapabilities]); - - useEffect(() => { - if (ruleParams.influencerFilter) { - setRuleParams('influencerFilter', { - ...ruleParams.influencerFilter, - fieldName: influencerFieldName, - }); - } - }, [influencerFieldName, ruleParams, setRuleParams]); - const updateInfluencerFieldValue = useCallback( - (value: string) => { - if (value) { - setRuleParams('influencerFilter', { - ...ruleParams.influencerFilter, - fieldValue: value, - } as MetricAnomalyParams['influencerFilter']); - } else { - setRuleParams('influencerFilter', undefined); - } - }, - [setRuleParams, ruleParams] - ); - - useEffect(() => { - setRuleParams('alertInterval', ruleInterval); - }, [setRuleParams, ruleInterval]); - - const updateNodeType = useCallback( - (nt: any) => { - setRuleParams('nodeType', nt); - }, - [setRuleParams] - ); - - const updateMetric = useCallback( - (metric: string) => { - setRuleParams('metric', metric as MetricAnomalyParams['metric']); - }, - [setRuleParams] - ); - - const updateSeverityThreshold = useCallback( - (threshold: any) => { - setRuleParams('threshold', threshold); - }, - [setRuleParams] - ); - - const prefillNodeType = useCallback(() => { - const md = metadata; - if (md && md.nodeType) { - setRuleParams( - 'nodeType', - getMLNodeTypeFromInventoryNodeType(md.nodeType) ?? defaultExpression.nodeType - ); - } else { - setRuleParams('nodeType', defaultExpression.nodeType); - } - }, [metadata, setRuleParams]); - - const prefillMetric = useCallback(() => { - const md = metadata; - if (md && md.metric) { - setRuleParams( - 'metric', - getMLMetricFromInventoryMetric(md.metric.type) ?? defaultExpression.metric - ); - } else { - setRuleParams('metric', defaultExpression.metric); - } - }, [metadata, setRuleParams]); - - useEffect(() => { - if (!ruleParams.nodeType) { - prefillNodeType(); - } - - if (!ruleParams.threshold) { - setRuleParams('threshold', defaultExpression.threshold); - } - - if (!ruleParams.metric) { - prefillMetric(); - } - - if (!ruleParams.sourceId) { - setRuleParams('sourceId', source?.id || 'default'); - } - - if (!ruleParams.spaceId) { - setRuleParams('spaceId', space?.id || 'default'); - } - }, [metadata, derivedIndexPattern, defaultExpression, source, space]); // eslint-disable-line react-hooks/exhaustive-deps - - if (isLoadingMLCapabilities) return ; - if (!hasInfraMLCapabilities) return ; - - return ( - // https://github.com/elastic/kibana/issues/89506 - - -

- -

-
- - - - - - - - - - - - - - - - - -
- ); -}; - -// required for dynamic import -// eslint-disable-next-line import/no-default-export -export default withSourceProvider(Expression)('default'); - -const StyledExpressionRow = euiStyled(EuiFlexGroup)` - display: flex; - flex-wrap: wrap; - margin: 0 -4px; -`; - -const StyledExpression = euiStyled.div` - padding: 0 4px; -`; - -const getDisplayNameForType = (type: InventoryItemType) => { - const inventoryModel = findInventoryModel(type); - return inventoryModel.displayName; -}; - -export const nodeTypes: { [key: string]: any } = { - hosts: { - text: getDisplayNameForType('host'), - value: 'hosts', - }, - k8s: { - text: getDisplayNameForType('pod'), - value: 'k8s', - }, -}; - -const getMLMetricFromInventoryMetric: ( - metric: SnapshotMetricType -) => MetricAnomalyParams['metric'] | null = (metric) => { - switch (metric) { - case 'memory': - return 'memory_usage'; - case 'tx': - return 'network_out'; - case 'rx': - return 'network_in'; - default: - return null; - } -}; - -const getMLNodeTypeFromInventoryNodeType: ( - nodeType: InventoryItemType -) => MetricAnomalyParams['nodeType'] | null = (nodeType) => { - switch (nodeType) { - case 'host': - return 'hosts'; - case 'pod': - return 'k8s'; - default: - return null; - } -}; diff --git a/x-pack/plugins/infra/public/alerting/metric_anomaly/components/influencer_filter.tsx b/x-pack/plugins/infra/public/alerting/metric_anomaly/components/influencer_filter.tsx deleted file mode 100644 index cc1e664d6f9d9..0000000000000 --- a/x-pack/plugins/infra/public/alerting/metric_anomaly/components/influencer_filter.tsx +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { debounce } from 'lodash'; -import { i18n } from '@kbn/i18n'; -import React, { useState, useCallback, useEffect, useMemo } from 'react'; -import { first } from 'lodash'; -import { EuiFlexGroup, EuiFormRow, EuiCheckbox, EuiFlexItem, EuiSelect } from '@elastic/eui'; -import { - MetricsExplorerKueryBar, - CurryLoadSuggestionsType, -} from '../../../pages/metrics/metrics_explorer/components/kuery_bar'; -import { MetricAnomalyParams } from '../../../../common/alerting/metrics'; - -interface Props { - fieldName: string; - fieldValue: string; - nodeType: MetricAnomalyParams['nodeType']; - onChangeFieldName: (v: string) => void; - onChangeFieldValue: (v: string) => void; - derivedIndexPattern: Parameters[0]['derivedIndexPattern']; -} - -const FILTER_TYPING_DEBOUNCE_MS = 500; - -export const InfluencerFilter = ({ - fieldName, - fieldValue, - nodeType, - onChangeFieldName, - onChangeFieldValue, - derivedIndexPattern, -}: Props) => { - const fieldNameOptions = useMemo( - () => (nodeType === 'k8s' ? k8sFieldNames : hostFieldNames), - [nodeType] - ); - - // If initial props contain a fieldValue, assume it was passed in from loaded alertParams, - // and enable the UI element - const [isEnabled, updateIsEnabled] = useState(fieldValue ? true : false); - const [storedFieldValue, updateStoredFieldValue] = useState(fieldValue); - - useEffect( - () => - nodeType === 'k8s' - ? onChangeFieldName(first(k8sFieldNames)!.value) - : onChangeFieldName(first(hostFieldNames)!.value), - [nodeType, onChangeFieldName] - ); - - const onSelectFieldName = useCallback( - (e) => onChangeFieldName(e.target.value), - [onChangeFieldName] - ); - const onUpdateFieldValue = useCallback( - (value) => { - updateStoredFieldValue(value); - onChangeFieldValue(value); - }, - [onChangeFieldValue] - ); - - const toggleEnabled = useCallback(() => { - const nextState = !isEnabled; - updateIsEnabled(nextState); - if (!nextState) { - onChangeFieldValue(''); - } else { - onChangeFieldValue(storedFieldValue); - } - }, [isEnabled, updateIsEnabled, onChangeFieldValue, storedFieldValue]); - - /* eslint-disable-next-line react-hooks/exhaustive-deps */ - const debouncedOnUpdateFieldValue = useCallback( - debounce(onUpdateFieldValue, FILTER_TYPING_DEBOUNCE_MS), - [onUpdateFieldValue] - ); - - const affixFieldNameToQuery: CurryLoadSuggestionsType = - (fn) => (expression, cursorPosition, maxSuggestions) => { - // Add the field name to the front of the passed-in query - const prefix = `${fieldName}:`; - // Trim whitespace to prevent AND/OR suggestions - const modifiedExpression = `${prefix}${expression}`.trim(); - // Move the cursor position forward by the length of the field name - const modifiedPosition = cursorPosition + prefix.length; - return fn(modifiedExpression, modifiedPosition, maxSuggestions, (suggestions) => - suggestions - .map((s) => ({ - ...s, - // Remove quotes from suggestions - text: s.text.replace(/\"/g, '').trim(), - // Offset the returned suggestions' cursor positions so that they can be autocompleted accurately - start: s.start - prefix.length, - end: s.end - prefix.length, - })) - // Removing quotes can lead to an already-selected suggestion still coming up in the autocomplete list, - // so filter these out - .filter((s) => !expression.startsWith(s.text)) - ); - }; - - return ( - - } - helpText={ - isEnabled ? ( - <> - {i18n.translate('xpack.infra.metrics.alertFlyout.anomalyFilterHelpText', { - defaultMessage: - 'Limit the scope of your alert trigger to anomalies influenced by certain node(s).', - })} -
- {i18n.translate('xpack.infra.metrics.alertFlyout.anomalyFilterHelpTextExample', { - defaultMessage: 'For example: "my-node-1" or "my-node-*"', - })} - - ) : null - } - fullWidth - display="rowCompressed" - > - {isEnabled ? ( - - - - - - - - - ) : ( - <> - )} -
- ); -}; - -const hostFieldNames = [ - { - value: 'host.name', - text: 'host.name', - }, -]; - -const k8sFieldNames = [ - { - value: 'kubernetes.pod.uid', - text: 'kubernetes.pod.uid', - }, - { - value: 'kubernetes.node.name', - text: 'kubernetes.node.name', - }, - { - value: 'kubernetes.namespace', - text: 'kubernetes.namespace', - }, -]; - -const filterByNodeLabel = i18n.translate('xpack.infra.metrics.alertFlyout.filterByNodeLabel', { - defaultMessage: 'Filter by node', -}); diff --git a/x-pack/plugins/infra/public/alerting/metric_anomaly/components/node_type.tsx b/x-pack/plugins/infra/public/alerting/metric_anomaly/components/node_type.tsx deleted file mode 100644 index a3cfbc978388a..0000000000000 --- a/x-pack/plugins/infra/public/alerting/metric_anomaly/components/node_type.tsx +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useState } from 'react'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { EuiExpression, EuiPopover, EuiFlexGroup, EuiFlexItem, EuiSelect } from '@elastic/eui'; -import { EuiPopoverTitle, EuiButtonIcon } from '@elastic/eui'; -import { MetricAnomalyParams } from '../../../../common/alerting/metrics'; - -type Node = MetricAnomalyParams['nodeType']; - -interface WhenExpressionProps { - value: Node; - options: { [key: string]: { text: string; value: Node } }; - onChange: (value: Node) => void; - popupPosition?: - | 'upCenter' - | 'upLeft' - | 'upRight' - | 'downCenter' - | 'downLeft' - | 'downRight' - | 'leftCenter' - | 'leftUp' - | 'leftDown' - | 'rightCenter' - | 'rightUp' - | 'rightDown'; -} - -export const NodeTypeExpression = ({ - value, - options, - onChange, - popupPosition, -}: WhenExpressionProps) => { - const [aggTypePopoverOpen, setAggTypePopoverOpen] = useState(false); - - return ( - { - setAggTypePopoverOpen(true); - }} - /> - } - isOpen={aggTypePopoverOpen} - closePopover={() => { - setAggTypePopoverOpen(false); - }} - ownFocus - anchorPosition={popupPosition ?? 'downLeft'} - > -
- setAggTypePopoverOpen(false)}> - - - { - onChange(e.target.value as Node); - setAggTypePopoverOpen(false); - }} - options={Object.values(options).map((o) => o)} - /> -
-
- ); -}; - -interface ClosablePopoverTitleProps { - children: JSX.Element; - onClose: () => void; -} - -export const ClosablePopoverTitle = ({ children, onClose }: ClosablePopoverTitleProps) => { - return ( - - - {children} - - onClose()} - /> - - - - ); -}; diff --git a/x-pack/plugins/infra/public/alerting/metric_anomaly/components/severity_threshold.tsx b/x-pack/plugins/infra/public/alerting/metric_anomaly/components/severity_threshold.tsx deleted file mode 100644 index d910de567a1e9..0000000000000 --- a/x-pack/plugins/infra/public/alerting/metric_anomaly/components/severity_threshold.tsx +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useState } from 'react'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { EuiExpression, EuiPopover, EuiFlexGroup, EuiFlexItem, EuiSelect } from '@elastic/eui'; -import { EuiPopoverTitle, EuiButtonIcon } from '@elastic/eui'; -import { ML_ANOMALY_THRESHOLD } from '@kbn/ml-anomaly-utils/anomaly_threshold'; - -interface WhenExpressionProps { - value: Exclude; - onChange: (value: ML_ANOMALY_THRESHOLD) => void; - popupPosition?: - | 'upCenter' - | 'upLeft' - | 'upRight' - | 'downCenter' - | 'downLeft' - | 'downRight' - | 'leftCenter' - | 'leftUp' - | 'leftDown' - | 'rightCenter' - | 'rightUp' - | 'rightDown'; -} - -const options = { - [ML_ANOMALY_THRESHOLD.CRITICAL]: { - text: i18n.translate('xpack.infra.metrics.alertFlyout.expression.severityScore.criticalLabel', { - defaultMessage: 'Critical', - }), - value: ML_ANOMALY_THRESHOLD.CRITICAL, - }, - [ML_ANOMALY_THRESHOLD.MAJOR]: { - text: i18n.translate('xpack.infra.metrics.alertFlyout.expression.severityScore.majorLabel', { - defaultMessage: 'Major', - }), - value: ML_ANOMALY_THRESHOLD.MAJOR, - }, - [ML_ANOMALY_THRESHOLD.MINOR]: { - text: i18n.translate('xpack.infra.metrics.alertFlyout.expression.severityScore.minorLabel', { - defaultMessage: 'Minor', - }), - value: ML_ANOMALY_THRESHOLD.MINOR, - }, - [ML_ANOMALY_THRESHOLD.WARNING]: { - text: i18n.translate('xpack.infra.metrics.alertFlyout.expression.severityScore.warningLabel', { - defaultMessage: 'Warning', - }), - value: ML_ANOMALY_THRESHOLD.WARNING, - }, -}; - -export const SeverityThresholdExpression = ({ - value, - onChange, - popupPosition, -}: WhenExpressionProps) => { - const [aggTypePopoverOpen, setAggTypePopoverOpen] = useState(false); - - return ( - { - setAggTypePopoverOpen(true); - }} - /> - } - isOpen={aggTypePopoverOpen} - closePopover={() => { - setAggTypePopoverOpen(false); - }} - ownFocus - anchorPosition={popupPosition ?? 'downLeft'} - > -
- setAggTypePopoverOpen(false)}> - - - { - onChange(Number(e.target.value) as ML_ANOMALY_THRESHOLD); - setAggTypePopoverOpen(false); - }} - options={Object.values(options).map((o) => o)} - /> -
-
- ); -}; - -interface ClosablePopoverTitleProps { - children: JSX.Element; - onClose: () => void; -} - -export const ClosablePopoverTitle = ({ children, onClose }: ClosablePopoverTitleProps) => { - return ( - - - {children} - - onClose()} - /> - - - - ); -}; diff --git a/x-pack/plugins/infra/public/alerting/metric_anomaly/components/validation.tsx b/x-pack/plugins/infra/public/alerting/metric_anomaly/components/validation.tsx deleted file mode 100644 index fa278674d55e8..0000000000000 --- a/x-pack/plugins/infra/public/alerting/metric_anomaly/components/validation.tsx +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import type { ValidationResult } from '@kbn/triggers-actions-ui-plugin/public'; - -export function validateMetricAnomaly({ - hasInfraMLCapabilities, -}: { - hasInfraMLCapabilities: boolean; -}): ValidationResult { - const validationResult = { errors: {} }; - const errors: { - hasInfraMLCapabilities: string[]; - } = { - hasInfraMLCapabilities: [], - }; - - validationResult.errors = errors; - - if (!hasInfraMLCapabilities) { - errors.hasInfraMLCapabilities.push( - i18n.translate('xpack.infra.metrics.alertFlyout.error.mlCapabilitiesRequired', { - defaultMessage: 'Cannot create an anomaly alert when machine learning is disabled.', - }) - ); - } - - return validationResult; -} diff --git a/x-pack/plugins/infra/public/alerting/metric_anomaly/index.ts b/x-pack/plugins/infra/public/alerting/metric_anomaly/index.ts deleted file mode 100644 index 2dfee3891b86b..0000000000000 --- a/x-pack/plugins/infra/public/alerting/metric_anomaly/index.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import React from 'react'; -import { RuleTypeModel } from '@kbn/triggers-actions-ui-plugin/public'; -import { RuleTypeParams } from '@kbn/alerting-plugin/common'; -import { METRIC_ANOMALY_ALERT_TYPE_ID } from '../../../common/alerting/metrics'; -import { validateMetricAnomaly } from './components/validation'; - -interface MetricAnomalyRuleTypeParams extends RuleTypeParams { - hasInfraMLCapabilities: boolean; -} - -export function createMetricAnomalyRuleType(): RuleTypeModel { - return { - id: METRIC_ANOMALY_ALERT_TYPE_ID, - description: i18n.translate('xpack.infra.metrics.anomaly.alertFlyout.alertDescription', { - defaultMessage: 'Alert when the anomaly score exceeds a defined threshold.', - }), - iconClass: 'bell', - documentationUrl(docLinks) { - return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/observability/${docLinks.DOC_LINK_VERSION}/infrastructure-anomaly-alert.html`; - }, - ruleParamsExpression: React.lazy(() => import('./components/expression')), - validate: validateMetricAnomaly, - defaultActionMessage: i18n.translate( - 'xpack.infra.metrics.alerting.anomaly.defaultActionMessage', - { - defaultMessage: `\\{\\{alertName\\}\\} is in a state of \\{\\{context.alertState\\}\\} - -\\{\\{context.metric\\}\\} was \\{\\{context.summary\\}\\} than normal at \\{\\{context.timestamp\\}\\} - -Typical value: \\{\\{context.typical\\}\\} -Actual value: \\{\\{context.actual\\}\\} -`, - } - ), - requiresAppContext: false, - }; -} diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/alerts.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/alerts.tsx index 2fa09451118cb..1dda6d6ac7a46 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/alerts.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/alerts.tsx @@ -9,6 +9,7 @@ import React, { useMemo } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import { useSummaryTimeRange } from '@kbn/observability-plugin/public'; import type { TimeRange } from '@kbn/es-query'; +import { usePluginConfig } from '../../../../containers/plugin_config_context'; import type { AlertsEsQuery } from '../../../../common/alerts/types'; import type { InventoryItemType } from '../../../../../common/inventory_models/types'; import { findInventoryFields } from '../../../../../common/inventory_models'; @@ -32,6 +33,7 @@ export const AlertsSummaryContent = ({ assetType: InventoryItemType; dateRange: TimeRange; }) => { + const { featureFlags } = usePluginConfig(); const [isAlertFlyoutVisible, { toggle: toggleAlertFlyout }] = useBoolean(false); const { overrides } = useAssetDetailsRenderPropsContext(); @@ -51,9 +53,11 @@ export const AlertsSummaryContent = ({ - - - + {featureFlags.inventoryThresholdAlertRuleEnabled && ( + + + + )} - + + {featureFlags.inventoryThresholdAlertRuleEnabled && ( + + )} ); }; diff --git a/x-pack/plugins/infra/public/containers/plugin_config_context.test.tsx b/x-pack/plugins/infra/public/containers/plugin_config_context.test.tsx index 70b3cf466f749..a8afb67fb6e32 100644 --- a/x-pack/plugins/infra/public/containers/plugin_config_context.test.tsx +++ b/x-pack/plugins/infra/public/containers/plugin_config_context.test.tsx @@ -24,6 +24,9 @@ describe('usePluginConfig()', () => { logsUIEnabled: false, metricsExplorerEnabled: false, osqueryEnabled: false, + inventoryThresholdAlertRuleEnabled: true, + metricThresholdAlertRuleEnabled: true, + logThresholdAlertRuleEnabled: true, }, }; const { result } = renderHook(() => usePluginConfig(), { diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_rule_type.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_rule_type.ts index d956b30940f4c..a1381f9679d9b 100644 --- a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_rule_type.ts +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_rule_type.ts @@ -11,6 +11,7 @@ import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; import { GetViewInAppRelativeUrlFnOpts, PluginSetupContract } from '@kbn/alerting-plugin/server'; import { observabilityPaths } from '@kbn/observability-plugin/common'; import { TimeUnitChar } from '@kbn/observability-plugin/common/utils/formatters/duration'; +import type { InfraConfig } from '../../../../common/plugin_config_types'; import { Comparator, METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID, @@ -81,10 +82,15 @@ const groupActionVariableDescription = i18n.translate( } ); -export async function registerMetricInventoryThresholdRuleType( +export async function registerInventoryThresholdRuleType( alertingPlugin: PluginSetupContract, - libs: InfraBackendLibs + libs: InfraBackendLibs, + { featureFlags }: InfraConfig ) { + if (!featureFlags.inventoryThresholdAlertRuleEnabled) { + return; + } + alertingPlugin.registerType({ id: METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID, name: i18n.translate('xpack.infra.metrics.inventory.alertName', { diff --git a/x-pack/plugins/infra/server/lib/alerting/log_threshold/register_log_threshold_rule_type.ts b/x-pack/plugins/infra/server/lib/alerting/log_threshold/register_log_threshold_rule_type.ts index 40848b9a109ed..f16e7dfd284d2 100644 --- a/x-pack/plugins/infra/server/lib/alerting/log_threshold/register_log_threshold_rule_type.ts +++ b/x-pack/plugins/infra/server/lib/alerting/log_threshold/register_log_threshold_rule_type.ts @@ -9,6 +9,7 @@ import { i18n } from '@kbn/i18n'; import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; import { GetViewInAppRelativeUrlFnOpts, PluginSetupContract } from '@kbn/alerting-plugin/server'; import { observabilityPaths } from '@kbn/observability-plugin/common'; +import type { InfraConfig } from '../../../../common/plugin_config_types'; import { O11Y_AAD_FIELDS } from '../../../../common/constants'; import { createLogThresholdExecutor, FIRED_ACTIONS } from './log_threshold_executor'; import { extractReferences, injectReferences } from './log_threshold_references_manager'; @@ -103,8 +104,13 @@ const viewInAppUrlActionVariableDescription = i18n.translate( export async function registerLogThresholdRuleType( alertingPlugin: PluginSetupContract, - libs: InfraBackendLibs + libs: InfraBackendLibs, + { featureFlags }: InfraConfig ) { + if (!featureFlags.logThresholdAlertRuleEnabled) { + return; + } + if (!alertingPlugin) { throw new Error( 'Cannot register log threshold alert type. Both the actions and alerting plugins need to be enabled.' diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/evaluate_condition.ts b/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/evaluate_condition.ts deleted file mode 100644 index 362cf0bc5a073..0000000000000 --- a/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/evaluate_condition.ts +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { MetricAnomalyParams } from '../../../../common/alerting/metrics'; -import { getMetricsHostsAnomalies, getMetricK8sAnomalies } from '../../infra_ml'; -import { MlSystem, MlAnomalyDetectors } from '../../../types'; - -type ConditionParams = Omit & { - spaceId: string; - startTime: number; - endTime: number; - mlSystem: MlSystem; - mlAnomalyDetectors: MlAnomalyDetectors; -}; - -export const evaluateCondition = async ({ - nodeType, - spaceId, - sourceId, - mlSystem, - mlAnomalyDetectors, - startTime, - endTime, - metric, - threshold, - influencerFilter, -}: ConditionParams) => { - const getAnomalies = nodeType === 'k8s' ? getMetricK8sAnomalies : getMetricsHostsAnomalies; - - const result = await getAnomalies({ - context: { - spaceId, - mlSystem, - mlAnomalyDetectors, - }, - sourceId: sourceId ?? 'default', - anomalyThreshold: threshold, - startTime, - endTime, - metric, - sort: { field: 'anomalyScore', direction: 'desc' }, - pagination: { pageSize: 100 }, - influencerFilter, - }); - - return result; -}; diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/metric_anomaly_executor.ts b/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/metric_anomaly_executor.ts deleted file mode 100644 index b6d583cb17e6b..0000000000000 --- a/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/metric_anomaly_executor.ts +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import { KibanaRequest } from '@kbn/core/server'; -import { first } from 'lodash'; -import moment from 'moment'; -import { - ActionGroup, - AlertInstanceContext as AlertContext, - AlertInstanceState as AlertState, -} from '@kbn/alerting-plugin/common'; -import { RuleExecutorOptions } from '@kbn/alerting-plugin/server'; -import { MlPluginSetup } from '@kbn/ml-plugin/server'; -import { AlertStates, MetricAnomalyParams } from '../../../../common/alerting/metrics'; -import { getIntervalInSeconds } from '../../../../common/utils/get_interval_in_seconds'; -import { MappedAnomalyHit } from '../../infra_ml'; -import { InfraBackendLibs } from '../../infra_types'; -import { stateToAlertMessage } from '../common/messages'; -import { evaluateCondition } from './evaluate_condition'; -import { MetricAnomalyAllowedActionGroups } from './register_metric_anomaly_rule_type'; - -export const createMetricAnomalyExecutor = - (_libs: InfraBackendLibs, ml?: MlPluginSetup) => - async ({ - services, - params, - startedAt, - }: RuleExecutorOptions< - /** - * TODO: Remove this use of `any` by utilizing a proper type - */ - Record, - Record, - AlertState, - AlertContext, - MetricAnomalyAllowedActionGroups - >) => { - if (!ml) { - return { state: {} }; - } - const request = {} as KibanaRequest; - const mlSystem = ml.mlSystemProvider(request, services.savedObjectsClient); - const mlAnomalyDetectors = ml.anomalyDetectorsProvider(request, services.savedObjectsClient); - - const { metric, alertInterval, influencerFilter, sourceId, spaceId, nodeType, threshold } = - params as MetricAnomalyParams; - - const bucketInterval = getIntervalInSeconds('15m') * 1000; - const alertIntervalInMs = getIntervalInSeconds(alertInterval ?? '1m') * 1000; - - const endTime = startedAt.getTime(); - // Anomalies are bucketed at :00, :15, :30, :45 minutes every hour - const previousBucketStartTime = endTime - (endTime % bucketInterval); - - // If the alert interval is less than 15m, make sure that it actually queries an anomaly bucket - const startTime = Math.min(endTime - alertIntervalInMs, previousBucketStartTime); - - const { data } = await evaluateCondition({ - sourceId: sourceId ?? 'default', - spaceId: spaceId ?? 'default', - mlSystem, - mlAnomalyDetectors, - startTime, - endTime, - metric, - threshold, - nodeType, - influencerFilter, - }); - - const shouldAlertFire = data.length > 0; - - if (shouldAlertFire) { - const { - startTime: anomalyStartTime, - anomalyScore, - actual, - typical, - influencers, - } = first(data as MappedAnomalyHit[])!; - const alert = services.alertFactory.create(`${nodeType}-${metric}`); - - alert.scheduleActions(FIRED_ACTIONS_ID, { - alertState: stateToAlertMessage[AlertStates.ALERT], - timestamp: moment(anomalyStartTime).toISOString(), - anomalyScore, - actual, - typical, - metric: metricNameMap[metric], - summary: generateSummaryMessage(actual, typical), - influencers: influencers.join(', '), - }); - } - - return { state: {} }; - }; - -export const FIRED_ACTIONS_ID = 'metrics.anomaly.fired'; -export const FIRED_ACTIONS: ActionGroup = { - id: FIRED_ACTIONS_ID, - name: i18n.translate('xpack.infra.metrics.alerting.anomaly.fired', { - defaultMessage: 'Fired', - }), -}; - -const generateSummaryMessage = (actual: number, typical: number) => { - const differential = (Math.max(actual, typical) / Math.min(actual, typical)) - .toFixed(1) - .replace('.0', ''); - if (actual > typical) { - return i18n.translate('xpack.infra.metrics.alerting.anomaly.summaryHigher', { - defaultMessage: '{differential}x higher', - values: { - differential, - }, - }); - } else { - return i18n.translate('xpack.infra.metrics.alerting.anomaly.summaryLower', { - defaultMessage: '{differential}x lower', - values: { - differential, - }, - }); - } -}; - -const metricNameMap = { - memory_usage: i18n.translate('xpack.infra.metrics.alerting.anomaly.memoryUsage', { - defaultMessage: 'Memory usage', - }), - network_in: i18n.translate('xpack.infra.metrics.alerting.anomaly.networkIn', { - defaultMessage: 'Network in', - }), - network_out: i18n.translate('xpack.infra.metrics.alerting.anomaly.networkOut', { - defaultMessage: 'Network out', - }), -}; diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/preview_metric_anomaly_alert.ts b/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/preview_metric_anomaly_alert.ts deleted file mode 100644 index 5c55fa3499202..0000000000000 --- a/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/preview_metric_anomaly_alert.ts +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { Unit } from '@kbn/datemath'; -import { countBy } from 'lodash'; -import { - isTooManyBucketsPreviewException, - MetricAnomalyParams, - TOO_MANY_BUCKETS_PREVIEW_EXCEPTION, -} from '../../../../common/alerting/metrics'; -import { getIntervalInSeconds } from '../../../../common/utils/get_interval_in_seconds'; -import { MlAnomalyDetectors, MlSystem } from '../../../types'; -import { MappedAnomalyHit } from '../../infra_ml'; -import { evaluateCondition } from './evaluate_condition'; - -interface PreviewMetricAnomalyAlertParams { - mlSystem: MlSystem; - mlAnomalyDetectors: MlAnomalyDetectors; - spaceId: string; - params: MetricAnomalyParams; - sourceId: string; - lookback: Unit; - alertInterval: string; - alertThrottle: string; - alertOnNoData: boolean; - alertNotifyWhen: string; -} - -export const previewMetricAnomalyAlert = async ({ - mlSystem, - mlAnomalyDetectors, - spaceId, - params, - sourceId, - lookback, - alertInterval, - alertThrottle, - alertNotifyWhen, -}: PreviewMetricAnomalyAlertParams) => { - const { metric, threshold, influencerFilter, nodeType } = params as MetricAnomalyParams; - - const alertIntervalInSeconds = getIntervalInSeconds(alertInterval); - const throttleIntervalInSeconds = getIntervalInSeconds(alertThrottle); - - const lookbackInterval = `1${lookback}`; - const lookbackIntervalInSeconds = getIntervalInSeconds(lookbackInterval); - const endTime = Date.now(); - const startTime = endTime - lookbackIntervalInSeconds * 1000; - - const numberOfExecutions = Math.floor(lookbackIntervalInSeconds / alertIntervalInSeconds); - const bucketIntervalInSeconds = getIntervalInSeconds('15m'); - const bucketsPerExecution = Math.max( - 1, - Math.floor(alertIntervalInSeconds / bucketIntervalInSeconds) - ); - - try { - let anomalies: MappedAnomalyHit[] = []; - const { data } = await evaluateCondition({ - nodeType, - spaceId, - sourceId, - mlSystem, - mlAnomalyDetectors, - startTime, - endTime, - metric, - threshold, - influencerFilter, - }); - anomalies = [...anomalies, ...data]; - - const anomaliesByTime = countBy(anomalies, ({ startTime: anomStartTime }) => anomStartTime); - - let numberOfTimesFired = 0; - let numberOfNotifications = 0; - let throttleTracker = 0; - let previousActionGroup: string | null = null; - const notifyWithThrottle = (actionGroup: string) => { - if (alertNotifyWhen === 'onActionGroupChange') { - if (previousActionGroup !== actionGroup) numberOfNotifications++; - } else if (alertNotifyWhen === 'onThrottleInterval') { - if (throttleTracker === 0) numberOfNotifications++; - throttleTracker += alertIntervalInSeconds; - } else { - numberOfNotifications++; - } - previousActionGroup = actionGroup; - }; - // Mock each alert evaluation - for (let i = 0; i < numberOfExecutions; i++) { - const executionTime = startTime + alertIntervalInSeconds * 1000 * i; - // Get an array of bucket times this mock alert evaluation will be looking at - // Anomalies are bucketed at :00, :15, :30, :45 minutes every hour, - // so this is an array of how many of those times occurred between this evaluation - // and the previous one - const bucketsLookedAt = Array.from(Array(bucketsPerExecution), (_, idx) => { - const previousBucketStartTime = - executionTime - - (executionTime % (bucketIntervalInSeconds * 1000)) - - idx * bucketIntervalInSeconds * 1000; - return previousBucketStartTime; - }); - const anomaliesDetectedInBuckets = bucketsLookedAt.some((bucketTime) => - Reflect.has(anomaliesByTime, bucketTime) - ); - - if (anomaliesDetectedInBuckets) { - numberOfTimesFired++; - notifyWithThrottle('fired'); - } else { - previousActionGroup = 'recovered'; - if (throttleTracker > 0) { - throttleTracker += alertIntervalInSeconds; - } - } - if (throttleTracker >= throttleIntervalInSeconds) { - throttleTracker = 0; - } - } - - return { fired: numberOfTimesFired, notifications: numberOfNotifications }; - } catch (e) { - if (!isTooManyBucketsPreviewException(e)) throw e; - const { maxBuckets } = e; - throw new Error(`${TOO_MANY_BUCKETS_PREVIEW_EXCEPTION}:${maxBuckets}`); - } -}; diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/register_metric_anomaly_rule_type.ts b/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/register_metric_anomaly_rule_type.ts deleted file mode 100644 index dc3fd1b28546c..0000000000000 --- a/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/register_metric_anomaly_rule_type.ts +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; -import { schema } from '@kbn/config-schema'; -import { i18n } from '@kbn/i18n'; -import { MlPluginSetup } from '@kbn/ml-plugin/server'; -import { - RuleType, - AlertInstanceState as AlertState, - AlertInstanceContext as AlertContext, - GetViewInAppRelativeUrlFnOpts, -} from '@kbn/alerting-plugin/server'; -import { RecoveredActionGroupId } from '@kbn/alerting-plugin/common'; -import { observabilityPaths } from '@kbn/observability-plugin/common'; -import { O11Y_AAD_FIELDS } from '../../../../common/constants'; -import { - createMetricAnomalyExecutor, - FIRED_ACTIONS, - FIRED_ACTIONS_ID, -} from './metric_anomaly_executor'; -import { METRIC_ANOMALY_ALERT_TYPE_ID } from '../../../../common/alerting/metrics'; -import { InfraBackendLibs } from '../../infra_types'; -import { oneOfLiterals, validateIsStringElasticsearchJSONFilter } from '../common/utils'; -import { alertStateActionVariableDescription } from '../common/messages'; - -export type MetricAnomalyAllowedActionGroups = typeof FIRED_ACTIONS_ID; - -export const registerMetricAnomalyRuleType = ( - libs: InfraBackendLibs, - ml?: MlPluginSetup -): RuleType< - /** - * TODO: Remove this use of `any` by utilizing a proper type - */ - Record, - never, // Only use if defining useSavedObjectReferences hook - Record, - AlertState, - AlertContext, - MetricAnomalyAllowedActionGroups, - RecoveredActionGroupId -> => ({ - id: METRIC_ANOMALY_ALERT_TYPE_ID, - name: i18n.translate('xpack.infra.metrics.anomaly.alertName', { - defaultMessage: 'Infrastructure anomaly', - }), - validate: { - params: schema.object( - { - nodeType: oneOfLiterals(['hosts', 'k8s']), - alertInterval: schema.string(), - metric: oneOfLiterals(['memory_usage', 'network_in', 'network_out']), - threshold: schema.number(), - filterQuery: schema.maybe( - schema.string({ validate: validateIsStringElasticsearchJSONFilter }) - ), - sourceId: schema.string(), - spaceId: schema.string(), - }, - { unknowns: 'allow' } - ), - }, - defaultActionGroupId: FIRED_ACTIONS_ID, - actionGroups: [FIRED_ACTIONS], - category: DEFAULT_APP_CATEGORIES.observability.id, - producer: 'infrastructure', - minimumLicenseRequired: 'basic', - isExportable: true, - executor: createMetricAnomalyExecutor(libs, ml), - fieldsForAAD: O11Y_AAD_FIELDS, - actionVariables: { - context: [ - { name: 'alertState', description: alertStateActionVariableDescription }, - { - name: 'metric', - description: i18n.translate('xpack.infra.metrics.alerting.anomalyMetricDescription', { - defaultMessage: 'The metric name in the specified condition.', - }), - }, - { - name: 'timestamp', - description: i18n.translate('xpack.infra.metrics.alerting.anomalyTimestampDescription', { - defaultMessage: 'A timestamp of when the anomaly was detected.', - }), - }, - { - name: 'anomalyScore', - description: i18n.translate('xpack.infra.metrics.alerting.anomalyScoreDescription', { - defaultMessage: 'The exact severity score of the detected anomaly.', - }), - }, - { - name: 'actual', - description: i18n.translate('xpack.infra.metrics.alerting.anomalyActualDescription', { - defaultMessage: 'The actual value of the monitored metric at the time of the anomaly.', - }), - }, - { - name: 'typical', - description: i18n.translate('xpack.infra.metrics.alerting.anomalyTypicalDescription', { - defaultMessage: 'The typical value of the monitored metric at the time of the anomaly.', - }), - }, - { - name: 'summary', - description: i18n.translate('xpack.infra.metrics.alerting.anomalySummaryDescription', { - defaultMessage: 'A description of the anomaly, e.g. "2x higher."', - }), - }, - { - name: 'influencers', - description: i18n.translate('xpack.infra.metrics.alerting.anomalyInfluencersDescription', { - defaultMessage: 'A list of node names that influenced the anomaly.', - }), - }, - ], - }, - getViewInAppRelativeUrl: ({ rule }: GetViewInAppRelativeUrlFnOpts<{}>) => - observabilityPaths.ruleDetails(rule.id), -}); diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts index b3b82602f11f1..f7052b3e1916f 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts @@ -1903,6 +1903,9 @@ const createMockStaticConfiguration = (sources: any): InfraConfig => ({ logsUIEnabled: true, metricsExplorerEnabled: true, osqueryEnabled: true, + inventoryThresholdAlertRuleEnabled: true, + metricThresholdAlertRuleEnabled: true, + logThresholdAlertRuleEnabled: true, }, enabled: true, sources, diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_rule_type.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_rule_type.ts index ad6429eb2ba0f..e7ea693a0e74d 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_rule_type.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_rule_type.ts @@ -15,6 +15,7 @@ import { RuleType, } from '@kbn/alerting-plugin/server'; import { observabilityPaths } from '@kbn/observability-plugin/common'; +import type { InfraConfig } from '../../../../common/plugin_config_types'; import { Comparator, METRIC_THRESHOLD_ALERT_TYPE_ID } from '../../../../common/alerting/metrics'; import { METRIC_EXPLORER_AGGREGATIONS } from '../../../../common/http_api'; import { InfraBackendLibs } from '../../infra_types'; @@ -56,8 +57,13 @@ export type MetricThresholdAlertType = Omit & { export async function registerMetricThresholdRuleType( alertingPlugin: PluginSetupContract, - libs: InfraBackendLibs + libs: InfraBackendLibs, + { featureFlags }: InfraConfig ) { + if (!featureFlags.metricThresholdAlertRuleEnabled) { + return; + } + const baseCriterion = { threshold: schema.arrayOf(schema.number()), comparator: oneOfLiterals(Object.values(Comparator)), diff --git a/x-pack/plugins/infra/server/lib/alerting/register_rule_types.ts b/x-pack/plugins/infra/server/lib/alerting/register_rule_types.ts index ee05dc38cc1f5..36c836fc50aa7 100644 --- a/x-pack/plugins/infra/server/lib/alerting/register_rule_types.ts +++ b/x-pack/plugins/infra/server/lib/alerting/register_rule_types.ts @@ -7,12 +7,11 @@ import { legacyExperimentalFieldMap } from '@kbn/alerts-as-data-utils'; import { type IRuleTypeAlerts, PluginSetupContract } from '@kbn/alerting-plugin/server'; -import { MlPluginSetup } from '@kbn/ml-plugin/server'; import { registerMetricThresholdRuleType } from './metric_threshold/register_metric_threshold_rule_type'; -import { registerMetricInventoryThresholdRuleType } from './inventory_metric_threshold/register_inventory_metric_threshold_rule_type'; -import { registerMetricAnomalyRuleType } from './metric_anomaly/register_metric_anomaly_rule_type'; +import { registerInventoryThresholdRuleType } from './inventory_metric_threshold/register_inventory_metric_threshold_rule_type'; import { registerLogThresholdRuleType } from './log_threshold/register_log_threshold_rule_type'; import { InfraBackendLibs } from '../infra_types'; +import type { InfraConfig } from '../../types'; export const LOGS_RULES_ALERT_CONTEXT = 'observability.logs'; // Defines which alerts-as-data index logs rules will use @@ -35,18 +34,16 @@ export const MetricsRulesTypeAlertDefinition: IRuleTypeAlerts = { const registerRuleTypes = ( alertingPlugin: PluginSetupContract, libs: InfraBackendLibs, - ml?: MlPluginSetup + config: InfraConfig ) => { if (alertingPlugin) { - alertingPlugin.registerType(registerMetricAnomalyRuleType(libs, ml)); - const registerFns = [ registerLogThresholdRuleType, - registerMetricInventoryThresholdRuleType, + registerInventoryThresholdRuleType, registerMetricThresholdRuleType, ]; registerFns.forEach((fn) => { - fn(alertingPlugin, libs); + fn(alertingPlugin, libs, config); }); } }; diff --git a/x-pack/plugins/infra/server/lib/sources/sources.test.ts b/x-pack/plugins/infra/server/lib/sources/sources.test.ts index d9e3e3ee4dbac..bf31f4ed099d8 100644 --- a/x-pack/plugins/infra/server/lib/sources/sources.test.ts +++ b/x-pack/plugins/infra/server/lib/sources/sources.test.ts @@ -130,6 +130,9 @@ const createMockStaticConfiguration = (sources: any): InfraConfig => ({ logsUIEnabled: true, metricsExplorerEnabled: true, osqueryEnabled: true, + inventoryThresholdAlertRuleEnabled: true, + metricThresholdAlertRuleEnabled: true, + logThresholdAlertRuleEnabled: true, }, sources, enabled: true, diff --git a/x-pack/plugins/infra/server/plugin.ts b/x-pack/plugins/infra/server/plugin.ts index 04a57f294303f..ed9bf805b2b6a 100644 --- a/x-pack/plugins/infra/server/plugin.ts +++ b/x-pack/plugins/infra/server/plugin.ts @@ -97,6 +97,18 @@ export const config: PluginConfigDescriptor = { traditional: schema.boolean({ defaultValue: true }), serverless: schema.boolean({ defaultValue: false }), }), + inventoryThresholdAlertRuleEnabled: offeringBasedSchema({ + traditional: schema.boolean({ defaultValue: true }), + serverless: schema.boolean({ defaultValue: false }), + }), + metricThresholdAlertRuleEnabled: offeringBasedSchema({ + traditional: schema.boolean({ defaultValue: true }), + serverless: schema.boolean({ defaultValue: false }), + }), + logThresholdAlertRuleEnabled: offeringBasedSchema({ + traditional: schema.boolean({ defaultValue: true }), + serverless: schema.boolean({ defaultValue: false }), + }), }), }), deprecations: configDeprecations, @@ -238,7 +250,7 @@ export class InfraServerPlugin } initInfraServer(this.libs); - registerRuleTypes(plugins.alerting, this.libs, plugins.ml); + registerRuleTypes(plugins.alerting, this.libs, this.config); core.http.registerRouteHandlerContext( 'infra', diff --git a/x-pack/plugins/observability/common/custom_threshold_rule/types.ts b/x-pack/plugins/observability/common/custom_threshold_rule/types.ts index 66e058dfad8cf..dc5b434e0a7e9 100644 --- a/x-pack/plugins/observability/common/custom_threshold_rule/types.ts +++ b/x-pack/plugins/observability/common/custom_threshold_rule/types.ts @@ -166,7 +166,6 @@ export enum MetricsExplorerChartType { export enum InfraRuleType { MetricThreshold = 'metrics.alert.threshold', InventoryThreshold = 'metrics.alert.inventory.threshold', - Anomaly = 'metrics.alert.anomaly', } export enum AlertStates { diff --git a/x-pack/plugins/observability/server/lib/rules/custom_threshold/types.ts b/x-pack/plugins/observability/server/lib/rules/custom_threshold/types.ts index cc63f2cd688d3..719eddbd0e646 100644 --- a/x-pack/plugins/observability/server/lib/rules/custom_threshold/types.ts +++ b/x-pack/plugins/observability/server/lib/rules/custom_threshold/types.ts @@ -14,7 +14,6 @@ import { TimeUnitChar } from '../../../../common'; export enum InfraRuleType { MetricThreshold = 'metrics.alert.threshold', InventoryThreshold = 'metrics.alert.inventory.threshold', - Anomaly = 'metrics.alert.anomaly', } export enum AlertStates { diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index f3514ba7fbb65..34c7139f94575 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -18480,8 +18480,6 @@ "xpack.infra.metrics.alertFlyout.customEquationEditor.fieldLabel": "Champ {name}", "xpack.infra.metrics.alertFlyout.customEquationEditor.filterLabel": "Filtre KQL {name}", "xpack.infra.metrics.alertFlyout.ofExpression.helpTextDetail": "Vous ne trouvez pas un indicateur ? {documentationLink}.", - "xpack.infra.metrics.alerting.anomaly.summaryHigher": "{differential}x plus élevé", - "xpack.infra.metrics.alerting.anomaly.summaryLower": "{differential}x plus bas", "xpack.infra.metrics.alerting.threshold.errorAlertReason": "Elasticsearch a échoué lors de l'interrogation des données pour {metric}", "xpack.infra.metrics.alerting.threshold.firedAlertReason": "{metric} est {currentValue} dans les dernières {duration}{group}. Alerte lorsque {comparator} {threshold}.", "xpack.infra.metrics.alerting.threshold.noDataAlertReason": "{metric} n'a signalé aucune donnée dans les dernières {interval} {group}", @@ -19062,12 +19060,6 @@ "xpack.infra.metrics.alertFlyout.alertOnGroupDisappear": "Me prévenir si un groupe cesse de signaler les données", "xpack.infra.metrics.alertFlyout.alertOnNoData": "M'alerter s'il n'y a aucune donnée", "xpack.infra.metrics.alertFlyout.alertPerRedundantFilterError.docsLink": "les documents", - "xpack.infra.metrics.alertFlyout.anomalyFilterHelpText": "Limitez la portée de votre déclenchement d'alerte aux anomalies influencées par certains nœuds.", - "xpack.infra.metrics.alertFlyout.anomalyFilterHelpTextExample": "Par exemple : \"my-node-1\" ou \"my-node-*\"", - "xpack.infra.metrics.alertFlyout.anomalyInfluencerFilterPlaceholder": "Tout", - "xpack.infra.metrics.alertFlyout.anomalyJobs.memoryUsage": "Utilisation mémoire", - "xpack.infra.metrics.alertFlyout.anomalyJobs.networkIn": "Entrée réseau", - "xpack.infra.metrics.alertFlyout.anomalyJobs.networkOut": "Sortie réseau", "xpack.infra.metrics.alertFlyout.conditions": "Conditions", "xpack.infra.metrics.alertFlyout.createAlertPerHelpText": "Créer une alerte pour chaque valeur unique. Par exemple : \"host.id\" ou \"cloud.region\".", "xpack.infra.metrics.alertFlyout.createAlertPerText": "Regrouper les alertes par (facultatif)", @@ -19087,7 +19079,6 @@ "xpack.infra.metrics.alertFlyout.error.equation.invalidCharacters": "Le champ d'équation prend en charge uniquement les caractères suivants : A-Z, +, -, /, *, (, ), ?, !, &, :, |, >, <, =", "xpack.infra.metrics.alertFlyout.error.invalidFilterQuery": "La requête de filtre n'est pas valide.", "xpack.infra.metrics.alertFlyout.error.metricRequired": "L'indicateur est requis.", - "xpack.infra.metrics.alertFlyout.error.mlCapabilitiesRequired": "Impossible de créer une alerte d'anomalie lors que le Machine Learning est désactivé.", "xpack.infra.metrics.alertFlyout.error.thresholdRequired": "Le seuil est requis.", "xpack.infra.metrics.alertFlyout.error.thresholdTypeRequired": "Les seuils doivent contenir un nombre valide.", "xpack.infra.metrics.alertFlyout.error.timeRequred": "La taille de temps est requise.", @@ -19097,13 +19088,6 @@ "xpack.infra.metrics.alertFlyout.expression.metric.popoverTitle": "Indicateur", "xpack.infra.metrics.alertFlyout.expression.metric.selectFieldLabel": "Sélectionner un indicateur", "xpack.infra.metrics.alertFlyout.expression.metric.whenLabel": "Quand", - "xpack.infra.metrics.alertFlyout.expression.severityScore.criticalLabel": "Critique", - "xpack.infra.metrics.alertFlyout.expression.severityScore.descriptionLabel": "Le score de sévérité est supérieur à", - "xpack.infra.metrics.alertFlyout.expression.severityScore.majorLabel": "Majeur", - "xpack.infra.metrics.alertFlyout.expression.severityScore.minorLabel": "Mineur", - "xpack.infra.metrics.alertFlyout.expression.severityScore.popoverTitle": "Score de sévérité", - "xpack.infra.metrics.alertFlyout.expression.severityScore.warningLabel": "Avertissement", - "xpack.infra.metrics.alertFlyout.filterByNodeLabel": "Filtrer par nœud", "xpack.infra.metrics.alertFlyout.filterHelpText": "Utilisez une expression KQL pour limiter la portée de votre déclenchement d'alerte.", "xpack.infra.metrics.alertFlyout.filterLabel": "Filtre (facultatif)", "xpack.infra.metrics.alertFlyout.groupDisappearHelpText": "Activez cette option pour déclencher l’action si un groupe précédemment détecté cesse de signaler des résultats. Ce n’est pas recommandé pour les infrastructures à montée en charge dynamique qui peuvent rapidement lancer ou stopper des nœuds automatiquement.", @@ -19115,18 +19099,6 @@ "xpack.infra.metrics.alertFlyout.warningThreshold": "Avertissement", "xpack.infra.metrics.alerting.alertDetailUrlActionVariableDescription": "Lien vers l’affichage de résolution des problèmes d’alerte pour voir plus de contextes et de détails. La chaîne sera vide si server.publicBaseUrl n'est pas configuré.", "xpack.infra.metrics.alerting.alertStateActionVariableDescription": "État actuel de l'alerte", - "xpack.infra.metrics.alerting.anomaly.defaultActionMessage": "\\{\\{alertName\\}\\} est à l'état \\{\\{context.alertState\\}\\}\n\n\\{\\{context.metric\\}\\} était \\{\\{context.summary\\}\\} que la normale à \\{\\{context.timestamp\\}\\}\n\nValeur typique : \\{\\{context.typical\\}\\}\nValeur réelle : \\{\\{context.actual\\}\\}\n", - "xpack.infra.metrics.alerting.anomaly.fired": "Déclenché", - "xpack.infra.metrics.alerting.anomaly.memoryUsage": "Utilisation mémoire", - "xpack.infra.metrics.alerting.anomaly.networkIn": "Entrée réseau", - "xpack.infra.metrics.alerting.anomaly.networkOut": "Sortie réseau", - "xpack.infra.metrics.alerting.anomalyActualDescription": "Valeur réelle de l'indicateur monitoré au moment de l'anomalie.", - "xpack.infra.metrics.alerting.anomalyInfluencersDescription": "Liste des noms de nœuds ayant influencé l'anomalie.", - "xpack.infra.metrics.alerting.anomalyMetricDescription": "Nom de l'indicateur dans la condition spécifiée.", - "xpack.infra.metrics.alerting.anomalyScoreDescription": "Score de sévérité exact de l'anomalie détectée.", - "xpack.infra.metrics.alerting.anomalySummaryDescription": "Description de l'anomalie, par ex. \"2 x plus élevé.\"", - "xpack.infra.metrics.alerting.anomalyTimestampDescription": "Horodatage du moment où l'anomalie a été détectée.", - "xpack.infra.metrics.alerting.anomalyTypicalDescription": "Valeur typique de l'indicateur monitoré au moment de l'anomalie.", "xpack.infra.metrics.alerting.cloudActionVariableDescription": "Objet cloud défini par ECS s'il est disponible dans la source.", "xpack.infra.metrics.alerting.containerActionVariableDescription": "Objet conteneur défini par ECS s'il est disponible dans la source.", "xpack.infra.metrics.alerting.groupActionVariableDescription": "Nom des données de reporting des groupes. Pour accéder à chaque clé de groupe, utilisez context.groupByKeys.", @@ -19165,8 +19137,6 @@ "xpack.infra.metrics.alerting.valueActionVariableDescription": "Valeur de l'indicateur dans la condition spécifiée. Utilisation : (ctx.value.condition0, ctx.value.condition1, etc...).", "xpack.infra.metrics.alerting.viewInAppUrlActionVariableDescription": "Lien vers la source de l’alerte", "xpack.infra.metrics.alertName": "Seuil de l'indicateur", - "xpack.infra.metrics.anomaly.alertFlyout.alertDescription": "Alerte lorsque le score d'anomalie dépasse un seuil défini.", - "xpack.infra.metrics.anomaly.alertName": "Anomalie d'infrastructure", "xpack.infra.metrics.emptyViewDescription": "Essayez d'ajuster vos heures ou votre filtre.", "xpack.infra.metrics.emptyViewTitle": "Il n'y a aucune donnée à afficher.", "xpack.infra.metrics.expressionItems.components.closablePopoverTitle.closeLabel": "Fermer", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index d078f535b6c99..3758374e85e3b 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -18494,8 +18494,6 @@ "xpack.infra.metrics.alertFlyout.customEquationEditor.fieldLabel": "フィールド{name}", "xpack.infra.metrics.alertFlyout.customEquationEditor.filterLabel": "KQLフィルター{name}", "xpack.infra.metrics.alertFlyout.ofExpression.helpTextDetail": "メトリックが見つからない場合は、{documentationLink}。", - "xpack.infra.metrics.alerting.anomaly.summaryHigher": "{differential}x高い", - "xpack.infra.metrics.alerting.anomaly.summaryLower": "{differential}x低い", "xpack.infra.metrics.alerting.threshold.errorAlertReason": "{metric}のデータのクエリを試行しているときに、Elasticsearchが失敗しました", "xpack.infra.metrics.alerting.threshold.firedAlertReason": "{metric}は最後の{duration}{group}の{currentValue}です。{comparator} {threshold}のときにアラートを通知します。", "xpack.infra.metrics.alerting.threshold.noDataAlertReason": "{metric}は最後の{interval}{group}でデータがないことを報告しました", @@ -19076,12 +19074,6 @@ "xpack.infra.metrics.alertFlyout.alertOnGroupDisappear": "グループがデータのレポートを停止する場合にアラートで通知する", "xpack.infra.metrics.alertFlyout.alertOnNoData": "データがない場合に通知する", "xpack.infra.metrics.alertFlyout.alertPerRedundantFilterError.docsLink": "ドキュメント", - "xpack.infra.metrics.alertFlyout.anomalyFilterHelpText": "アラートトリガーの範囲を、特定のノードの影響を受ける異常に制限します。", - "xpack.infra.metrics.alertFlyout.anomalyFilterHelpTextExample": "例:「my-node-1」または「my-node-*」", - "xpack.infra.metrics.alertFlyout.anomalyInfluencerFilterPlaceholder": "すべて", - "xpack.infra.metrics.alertFlyout.anomalyJobs.memoryUsage": "メモリー使用状況", - "xpack.infra.metrics.alertFlyout.anomalyJobs.networkIn": "内向きのネットワーク", - "xpack.infra.metrics.alertFlyout.anomalyJobs.networkOut": "外向きのネットワーク", "xpack.infra.metrics.alertFlyout.conditions": "条件", "xpack.infra.metrics.alertFlyout.createAlertPerHelpText": "すべての一意の値についてアラートを作成します。例:「host.id」または「cloud.region」。", "xpack.infra.metrics.alertFlyout.createAlertPerText": "アラートのグループ化条件(オプション)", @@ -19101,7 +19093,6 @@ "xpack.infra.metrics.alertFlyout.error.equation.invalidCharacters": "等式フィールドでは次の文字のみを使用できます:A-Z、+、-、/、*、(、)、?、!、&、:、|、>、<、=", "xpack.infra.metrics.alertFlyout.error.invalidFilterQuery": "フィルタークエリは無効です。", "xpack.infra.metrics.alertFlyout.error.metricRequired": "メトリックが必要です。", - "xpack.infra.metrics.alertFlyout.error.mlCapabilitiesRequired": "機械学習が無効なときには、異常アラートを作成できません。", "xpack.infra.metrics.alertFlyout.error.thresholdRequired": "しきい値が必要です。", "xpack.infra.metrics.alertFlyout.error.thresholdTypeRequired": "しきい値には有効な数値を含める必要があります。", "xpack.infra.metrics.alertFlyout.error.timeRequred": "ページサイズが必要です。", @@ -19111,13 +19102,6 @@ "xpack.infra.metrics.alertFlyout.expression.metric.popoverTitle": "メトリック", "xpack.infra.metrics.alertFlyout.expression.metric.selectFieldLabel": "メトリックを選択", "xpack.infra.metrics.alertFlyout.expression.metric.whenLabel": "タイミング", - "xpack.infra.metrics.alertFlyout.expression.severityScore.criticalLabel": "重大", - "xpack.infra.metrics.alertFlyout.expression.severityScore.descriptionLabel": "重要度スコアが超えています", - "xpack.infra.metrics.alertFlyout.expression.severityScore.majorLabel": "高", - "xpack.infra.metrics.alertFlyout.expression.severityScore.minorLabel": "低", - "xpack.infra.metrics.alertFlyout.expression.severityScore.popoverTitle": "重要度スコア", - "xpack.infra.metrics.alertFlyout.expression.severityScore.warningLabel": "警告", - "xpack.infra.metrics.alertFlyout.filterByNodeLabel": "ノードでフィルタリング", "xpack.infra.metrics.alertFlyout.filterHelpText": "KQL式を使用して、アラートトリガーの範囲を制限します。", "xpack.infra.metrics.alertFlyout.filterLabel": "フィルター(任意)", "xpack.infra.metrics.alertFlyout.groupDisappearHelpText": "以前に検出されたグループが結果を報告しなくなった場合は、これを有効にすると、アクションがトリガーされます。自動的に急速にノードを開始および停止することがある動的に拡張するインフラストラクチャーでは、これは推奨されません。", @@ -19129,18 +19113,6 @@ "xpack.infra.metrics.alertFlyout.warningThreshold": "警告", "xpack.infra.metrics.alerting.alertDetailUrlActionVariableDescription": "アラートトラブルシューティングビューにリンクして、さらに詳しい状況や詳細を確認できます。server.publicBaseUrlが構成されていない場合は、空の文字列になります。", "xpack.infra.metrics.alerting.alertStateActionVariableDescription": "現在のアラートの状態", - "xpack.infra.metrics.alerting.anomaly.defaultActionMessage": "\\{\\{alertName\\}\\}は\\{\\{context.alertState\\}\\}の状態です\n\n\\{\\{context.metric\\}\\}は\\{\\{context.timestamp\\}\\}で標準を超える\\{\\{context.summary\\}\\}でした\n\n標準の値:\\{\\{context.typical\\}\\}\n実際の値:\\{\\{context.actual\\}\\}\n", - "xpack.infra.metrics.alerting.anomaly.fired": "実行", - "xpack.infra.metrics.alerting.anomaly.memoryUsage": "メモリー使用状況", - "xpack.infra.metrics.alerting.anomaly.networkIn": "内向きのネットワーク", - "xpack.infra.metrics.alerting.anomaly.networkOut": "外向きのネットワーク", - "xpack.infra.metrics.alerting.anomalyActualDescription": "異常時に監視されたメトリックの実際の値。", - "xpack.infra.metrics.alerting.anomalyInfluencersDescription": "異常に影響したノード名のリスト。", - "xpack.infra.metrics.alerting.anomalyMetricDescription": "指定された条件のメトリック名。", - "xpack.infra.metrics.alerting.anomalyScoreDescription": "検出された異常の正確な重要度スコア。", - "xpack.infra.metrics.alerting.anomalySummaryDescription": "異常の説明。例:「2x高い」", - "xpack.infra.metrics.alerting.anomalyTimestampDescription": "異常が検出された時点のタイムスタンプ。", - "xpack.infra.metrics.alerting.anomalyTypicalDescription": "異常時に監視されたメトリックの標準の値。", "xpack.infra.metrics.alerting.cloudActionVariableDescription": "ソースで使用可能な場合に、ECSで定義されたクラウドオブジェクト。", "xpack.infra.metrics.alerting.containerActionVariableDescription": "ソースで使用可能な場合に、ECSで定義されたコンテナーオブジェクト。", "xpack.infra.metrics.alerting.groupActionVariableDescription": "データを報告するグループの名前。各グループキーにアクセスするには、context.groupByKeysを使用します。", @@ -19179,8 +19151,6 @@ "xpack.infra.metrics.alerting.valueActionVariableDescription": "指定された条件のメトリックの値。使用方法:(ctx.value.condition0、ctx.value.condition1など)。", "xpack.infra.metrics.alerting.viewInAppUrlActionVariableDescription": "アラートソースにリンク", "xpack.infra.metrics.alertName": "メトリックしきい値", - "xpack.infra.metrics.anomaly.alertFlyout.alertDescription": "異常スコアが定義されたしきい値を超えたときにアラートを発行します。", - "xpack.infra.metrics.anomaly.alertName": "インフラストラクチャーの異常", "xpack.infra.metrics.emptyViewDescription": "期間またはフィルターを調整してみてください。", "xpack.infra.metrics.emptyViewTitle": "表示するデータがありません。", "xpack.infra.metrics.expressionItems.components.closablePopoverTitle.closeLabel": "閉じる", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 3b8006085b1da..367c6d175f87f 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -18494,8 +18494,6 @@ "xpack.infra.metrics.alertFlyout.customEquationEditor.fieldLabel": "字段 {name}", "xpack.infra.metrics.alertFlyout.customEquationEditor.filterLabel": "KQL 筛选 {name}", "xpack.infra.metrics.alertFlyout.ofExpression.helpTextDetail": "找不到指标?{documentationLink}。", - "xpack.infra.metrics.alerting.anomaly.summaryHigher": "高 {differential} 倍", - "xpack.infra.metrics.alerting.anomaly.summaryLower": "低 {differential} 倍", "xpack.infra.metrics.alerting.threshold.errorAlertReason": "Elasticsearch 尝试查询 {metric} 的数据时出现故障", "xpack.infra.metrics.alerting.threshold.firedAlertReason": "过去 {duration}{group},{metric} 为 {currentValue}。{comparator} {threshold} 时告警。", "xpack.infra.metrics.alerting.threshold.noDataAlertReason": "对于 {group},{metric} 在过去 {interval}中未报告数据", @@ -19076,12 +19074,6 @@ "xpack.infra.metrics.alertFlyout.alertOnGroupDisappear": "组停止报告数据时提醒我", "xpack.infra.metrics.alertFlyout.alertOnNoData": "没数据时提醒我", "xpack.infra.metrics.alertFlyout.alertPerRedundantFilterError.docsLink": "文档", - "xpack.infra.metrics.alertFlyout.anomalyFilterHelpText": "将告警触发的范围限定在特定节点影响的异常。", - "xpack.infra.metrics.alertFlyout.anomalyFilterHelpTextExample": "例如:“my-node-1”或“my-node-*”", - "xpack.infra.metrics.alertFlyout.anomalyInfluencerFilterPlaceholder": "所有内容", - "xpack.infra.metrics.alertFlyout.anomalyJobs.memoryUsage": "内存使用", - "xpack.infra.metrics.alertFlyout.anomalyJobs.networkIn": "网络传入", - "xpack.infra.metrics.alertFlyout.anomalyJobs.networkOut": "网络传出", "xpack.infra.metrics.alertFlyout.conditions": "条件", "xpack.infra.metrics.alertFlyout.createAlertPerHelpText": "为每个唯一值创建告警。例如:“host.id”或“cloud.region”。", "xpack.infra.metrics.alertFlyout.createAlertPerText": "告警分组依据(可选)", @@ -19101,7 +19093,6 @@ "xpack.infra.metrics.alertFlyout.error.equation.invalidCharacters": "方程字段仅支持以下字符:A-Z、+、-、/、*、(、)、?、!、&、:、|、>、<、=", "xpack.infra.metrics.alertFlyout.error.invalidFilterQuery": "筛选查询无效。", "xpack.infra.metrics.alertFlyout.error.metricRequired": "“指标”必填。", - "xpack.infra.metrics.alertFlyout.error.mlCapabilitiesRequired": "禁用 Machine Learning 时,无法创建异常告警。", "xpack.infra.metrics.alertFlyout.error.thresholdRequired": "“阈值”必填。", "xpack.infra.metrics.alertFlyout.error.thresholdTypeRequired": "阈值必须包含有效数字。", "xpack.infra.metrics.alertFlyout.error.timeRequred": "“时间大小”必填。", @@ -19111,13 +19102,6 @@ "xpack.infra.metrics.alertFlyout.expression.metric.popoverTitle": "指标", "xpack.infra.metrics.alertFlyout.expression.metric.selectFieldLabel": "选择指标", "xpack.infra.metrics.alertFlyout.expression.metric.whenLabel": "当", - "xpack.infra.metrics.alertFlyout.expression.severityScore.criticalLabel": "紧急", - "xpack.infra.metrics.alertFlyout.expression.severityScore.descriptionLabel": "严重性分数高于", - "xpack.infra.metrics.alertFlyout.expression.severityScore.majorLabel": "重大", - "xpack.infra.metrics.alertFlyout.expression.severityScore.minorLabel": "轻微", - "xpack.infra.metrics.alertFlyout.expression.severityScore.popoverTitle": "严重性分数", - "xpack.infra.metrics.alertFlyout.expression.severityScore.warningLabel": "警告", - "xpack.infra.metrics.alertFlyout.filterByNodeLabel": "按节点筛选", "xpack.infra.metrics.alertFlyout.filterHelpText": "使用 KQL 表达式限制告警触发的范围。", "xpack.infra.metrics.alertFlyout.filterLabel": "筛选(可选)", "xpack.infra.metrics.alertFlyout.groupDisappearHelpText": "启用此选项可在之前检测的组开始不报告任何数据时触发操作。不建议将此选项用于可能会快速自动启动和停止节点的动态扩展基础架构。", @@ -19129,18 +19113,6 @@ "xpack.infra.metrics.alertFlyout.warningThreshold": "警告", "xpack.infra.metrics.alerting.alertDetailUrlActionVariableDescription": "链接到告警故障排除视图获取进一步的上下文和详情。如果未配置 server.publicBaseUrl,这将为空字符串。", "xpack.infra.metrics.alerting.alertStateActionVariableDescription": "告警的当前状态", - "xpack.infra.metrics.alerting.anomaly.defaultActionMessage": "\\{\\{alertName\\}\\} 处于 \\{\\{context.alertState\\}\\} 状态\n\n\\{\\{context.metric\\}\\} 在 \\{\\{context.timestamp\\}\\}比正常\\{\\{context.summary\\}\\}\n\n典型值:\\{\\{context.typical\\}\\}\n实际值:\\{\\{context.actual\\}\\}\n", - "xpack.infra.metrics.alerting.anomaly.fired": "已触发", - "xpack.infra.metrics.alerting.anomaly.memoryUsage": "内存使用", - "xpack.infra.metrics.alerting.anomaly.networkIn": "网络传入", - "xpack.infra.metrics.alerting.anomaly.networkOut": "网络传出", - "xpack.infra.metrics.alerting.anomalyActualDescription": "在发生异常时受监测指标的实际值。", - "xpack.infra.metrics.alerting.anomalyInfluencersDescription": "影响异常的节点名称列表。", - "xpack.infra.metrics.alerting.anomalyMetricDescription": "指定条件中的指标名称。", - "xpack.infra.metrics.alerting.anomalyScoreDescription": "检测到的异常的确切严重性分数。", - "xpack.infra.metrics.alerting.anomalySummaryDescription": "异常的描述,例如“高 2 倍”。", - "xpack.infra.metrics.alerting.anomalyTimestampDescription": "检测到异常时的时间戳。", - "xpack.infra.metrics.alerting.anomalyTypicalDescription": "在发生异常时受监测指标的典型值。", "xpack.infra.metrics.alerting.cloudActionVariableDescription": "ECS 定义的云对象(如果在源中可用)。", "xpack.infra.metrics.alerting.containerActionVariableDescription": "ECS 定义的容器对象(如果在源中可用)。", "xpack.infra.metrics.alerting.groupActionVariableDescription": "报告数据的组名称。为了访问每个组密钥,请使用 context.groupByKeys。", @@ -19179,8 +19151,6 @@ "xpack.infra.metrics.alerting.valueActionVariableDescription": "指定条件中的指标值。用法:(ctx.value.condition0, ctx.value.condition1, 诸如此类)。", "xpack.infra.metrics.alerting.viewInAppUrlActionVariableDescription": "链接到告警源", "xpack.infra.metrics.alertName": "指标阈值", - "xpack.infra.metrics.anomaly.alertFlyout.alertDescription": "当异常分数超过定义的阈值时告警。", - "xpack.infra.metrics.anomaly.alertName": "基础架构异常", "xpack.infra.metrics.emptyViewDescription": "尝试调整您的时间或筛选。", "xpack.infra.metrics.emptyViewTitle": "没有可显示的数据。", "xpack.infra.metrics.expressionItems.components.closablePopoverTitle.closeLabel": "关闭", diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/check_registered_rule_types.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/check_registered_rule_types.ts index c31c7c8027495..9b68de616ee2f 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/check_registered_rule_types.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/check_registered_rule_types.ts @@ -46,7 +46,6 @@ export default function createRegisteredRuleTypeTests({ getService }: FtrProvide 'siem.newTermsRule', 'siem.notifications', 'slo.rules.burnRate', - 'metrics.alert.anomaly', 'logs.alert.document.count', 'metrics.alert.inventory.threshold', 'metrics.alert.threshold', diff --git a/x-pack/test/plugin_api_integration/test_suites/task_manager/check_registered_task_types.ts b/x-pack/test/plugin_api_integration/test_suites/task_manager/check_registered_task_types.ts index 17154d9a254c4..a8ab29da16979 100644 --- a/x-pack/test/plugin_api_integration/test_suites/task_manager/check_registered_task_types.ts +++ b/x-pack/test/plugin_api_integration/test_suites/task_manager/check_registered_task_types.ts @@ -81,7 +81,6 @@ export default function ({ getService }: FtrProviderContext) { 'alerting:apm.transaction_duration', 'alerting:apm.transaction_error_rate', 'alerting:logs.alert.document.count', - 'alerting:metrics.alert.anomaly', 'alerting:metrics.alert.inventory.threshold', 'alerting:metrics.alert.threshold', 'alerting:monitoring_alert_cluster_health', From 20e7ceabac25308b3ec155e67ab4b476ec7c153a Mon Sep 17 00:00:00 2001 From: Mykola Harmash Date: Mon, 9 Oct 2023 14:03:08 +0200 Subject: [PATCH 2/3] Rely on logThresholdAlertRuleEnab flag to initialize log alert routs --- .../infra/server/routes/log_alerts/chart_preview_data.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/plugins/infra/server/routes/log_alerts/chart_preview_data.ts b/x-pack/plugins/infra/server/routes/log_alerts/chart_preview_data.ts index 05b4452dc5557..6c5aafe34fa81 100644 --- a/x-pack/plugins/infra/server/routes/log_alerts/chart_preview_data.ts +++ b/x-pack/plugins/infra/server/routes/log_alerts/chart_preview_data.ts @@ -16,8 +16,7 @@ export const initGetLogAlertsChartPreviewDataRoute = ({ framework, getStartServices, }: Pick) => { - // Replace with the corresponding logs alert rule feature flag - if (!framework.config.featureFlags.logsUIEnabled) { + if (!framework.config.featureFlags.logThresholdAlertRuleEnabled) { return; } From 94b41b432ab098b5b39dccde1cd1c12f456d8403 Mon Sep 17 00:00:00 2001 From: Mykola Harmash Date: Mon, 9 Oct 2023 15:05:27 +0200 Subject: [PATCH 3/3] Disable threshold alert rule by default in serverless --- x-pack/plugins/infra/server/plugin.ts | 2 +- .../functional/test_suites/observability/config.ts | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/infra/server/plugin.ts b/x-pack/plugins/infra/server/plugin.ts index ed9bf805b2b6a..2dae74a2083b6 100644 --- a/x-pack/plugins/infra/server/plugin.ts +++ b/x-pack/plugins/infra/server/plugin.ts @@ -83,7 +83,7 @@ export const config: PluginConfigDescriptor = { featureFlags: schema.object({ customThresholdAlertsEnabled: offeringBasedSchema({ traditional: schema.boolean({ defaultValue: false }), - serverless: schema.boolean({ defaultValue: true }), + serverless: schema.boolean({ defaultValue: false }), }), logsUIEnabled: offeringBasedSchema({ traditional: schema.boolean({ defaultValue: true }), diff --git a/x-pack/test_serverless/functional/test_suites/observability/config.ts b/x-pack/test_serverless/functional/test_suites/observability/config.ts index 57e6894e3b892..bdfff52de245f 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/config.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/config.ts @@ -18,5 +18,9 @@ export default createTestConfig({ // include settings from project controller // https://github.com/elastic/project-controller/blob/main/internal/project/observability/config/elasticsearch.yml esServerArgs: ['xpack.ml.dfa.enabled=false', 'xpack.ml.nlp.enabled=false'], - kbnServerArgs: ['--xpack.infra.enabled=true'], + kbnServerArgs: [ + '--xpack.infra.enabled=true', + '--xpack.infra.featureFlags.customThresholdAlertsEnabled=true', + '--xpack.observability.unsafe.thresholdRule.enabled=true', + ], });