mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[AO] Add alertDetailsUrl for infra rule (#157987)
Closes #156534 ## Summary This PR adds the alertDetailsUrl to the infra rules. The value of this variable is a link to the `observability > alerts` page filtered for this instance of alert.  Here is an example of this action variable: |alertDetailsUrl as action variable|Result of action| |---|---| || **Note** - I will change this field to `kibana.alert.url` in another [ticket](https://github.com/elastic/kibana/issues/158359) ## 🧪 How to test - Ensure that `server.publicBaseUrl` is configured in kibana.dev.yml - Create a metric threshold/inventory/logs rule and use the `context.alertDetailsUrl` in action for this rule - After an alert is triggered, open the link provided by alertDetailsUrl and make sure that the alert is filtered correctly - Check the time range, it should be set for 5 mins before the alert start time --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Carlos Crespo <crespocarlos@users.noreply.github.com>
This commit is contained in:
parent
f4b88be5b2
commit
e7ddab7e57
26 changed files with 339 additions and 91 deletions
|
@ -169,6 +169,7 @@ enabled:
|
|||
- x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/config.ts
|
||||
- x-pack/test/alerting_api_integration/spaces_only/tests/actions/config.ts
|
||||
- x-pack/test/alerting_api_integration/spaces_only/tests/action_task_params/config.ts
|
||||
- x-pack/test/alerting_api_integration/observability/config.ts
|
||||
- x-pack/test/api_integration_basic/config.ts
|
||||
- x-pack/test/api_integration/config_security_basic.ts
|
||||
- x-pack/test/api_integration/config_security_trial.ts
|
||||
|
|
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
@ -970,6 +970,7 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib
|
|||
|
||||
# Response Ops team
|
||||
/x-pack/test/alerting_api_integration/ @elastic/response-ops
|
||||
/x-pack/test/alerting_api_integration/observability @elastic/actionable-observability
|
||||
/x-pack/test/plugin_api_integration/test_suites/task_manager/ @elastic/response-ops
|
||||
/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/ @elastic/response-ops
|
||||
/docs/user/alerting/ @elastic/response-ops
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { Lifecycle } from '@hapi/hapi';
|
||||
import { SharePluginSetup } from '@kbn/share-plugin/server';
|
||||
import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server';
|
||||
import { JsonArray, JsonValue } from '@kbn/utility-types';
|
||||
import { RouteConfig, RouteMethod } from '@kbn/core/server';
|
||||
|
@ -31,6 +32,7 @@ export interface InfraServerPluginSetupDeps {
|
|||
features: FeaturesPluginSetup;
|
||||
ruleRegistry: RuleRegistryPluginSetupContract;
|
||||
observability: ObservabilityPluginSetup;
|
||||
share: SharePluginSetup;
|
||||
spaces: SpacesPluginSetup;
|
||||
usageCollection: UsageCollectionSetup;
|
||||
visTypeTimeseries: VisTypeTimeseriesSetup;
|
||||
|
|
|
@ -5,12 +5,14 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import moment from 'moment';
|
||||
import { AlertsLocatorParams } from '@kbn/observability-plugin/common';
|
||||
import { LocatorPublic } from '@kbn/share-plugin/common';
|
||||
import { isEmpty, isError } from 'lodash';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { Logger, LogMeta } from '@kbn/logging';
|
||||
import type { ElasticsearchClient, IBasePath } from '@kbn/core/server';
|
||||
import { addSpaceIdToPath } from '@kbn/spaces-plugin/common';
|
||||
import { ObservabilityConfig } from '@kbn/observability-plugin/server';
|
||||
import { ALERT_RULE_PARAMETERS, TIMESTAMP } from '@kbn/rule-data-utils';
|
||||
import {
|
||||
ParsedTechnicalFields,
|
||||
|
@ -110,15 +112,6 @@ export const createScopedLogger = (
|
|||
};
|
||||
};
|
||||
|
||||
export const getAlertDetailsPageEnabledForApp = (
|
||||
config: ObservabilityConfig['unsafe']['alertDetails'] | null,
|
||||
appName: keyof ObservabilityConfig['unsafe']['alertDetails']
|
||||
): boolean => {
|
||||
if (!config) return false;
|
||||
|
||||
return config[appName].enabled;
|
||||
};
|
||||
|
||||
export const getViewInInventoryAppUrl = ({
|
||||
basePath,
|
||||
criteria,
|
||||
|
@ -153,6 +146,27 @@ export const getViewInInventoryAppUrl = ({
|
|||
export const getViewInMetricsAppUrl = (basePath: IBasePath, spaceId: string) =>
|
||||
addSpaceIdToPath(basePath.publicBaseUrl, spaceId, LINK_TO_METRICS_EXPLORER);
|
||||
|
||||
export const getAlertUrl = async (
|
||||
alertUuid: string | null,
|
||||
spaceId: string,
|
||||
startedAt: string,
|
||||
alertsLocator?: LocatorPublic<AlertsLocatorParams>,
|
||||
publicBaseUrl?: string
|
||||
) => {
|
||||
if (!publicBaseUrl || !alertsLocator || !alertUuid) return '';
|
||||
|
||||
const rangeFrom = moment(startedAt).subtract('5', 'minute').toISOString();
|
||||
|
||||
return (
|
||||
await alertsLocator.getLocation({
|
||||
baseUrl: publicBaseUrl,
|
||||
spaceId,
|
||||
kuery: `kibana.alert.uuid: "${alertUuid}"`,
|
||||
rangeFrom,
|
||||
})
|
||||
).path;
|
||||
};
|
||||
|
||||
export const getAlertDetailsUrl = (
|
||||
basePath: IBasePath,
|
||||
spaceId: string,
|
||||
|
|
|
@ -35,7 +35,7 @@ import {
|
|||
AdditionalContext,
|
||||
createScopedLogger,
|
||||
flattenAdditionalContext,
|
||||
getAlertDetailsUrl,
|
||||
getAlertUrl,
|
||||
getContextForRecoveredAlerts,
|
||||
getViewInInventoryAppUrl,
|
||||
UNGROUPED_FACTORY_KEY,
|
||||
|
@ -130,12 +130,18 @@ export const createInventoryMetricThresholdExecutor = (libs: InfraBackendLibs) =
|
|||
const actionGroupId = FIRED_ACTIONS.id; // Change this to an Error action group when able
|
||||
const reason = buildInvalidQueryAlertReason(params.filterQueryText);
|
||||
const alert = alertFactory(UNGROUPED_FACTORY_KEY, reason, actionGroupId);
|
||||
const indexedStartedDate =
|
||||
const indexedStartedAt =
|
||||
getAlertStartedDate(UNGROUPED_FACTORY_KEY) ?? startedAt.toISOString();
|
||||
const alertUuid = getAlertUuid(UNGROUPED_FACTORY_KEY);
|
||||
|
||||
alert.scheduleActions(actionGroupId, {
|
||||
alertDetailsUrl: getAlertDetailsUrl(libs.basePath, spaceId, alertUuid),
|
||||
alertDetailsUrl: await getAlertUrl(
|
||||
alertUuid,
|
||||
spaceId,
|
||||
indexedStartedAt,
|
||||
libs.alertsLocator,
|
||||
libs.basePath.publicBaseUrl
|
||||
),
|
||||
alertState: stateToAlertMessage[AlertStates.ERROR],
|
||||
group: UNGROUPED_FACTORY_KEY,
|
||||
metric: mapToConditionsLookup(criteria, (c) => c.metric),
|
||||
|
@ -146,7 +152,7 @@ export const createInventoryMetricThresholdExecutor = (libs: InfraBackendLibs) =
|
|||
basePath: libs.basePath,
|
||||
criteria,
|
||||
nodeType,
|
||||
timestamp: indexedStartedDate,
|
||||
timestamp: indexedStartedAt,
|
||||
spaceId,
|
||||
}),
|
||||
});
|
||||
|
@ -256,13 +262,19 @@ export const createInventoryMetricThresholdExecutor = (libs: InfraBackendLibs) =
|
|||
additionalContext,
|
||||
evaluationValues
|
||||
);
|
||||
const indexedStartedDate = getAlertStartedDate(group) ?? startedAt.toISOString();
|
||||
const indexedStartedAt = getAlertStartedDate(group) ?? startedAt.toISOString();
|
||||
const alertUuid = getAlertUuid(group);
|
||||
|
||||
scheduledActionsCount++;
|
||||
|
||||
const context = {
|
||||
alertDetailsUrl: getAlertDetailsUrl(libs.basePath, spaceId, alertUuid),
|
||||
alertDetailsUrl: await getAlertUrl(
|
||||
alertUuid,
|
||||
spaceId,
|
||||
indexedStartedAt,
|
||||
libs.alertsLocator,
|
||||
libs.basePath.publicBaseUrl
|
||||
),
|
||||
alertState: stateToAlertMessage[nextState],
|
||||
group,
|
||||
reason,
|
||||
|
@ -276,7 +288,7 @@ export const createInventoryMetricThresholdExecutor = (libs: InfraBackendLibs) =
|
|||
basePath: libs.basePath,
|
||||
criteria,
|
||||
nodeType,
|
||||
timestamp: indexedStartedDate,
|
||||
timestamp: indexedStartedAt,
|
||||
spaceId,
|
||||
}),
|
||||
...additionalContext,
|
||||
|
@ -290,14 +302,20 @@ export const createInventoryMetricThresholdExecutor = (libs: InfraBackendLibs) =
|
|||
|
||||
for (const alert of recoveredAlerts) {
|
||||
const recoveredAlertId = alert.getId();
|
||||
const indexedStartedDate = getAlertStartedDate(recoveredAlertId) ?? startedAt.toISOString();
|
||||
const indexedStartedAt = getAlertStartedDate(recoveredAlertId) ?? startedAt.toISOString();
|
||||
const alertUuid = getAlertUuid(recoveredAlertId);
|
||||
const alertHits = alertUuid ? await getAlertByAlertUuid(alertUuid) : undefined;
|
||||
const additionalContext = getContextForRecoveredAlerts(alertHits);
|
||||
const originalActionGroup = getOriginalActionGroup(alertHits);
|
||||
|
||||
alert.setContext({
|
||||
alertDetailsUrl: getAlertDetailsUrl(libs.basePath, spaceId, alertUuid),
|
||||
alertDetailsUrl: await getAlertUrl(
|
||||
alertUuid,
|
||||
spaceId,
|
||||
indexedStartedAt,
|
||||
libs.alertsLocator,
|
||||
libs.basePath.publicBaseUrl
|
||||
),
|
||||
alertState: stateToAlertMessage[AlertStates.OK],
|
||||
group: recoveredAlertId,
|
||||
metric: mapToConditionsLookup(criteria, (c) => c.metric),
|
||||
|
@ -307,7 +325,7 @@ export const createInventoryMetricThresholdExecutor = (libs: InfraBackendLibs) =
|
|||
basePath: libs.basePath,
|
||||
criteria,
|
||||
nodeType,
|
||||
timestamp: indexedStartedDate,
|
||||
timestamp: indexedStartedAt,
|
||||
spaceId,
|
||||
}),
|
||||
originalAlertState: translateActionGroupToAlertState(originalActionGroup),
|
||||
|
|
|
@ -41,11 +41,7 @@ import {
|
|||
valueActionVariableDescription,
|
||||
viewInAppUrlActionVariableDescription,
|
||||
} from '../common/messages';
|
||||
import {
|
||||
getAlertDetailsPageEnabledForApp,
|
||||
oneOfLiterals,
|
||||
validateIsStringElasticsearchJSONFilter,
|
||||
} from '../common/utils';
|
||||
import { oneOfLiterals, validateIsStringElasticsearchJSONFilter } from '../common/utils';
|
||||
import {
|
||||
createInventoryMetricThresholdExecutor,
|
||||
FIRED_ACTIONS,
|
||||
|
@ -86,8 +82,6 @@ export async function registerMetricInventoryThresholdRuleType(
|
|||
alertingPlugin: PluginSetupContract,
|
||||
libs: InfraBackendLibs
|
||||
) {
|
||||
const config = libs.getAlertDetailsConfig();
|
||||
|
||||
alertingPlugin.registerType({
|
||||
id: METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID,
|
||||
name: i18n.translate('xpack.infra.metrics.inventory.alertName', {
|
||||
|
@ -118,15 +112,11 @@ export async function registerMetricInventoryThresholdRuleType(
|
|||
context: [
|
||||
{ name: 'group', description: groupActionVariableDescription },
|
||||
{ name: 'alertState', description: alertStateActionVariableDescription },
|
||||
...(getAlertDetailsPageEnabledForApp(config, 'metrics')
|
||||
? [
|
||||
{
|
||||
name: 'alertDetailsUrl',
|
||||
description: alertDetailUrlActionVariableDescription,
|
||||
usesPublicBaseUrl: true,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
name: 'alertDetailsUrl',
|
||||
description: alertDetailUrlActionVariableDescription,
|
||||
usesPublicBaseUrl: true,
|
||||
},
|
||||
{ name: 'reason', description: reasonActionVariableDescription },
|
||||
{ name: 'timestamp', description: timestampActionVariableDescription },
|
||||
{ name: 'value', description: valueActionVariableDescription },
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { AlertsLocatorParams } from '@kbn/observability-plugin/common';
|
||||
import {
|
||||
ALERT_CONTEXT,
|
||||
ALERT_EVALUATION_THRESHOLD,
|
||||
|
@ -23,7 +24,9 @@ import {
|
|||
RuleExecutorServices,
|
||||
RuleTypeState,
|
||||
} from '@kbn/alerting-plugin/server';
|
||||
import { LocatorPublic } from '@kbn/share-plugin/common';
|
||||
import { addSpaceIdToPath } from '@kbn/spaces-plugin/common';
|
||||
import { asyncForEach } from '@kbn/std';
|
||||
|
||||
import { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common';
|
||||
import { ParsedExperimentalFields } from '@kbn/rule-registry-plugin/common/parse_experimental_fields';
|
||||
|
@ -57,7 +60,7 @@ import { InfraBackendLibs } from '../../infra_types';
|
|||
import {
|
||||
AdditionalContext,
|
||||
flattenAdditionalContext,
|
||||
getAlertDetailsUrl,
|
||||
getAlertUrl,
|
||||
getContextForRecoveredAlerts,
|
||||
getGroupByObject,
|
||||
unflattenObject,
|
||||
|
@ -127,7 +130,7 @@ export const createLogThresholdExecutor = (libs: InfraBackendLibs) =>
|
|||
getAlertUuid,
|
||||
getAlertByAlertUuid,
|
||||
} = services;
|
||||
const { basePath } = libs;
|
||||
const { basePath, alertsLocator } = libs;
|
||||
|
||||
const alertFactory: LogThresholdAlertFactory = (
|
||||
id,
|
||||
|
@ -168,7 +171,7 @@ export const createLogThresholdExecutor = (libs: InfraBackendLibs) =>
|
|||
viewInAppUrl,
|
||||
};
|
||||
|
||||
actions.forEach((actionSet) => {
|
||||
asyncForEach(actions, async (actionSet) => {
|
||||
const { actionGroup, context } = actionSet;
|
||||
|
||||
const alertInstanceId = (context.group || id) as string;
|
||||
|
@ -178,7 +181,13 @@ export const createLogThresholdExecutor = (libs: InfraBackendLibs) =>
|
|||
alert.scheduleActions(actionGroup, {
|
||||
...sharedContext,
|
||||
...context,
|
||||
alertDetailsUrl: getAlertDetailsUrl(libs.basePath, spaceId, alertUuid),
|
||||
alertDetailsUrl: await getAlertUrl(
|
||||
alertUuid,
|
||||
spaceId,
|
||||
indexedStartedAt,
|
||||
libs.alertsLocator,
|
||||
libs.basePath.publicBaseUrl
|
||||
),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -234,6 +243,7 @@ export const createLogThresholdExecutor = (libs: InfraBackendLibs) =>
|
|||
startedAt,
|
||||
validatedParams,
|
||||
getAlertByAlertUuid,
|
||||
alertsLocator,
|
||||
});
|
||||
} catch (e) {
|
||||
throw new Error(e);
|
||||
|
@ -997,6 +1007,7 @@ const processRecoveredAlerts = async ({
|
|||
startedAt,
|
||||
validatedParams,
|
||||
getAlertByAlertUuid,
|
||||
alertsLocator,
|
||||
}: {
|
||||
basePath: IBasePath;
|
||||
getAlertStartedDate: (alertId: string) => string | null;
|
||||
|
@ -1008,6 +1019,7 @@ const processRecoveredAlerts = async ({
|
|||
getAlertByAlertUuid: (
|
||||
alertUuid: string
|
||||
) => Promise<Partial<ParsedTechnicalFields & ParsedExperimentalFields> | null> | null;
|
||||
alertsLocator?: LocatorPublic<AlertsLocatorParams>;
|
||||
}) => {
|
||||
const groupByKeysObjectForRecovered = getGroupByObject(
|
||||
validatedParams.groupBy,
|
||||
|
@ -1024,7 +1036,13 @@ const processRecoveredAlerts = async ({
|
|||
const viewInAppUrl = addSpaceIdToPath(basePath.publicBaseUrl, spaceId, relativeViewInAppUrl);
|
||||
|
||||
const baseContext = {
|
||||
alertDetailsUrl: getAlertDetailsUrl(basePath, spaceId, alertUuid),
|
||||
alertDetailsUrl: await getAlertUrl(
|
||||
alertUuid,
|
||||
spaceId,
|
||||
indexedStartedAt,
|
||||
alertsLocator,
|
||||
basePath.publicBaseUrl
|
||||
),
|
||||
group: hasGroupBy(validatedParams) ? recoveredAlertId : null,
|
||||
groupByKeys: groupByKeysObjectForRecovered[recoveredAlertId],
|
||||
timestamp: startedAt.toISOString(),
|
||||
|
|
|
@ -15,7 +15,6 @@ import {
|
|||
} from '../../../../common/alerting/logs/log_threshold';
|
||||
import { InfraBackendLibs } from '../../infra_types';
|
||||
import { decodeOrThrow } from '../../../../common/runtime_types';
|
||||
import { getAlertDetailsPageEnabledForApp } from '../common/utils';
|
||||
import {
|
||||
alertDetailUrlActionVariableDescription,
|
||||
groupByKeysActionVariableDescription,
|
||||
|
@ -110,8 +109,6 @@ export async function registerLogThresholdRuleType(
|
|||
);
|
||||
}
|
||||
|
||||
const config = libs.getAlertDetailsConfig();
|
||||
|
||||
alertingPlugin.registerType({
|
||||
id: LOG_DOCUMENT_COUNT_RULE_TYPE_ID,
|
||||
name: i18n.translate('xpack.infra.logs.alertName', {
|
||||
|
@ -144,15 +141,11 @@ export async function registerLogThresholdRuleType(
|
|||
name: 'denominatorConditions',
|
||||
description: denominatorConditionsActionVariableDescription,
|
||||
},
|
||||
...(getAlertDetailsPageEnabledForApp(config, 'logs')
|
||||
? [
|
||||
{
|
||||
name: 'alertDetailsUrl',
|
||||
description: alertDetailUrlActionVariableDescription,
|
||||
usesPublicBaseUrl: true,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
name: 'alertDetailsUrl',
|
||||
description: alertDetailUrlActionVariableDescription,
|
||||
usesPublicBaseUrl: true,
|
||||
},
|
||||
{
|
||||
name: 'viewInAppUrl',
|
||||
description: viewInAppUrlActionVariableDescription,
|
||||
|
|
|
@ -30,7 +30,6 @@ import {
|
|||
import {
|
||||
createScopedLogger,
|
||||
AdditionalContext,
|
||||
getAlertDetailsUrl,
|
||||
getContextForRecoveredAlerts,
|
||||
getViewInMetricsAppUrl,
|
||||
UNGROUPED_FACTORY_KEY,
|
||||
|
@ -38,6 +37,7 @@ import {
|
|||
validGroupByForContext,
|
||||
flattenAdditionalContext,
|
||||
getGroupByObject,
|
||||
getAlertUrl,
|
||||
} from '../common/utils';
|
||||
|
||||
import { EvaluatedRuleParams, evaluateRule } from './lib/evaluate_rule';
|
||||
|
@ -110,7 +110,13 @@ export const createMetricThresholdExecutor = (libs: InfraBackendLibs) =>
|
|||
executionId,
|
||||
});
|
||||
|
||||
const { alertWithLifecycle, savedObjectsClient, getAlertUuid, getAlertByAlertUuid } = services;
|
||||
const {
|
||||
alertWithLifecycle,
|
||||
savedObjectsClient,
|
||||
getAlertUuid,
|
||||
getAlertStartedDate,
|
||||
getAlertByAlertUuid,
|
||||
} = services;
|
||||
|
||||
const alertFactory: MetricThresholdAlertFactory = (
|
||||
id,
|
||||
|
@ -150,9 +156,17 @@ export const createMetricThresholdExecutor = (libs: InfraBackendLibs) =>
|
|||
const reason = buildInvalidQueryAlertReason(params.filterQueryText);
|
||||
const alert = alertFactory(UNGROUPED_FACTORY_KEY, reason, actionGroupId);
|
||||
const alertUuid = getAlertUuid(UNGROUPED_FACTORY_KEY);
|
||||
const indexedStartedAt =
|
||||
getAlertStartedDate(UNGROUPED_FACTORY_KEY) ?? startedAt.toISOString();
|
||||
|
||||
alert.scheduleActions(actionGroupId, {
|
||||
alertDetailsUrl: getAlertDetailsUrl(libs.basePath, spaceId, alertUuid),
|
||||
alertDetailsUrl: await getAlertUrl(
|
||||
alertUuid,
|
||||
spaceId,
|
||||
indexedStartedAt,
|
||||
libs.alertsLocator,
|
||||
libs.basePath.publicBaseUrl
|
||||
),
|
||||
alertState: stateToAlertMessage[AlertStates.ERROR],
|
||||
group: UNGROUPED_FACTORY_KEY,
|
||||
metric: mapToConditionsLookup(criteria, (c) => c.metric),
|
||||
|
@ -309,10 +323,17 @@ export const createMetricThresholdExecutor = (libs: InfraBackendLibs) =>
|
|||
evaluationValues
|
||||
);
|
||||
const alertUuid = getAlertUuid(group);
|
||||
const indexedStartedAt = getAlertStartedDate(group) ?? startedAt.toISOString();
|
||||
scheduledActionsCount++;
|
||||
|
||||
alert.scheduleActions(actionGroupId, {
|
||||
alertDetailsUrl: getAlertDetailsUrl(libs.basePath, spaceId, alertUuid),
|
||||
alertDetailsUrl: await getAlertUrl(
|
||||
alertUuid,
|
||||
spaceId,
|
||||
indexedStartedAt,
|
||||
libs.alertsLocator,
|
||||
libs.basePath.publicBaseUrl
|
||||
),
|
||||
alertState: stateToAlertMessage[nextState],
|
||||
group,
|
||||
groupByKeys: groupByKeysObjectMapping[group],
|
||||
|
@ -357,13 +378,21 @@ export const createMetricThresholdExecutor = (libs: InfraBackendLibs) =>
|
|||
for (const alert of recoveredAlerts) {
|
||||
const recoveredAlertId = alert.getId();
|
||||
const alertUuid = getAlertUuid(recoveredAlertId);
|
||||
const timestamp = startedAt.toISOString();
|
||||
const indexedStartedAt = getAlertStartedDate(recoveredAlertId) ?? timestamp;
|
||||
|
||||
const alertHits = alertUuid ? await getAlertByAlertUuid(alertUuid) : undefined;
|
||||
const additionalContext = getContextForRecoveredAlerts(alertHits);
|
||||
const originalActionGroup = getOriginalActionGroup(alertHits);
|
||||
|
||||
alert.setContext({
|
||||
alertDetailsUrl: getAlertDetailsUrl(libs.basePath, spaceId, alertUuid),
|
||||
alertDetailsUrl: await getAlertUrl(
|
||||
alertUuid,
|
||||
spaceId,
|
||||
indexedStartedAt,
|
||||
libs.alertsLocator,
|
||||
libs.basePath.publicBaseUrl
|
||||
),
|
||||
alertState: stateToAlertMessage[AlertStates.OK],
|
||||
group: recoveredAlertId,
|
||||
groupByKeys: groupByKeysObjectForRecovered[recoveredAlertId],
|
||||
|
@ -373,7 +402,7 @@ export const createMetricThresholdExecutor = (libs: InfraBackendLibs) =>
|
|||
}
|
||||
return c.metric;
|
||||
}),
|
||||
timestamp: startedAt.toISOString(),
|
||||
timestamp,
|
||||
threshold: mapToConditionsLookup(criteria, (c) => c.threshold),
|
||||
viewInAppUrl: getViewInMetricsAppUrl(libs.basePath, spaceId),
|
||||
|
||||
|
|
|
@ -31,11 +31,7 @@ import {
|
|||
valueActionVariableDescription,
|
||||
viewInAppUrlActionVariableDescription,
|
||||
} from '../common/messages';
|
||||
import {
|
||||
getAlertDetailsPageEnabledForApp,
|
||||
oneOfLiterals,
|
||||
validateIsStringElasticsearchJSONFilter,
|
||||
} from '../common/utils';
|
||||
import { oneOfLiterals, validateIsStringElasticsearchJSONFilter } from '../common/utils';
|
||||
import {
|
||||
createMetricThresholdExecutor,
|
||||
FIRED_ACTIONS,
|
||||
|
@ -55,8 +51,6 @@ export async function registerMetricThresholdRuleType(
|
|||
alertingPlugin: PluginSetupContract,
|
||||
libs: InfraBackendLibs
|
||||
) {
|
||||
const config = libs.getAlertDetailsConfig();
|
||||
|
||||
const baseCriterion = {
|
||||
threshold: schema.arrayOf(schema.number()),
|
||||
comparator: oneOfLiterals(Object.values(Comparator)),
|
||||
|
@ -150,15 +144,11 @@ export async function registerMetricThresholdRuleType(
|
|||
context: [
|
||||
{ name: 'group', description: groupActionVariableDescription },
|
||||
{ name: 'groupByKeys', description: groupByKeysActionVariableDescription },
|
||||
...(getAlertDetailsPageEnabledForApp(config, 'metrics')
|
||||
? [
|
||||
{
|
||||
name: 'alertDetailsUrl',
|
||||
description: alertDetailUrlActionVariableDescription,
|
||||
usesPublicBaseUrl: true,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
name: 'alertDetailsUrl',
|
||||
description: alertDetailUrlActionVariableDescription,
|
||||
usesPublicBaseUrl: true,
|
||||
},
|
||||
{ name: 'alertState', description: alertStateActionVariableDescription },
|
||||
{ name: 'reason', description: reasonActionVariableDescription },
|
||||
{ name: 'timestamp', description: timestampActionVariableDescription },
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
import { Logger } from '@kbn/logging';
|
||||
import type { IBasePath } from '@kbn/core/server';
|
||||
import { handleEsError } from '@kbn/es-ui-shared-plugin/server';
|
||||
import type { AlertsLocatorParams } from '@kbn/observability-plugin/common';
|
||||
import { ObservabilityConfig } from '@kbn/observability-plugin/server';
|
||||
import { LocatorPublic } from '@kbn/share-plugin/common';
|
||||
import { RulesServiceSetup } from '../services/rules';
|
||||
import { InfraConfig, InfraPluginStartServicesAccessor } from '../types';
|
||||
import { KibanaFramework } from './adapters/framework/kibana_framework_adapter';
|
||||
|
@ -36,4 +38,5 @@ export interface InfraBackendLibs extends InfraDomainLibs {
|
|||
getStartServices: InfraPluginStartServicesAccessor;
|
||||
handleEsError: typeof handleEsError;
|
||||
logger: Logger;
|
||||
alertsLocator?: LocatorPublic<AlertsLocatorParams>;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import {
|
|||
import { handleEsError } from '@kbn/es-ui-shared-plugin/server';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { Logger } from '@kbn/logging';
|
||||
import { alertsLocatorID } from '@kbn/observability-plugin/common';
|
||||
import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common';
|
||||
import {
|
||||
DISCOVER_APP_TARGET,
|
||||
|
@ -203,6 +204,7 @@ export class InfraServerPlugin
|
|||
getAlertDetailsConfig: () => plugins.observability.getAlertDetailsConfig(),
|
||||
logger: this.logger,
|
||||
basePath: core.http.basePath,
|
||||
alertsLocator: plugins.share.url.locators.get(alertsLocatorID),
|
||||
};
|
||||
|
||||
plugins.features.registerKibanaFeature(METRICS_FEATURE);
|
||||
|
|
|
@ -8,3 +8,5 @@
|
|||
export const SLO_BURN_RATE_RULE_ID = 'slo.rules.burnRate';
|
||||
export const INVALID_EQUATION_REGEX = /[^A-Z|+|\-|\s|\d+|\.|\(|\)|\/|\*|>|<|=|\?|\:|&|\!|\|]+/g;
|
||||
export const ALERT_STATUS_ALL = 'all';
|
||||
|
||||
export const ALERTS_URL_STORAGE_KEY = '_a';
|
||||
|
|
|
@ -63,10 +63,13 @@ export const uptimeOverviewLocatorID = 'UPTIME_OVERVIEW_LOCATOR';
|
|||
export const syntheticsMonitorDetailLocatorID = 'SYNTHETICS_MONITOR_DETAIL_LOCATOR';
|
||||
export const syntheticsEditMonitorLocatorID = 'SYNTHETICS_EDIT_MONITOR_LOCATOR';
|
||||
export const syntheticsSettingsLocatorID = 'SYNTHETICS_SETTINGS';
|
||||
export const alertsLocatorID = 'ALERTS_LOCATOR';
|
||||
export const ruleDetailsLocatorID = 'RULE_DETAILS_LOCATOR';
|
||||
export const rulesLocatorID = 'RULES_LOCATOR';
|
||||
export const sloDetailsLocatorID = 'SLO_DETAILS_LOCATOR';
|
||||
|
||||
export type { AlertsLocatorParams } from './locators/alerts';
|
||||
|
||||
export {
|
||||
NETWORK_TIMINGS_FIELDS,
|
||||
SYNTHETICS_BLOCKED_TIMINGS,
|
||||
|
|
57
x-pack/plugins/observability/common/locators/alerts.test.ts
Normal file
57
x-pack/plugins/observability/common/locators/alerts.test.ts
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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 { ALERT_STATUS_ACTIVE } from '@kbn/rule-data-utils';
|
||||
import { ALERTS_PATH, AlertsLocatorDefinition } from './alerts';
|
||||
|
||||
describe('RuleDetailsLocator', () => {
|
||||
const locator = new AlertsLocatorDefinition();
|
||||
const baseUrlMock = 'https://kibana.dev';
|
||||
const spaceIdMock = 'mockedSpaceId';
|
||||
|
||||
it('should return correct url when only baseUrl and spaceId are provided', async () => {
|
||||
const location = await locator.getLocation({ baseUrl: baseUrlMock, spaceId: spaceIdMock });
|
||||
expect(location.app).toEqual('observability');
|
||||
expect(location.path).toEqual(
|
||||
`${baseUrlMock}/s/${spaceIdMock}${ALERTS_PATH}?_a=(kuery:%27%27%2CrangeFrom:now-15m%2CrangeTo:now%2Cstatus:all)`
|
||||
);
|
||||
});
|
||||
|
||||
it('should return correct url when spaceId is default', async () => {
|
||||
const location = await locator.getLocation({ baseUrl: baseUrlMock, spaceId: 'default' });
|
||||
expect(location.app).toEqual('observability');
|
||||
expect(location.path).toEqual(
|
||||
`${baseUrlMock}${ALERTS_PATH}?_a=(kuery:%27%27%2CrangeFrom:now-15m%2CrangeTo:now%2Cstatus:all)`
|
||||
);
|
||||
});
|
||||
|
||||
it('should return correct url when time range is provided', async () => {
|
||||
const location = await locator.getLocation({
|
||||
baseUrl: baseUrlMock,
|
||||
spaceId: spaceIdMock,
|
||||
rangeFrom: 'mockedRangeTo',
|
||||
rangeTo: 'mockedRangeFrom',
|
||||
});
|
||||
expect(location.path).toEqual(
|
||||
`${baseUrlMock}/s/${spaceIdMock}${ALERTS_PATH}?_a=(kuery:%27%27%2CrangeFrom:mockedRangeTo%2CrangeTo:mockedRangeFrom%2Cstatus:all)`
|
||||
);
|
||||
});
|
||||
|
||||
it('should return correct url when all the params are provided', async () => {
|
||||
const location = await locator.getLocation({
|
||||
baseUrl: baseUrlMock,
|
||||
spaceId: spaceIdMock,
|
||||
rangeFrom: 'mockedRangeTo',
|
||||
rangeTo: 'mockedRangeFrom',
|
||||
kuery: 'mockedKuery',
|
||||
status: ALERT_STATUS_ACTIVE,
|
||||
});
|
||||
expect(location.path).toEqual(
|
||||
`${baseUrlMock}/s/${spaceIdMock}${ALERTS_PATH}?_a=(kuery:mockedKuery%2CrangeFrom:mockedRangeTo%2CrangeTo:mockedRangeFrom%2Cstatus:active)`
|
||||
);
|
||||
});
|
||||
});
|
70
x-pack/plugins/observability/common/locators/alerts.ts
Normal file
70
x-pack/plugins/observability/common/locators/alerts.ts
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* 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 { stringify } from 'query-string';
|
||||
import rison from '@kbn/rison';
|
||||
import { url as urlUtils } from '@kbn/kibana-utils-plugin/common';
|
||||
import { addSpaceIdToPath } from '@kbn/spaces-plugin/common';
|
||||
import type { SerializableRecord } from '@kbn/utility-types';
|
||||
import type { LocatorDefinition } from '@kbn/share-plugin/public';
|
||||
import { alertsLocatorID } from '..';
|
||||
import { ALERTS_URL_STORAGE_KEY } from '../constants';
|
||||
import type { AlertStatus } from '../typings';
|
||||
|
||||
export interface AlertsLocatorParams extends SerializableRecord {
|
||||
baseUrl: string;
|
||||
spaceId: string;
|
||||
rangeFrom?: string;
|
||||
rangeTo?: string;
|
||||
kuery?: string;
|
||||
status?: AlertStatus;
|
||||
}
|
||||
|
||||
export const ALERTS_PATH = '/app/observability/alerts';
|
||||
|
||||
function fromQuery(query: Record<string, any>) {
|
||||
const encodedQuery = urlUtils.encodeQuery(query, (value) =>
|
||||
encodeURIComponent(value).replace(/%3A/g, ':')
|
||||
);
|
||||
|
||||
return stringify(encodedQuery, { sort: false, encode: false });
|
||||
}
|
||||
|
||||
export class AlertsLocatorDefinition implements LocatorDefinition<AlertsLocatorParams> {
|
||||
public readonly id = alertsLocatorID;
|
||||
|
||||
public readonly getLocation = async ({
|
||||
baseUrl,
|
||||
spaceId,
|
||||
kuery,
|
||||
rangeTo,
|
||||
rangeFrom,
|
||||
status,
|
||||
}: AlertsLocatorParams) => {
|
||||
const appState: {
|
||||
rangeFrom?: string;
|
||||
rangeTo?: string;
|
||||
kuery?: string;
|
||||
status?: AlertStatus;
|
||||
} = {};
|
||||
|
||||
appState.rangeFrom = rangeFrom || 'now-15m';
|
||||
appState.rangeTo = rangeTo || 'now';
|
||||
appState.kuery = kuery || '';
|
||||
appState.status = status || 'all';
|
||||
|
||||
const path = addSpaceIdToPath(baseUrl, spaceId, ALERTS_PATH);
|
||||
const url = new URL(path);
|
||||
url.search = fromQuery({ [ALERTS_URL_STORAGE_KEY]: rison.encodeUnknown(appState) });
|
||||
|
||||
return {
|
||||
app: 'observability',
|
||||
path: url.href,
|
||||
state: {},
|
||||
};
|
||||
};
|
||||
}
|
|
@ -40,7 +40,13 @@ export {
|
|||
enableInfrastructureHostsView,
|
||||
enableAgentExplorerView,
|
||||
} from '../common/ui_settings_keys';
|
||||
export { uptimeOverviewLocatorID } from '../common';
|
||||
export {
|
||||
alertsLocatorID,
|
||||
ruleDetailsLocatorID,
|
||||
rulesLocatorID,
|
||||
sloDetailsLocatorID,
|
||||
uptimeOverviewLocatorID,
|
||||
} from '../common';
|
||||
|
||||
export type { UXMetrics } from './components/core_web_vitals/core_vitals';
|
||||
export { getCoreVitalsComponent } from './components/core_web_vitals/get_core_web_vitals_lazy';
|
||||
|
|
|
@ -15,6 +15,7 @@ import { loadRuleAggregations } from '@kbn/triggers-actions-ui-plugin/public';
|
|||
import { AlertConsumers } from '@kbn/rule-data-utils';
|
||||
import { useBreadcrumbs } from '@kbn/observability-shared-plugin/public';
|
||||
|
||||
import { ALERTS_URL_STORAGE_KEY } from '../../../common/constants';
|
||||
import { useHasData } from '../../hooks/use_has_data';
|
||||
import { usePluginContext } from '../../hooks/use_plugin_context';
|
||||
import { useTimeBuckets } from '../../hooks/use_time_buckets';
|
||||
|
@ -35,7 +36,6 @@ import type { ObservabilityAppServices } from '../../application/types';
|
|||
const ALERTS_SEARCH_BAR_ID = 'alerts-search-bar-o11y';
|
||||
const ALERTS_PER_PAGE = 50;
|
||||
const ALERTS_TABLE_ID = 'xpack.observability.alerts.alert.table';
|
||||
const URL_STORAGE_KEY = '_a';
|
||||
|
||||
const DEFAULT_INTERVAL = '60s';
|
||||
const DEFAULT_DATE_FORMAT = 'YYYY-MM-DD HH:mm';
|
||||
|
@ -58,7 +58,7 @@ function InternalAlertsPage() {
|
|||
},
|
||||
} = useKibana<ObservabilityAppServices>().services;
|
||||
const { ObservabilityPageTemplate, observabilityRuleTypeRegistry } = usePluginContext();
|
||||
const alertSearchBarStateProps = useAlertSearchBarStateContainer(URL_STORAGE_KEY, {
|
||||
const alertSearchBarStateProps = useAlertSearchBarStateContainer(ALERTS_URL_STORAGE_KEY, {
|
||||
replace: false,
|
||||
});
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import {
|
|||
createUICapabilities as createCasesUICapabilities,
|
||||
getApiTags as getCasesApiTags,
|
||||
} from '@kbn/cases-plugin/common';
|
||||
import { SharePluginSetup } from '@kbn/share-plugin/server';
|
||||
import { SpacesPluginSetup } from '@kbn/spaces-plugin/server';
|
||||
import type { GuidedOnboardingPluginSetup } from '@kbn/guided-onboarding-plugin/server';
|
||||
|
||||
|
@ -43,6 +44,7 @@ import { getObservabilityServerRouteRepository } from './routes/get_global_obser
|
|||
import { casesFeatureId, observabilityFeatureId, sloFeatureId } from '../common';
|
||||
import { compositeSlo, slo, SO_COMPOSITE_SLO_TYPE, SO_SLO_TYPE } from './saved_objects';
|
||||
import { SLO_RULE_REGISTRATION_CONTEXT } from './common/constants';
|
||||
import { AlertsLocatorDefinition } from '../common/locators/alerts';
|
||||
import { registerRuleTypes } from './lib/rules/register_rule_types';
|
||||
import { SLO_BURN_RATE_RULE_ID } from '../common/constants';
|
||||
import { registerSloUsageCollector } from './lib/collectors/register';
|
||||
|
@ -55,6 +57,7 @@ interface PluginSetup {
|
|||
features: FeaturesSetup;
|
||||
guidedOnboarding: GuidedOnboardingPluginSetup;
|
||||
ruleRegistry: RuleRegistryPluginSetupContract;
|
||||
share: SharePluginSetup;
|
||||
spaces?: SpacesPluginSetup;
|
||||
usageCollection?: UsageCollectionSetup;
|
||||
}
|
||||
|
@ -77,6 +80,8 @@ export class ObservabilityPlugin implements Plugin<ObservabilityPluginSetup> {
|
|||
|
||||
const config = this.initContext.config.get<ObservabilityConfig>();
|
||||
|
||||
const alertsLocator = plugins.share.url.locators.create(new AlertsLocatorDefinition());
|
||||
|
||||
plugins.features.registerKibanaFeature({
|
||||
id: casesFeatureId,
|
||||
name: i18n.translate('xpack.observability.featureRegistry.linkObservabilityTitle', {
|
||||
|
@ -267,6 +272,7 @@ export class ObservabilityPlugin implements Plugin<ObservabilityPluginSetup> {
|
|||
const api = await annotationsApiPromise;
|
||||
return api?.getScopedAnnotationsClient(...args);
|
||||
},
|
||||
alertsLocator,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -68,7 +68,8 @@
|
|||
"@kbn/core-theme-browser",
|
||||
"@kbn/core-elasticsearch-server",
|
||||
"@kbn/observability-shared-plugin",
|
||||
"@kbn/exploratory-view-plugin"
|
||||
"@kbn/exploratory-view-plugin",
|
||||
"@kbn/rison"
|
||||
],
|
||||
"exclude": ["target/**/*"]
|
||||
}
|
||||
|
|
19
x-pack/test/alerting_api_integration/observability/config.ts
Normal file
19
x-pack/test/alerting_api_integration/observability/config.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* 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 { createTestConfig } from '../common/config';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default createTestConfig('observability', {
|
||||
disabledPlugins: [],
|
||||
license: 'trial',
|
||||
ssl: true,
|
||||
enableActionsProxy: true,
|
||||
publicBaseUrl: true,
|
||||
testFiles: [require.resolve('.')],
|
||||
useDedicatedTaskRunner: true,
|
||||
});
|
13
x-pack/test/alerting_api_integration/observability/index.ts
Normal file
13
x-pack/test/alerting_api_integration/observability/index.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default function ({ loadTestFile }: any) {
|
||||
describe('MetricsUI Endpoints', () => {
|
||||
loadTestFile(require.resolve('./metric_threshold_rule'));
|
||||
});
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import moment from 'moment';
|
||||
import expect from '@kbn/expect';
|
||||
import { cleanup, generate } from '@kbn/infra-forge';
|
||||
import { Aggregators, Comparator, InfraRuleType } from '@kbn/infra-plugin/common/alerting/metrics';
|
||||
|
@ -13,9 +14,10 @@ import {
|
|||
waitForAlertInIndex,
|
||||
waitForRuleStatus,
|
||||
} from './helpers/alerting_wait_for_helpers';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import { FtrProviderContext } from '../common/ftr_provider_context';
|
||||
import { createIndexConnector, createMetricThresholdRule } from './helpers/alerting_api_helper';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
const esClient = getService('es');
|
||||
const esDeleteAllIndices = getService('esDeleteAllIndices');
|
||||
|
@ -24,7 +26,9 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
|
||||
describe('Metric threshold rule >', () => {
|
||||
let ruleId: string;
|
||||
let actionId: string | undefined;
|
||||
let alertId: string;
|
||||
let startedAt: string;
|
||||
let actionId: string;
|
||||
let infraDataIndex: string;
|
||||
|
||||
const METRICS_ALERTS_INDEX = '.alerts-observability.metrics.alerts-default';
|
||||
|
@ -65,6 +69,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
documents: [
|
||||
{
|
||||
ruleType: '{{rule.type}}',
|
||||
alertDetailsUrl: '{{context.alertDetailsUrl}}',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -106,21 +111,14 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
expect(executionStatus.status).to.be('active');
|
||||
});
|
||||
|
||||
it('should set correct action parameter: ruleType', async () => {
|
||||
const resp = await waitForDocumentInIndex<{ ruleType: string }>({
|
||||
esClient,
|
||||
indexName: ALERT_ACTION_INDEX,
|
||||
});
|
||||
|
||||
expect(resp.hits.hits[0]._source?.ruleType).eql('metrics.alert.threshold');
|
||||
});
|
||||
|
||||
it('should set correct information in the alert document', async () => {
|
||||
const resp = await waitForAlertInIndex({
|
||||
esClient,
|
||||
indexName: METRICS_ALERTS_INDEX,
|
||||
ruleId,
|
||||
});
|
||||
alertId = (resp.hits.hits[0]._source as any)['kibana.alert.uuid'];
|
||||
startedAt = (resp.hits.hits[0]._source as any)['kibana.alert.start'];
|
||||
expect(resp.hits.hits[0]._source).property(
|
||||
'kibana.alert.rule.category',
|
||||
'Metric threshold'
|
||||
|
@ -169,6 +167,19 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
alertOnGroupDisappear: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('should set correct action parameter: ruleType', async () => {
|
||||
const rangeFrom = moment(startedAt).subtract('5', 'minute').toISOString();
|
||||
const resp = await waitForDocumentInIndex<{ ruleType: string; alertDetailsUrl: string }>({
|
||||
esClient,
|
||||
indexName: ALERT_ACTION_INDEX,
|
||||
});
|
||||
|
||||
expect(resp.hits.hits[0]._source?.ruleType).eql('metrics.alert.threshold');
|
||||
expect(resp.hits.hits[0]._source?.alertDetailsUrl).eql(
|
||||
`https://localhost:5601/app/observability/alerts?_a=(kuery:%27kibana.alert.uuid:%20%22${alertId}%22%27%2CrangeFrom:%27${rangeFrom}%27%2CrangeTo:now%2Cstatus:all)`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -18,7 +18,6 @@ export default function ({ loadTestFile }) {
|
|||
loadTestFile(require.resolve('./ip_to_hostname'));
|
||||
loadTestFile(require.resolve('./http_source'));
|
||||
loadTestFile(require.resolve('./metric_threshold_alert'));
|
||||
loadTestFile(require.resolve('./metric_threshold_rule'));
|
||||
loadTestFile(require.resolve('./metrics_overview_top'));
|
||||
loadTestFile(require.resolve('./metrics_process_list'));
|
||||
loadTestFile(require.resolve('./metrics_process_list_chart'));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue