Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Actionable Observability] Add context.alertDetailsUrl variable to action connector template for APM rule types #144791

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
149c3fe
Add context.alertDetailsUrl to connector template for APM Latency Thr…
CoenWarmer Nov 8, 2022
7e5977d
Add context.alertDetailsUrl to connector template for APM Error Count…
CoenWarmer Nov 8, 2022
93a0ee8
Merge branch 'main' of github.com:elastic/kibana into feat/144439-add…
CoenWarmer Nov 8, 2022
23d6ac9
Add context.alertDetailsUrl to connector template for APM Anomaly rule
CoenWarmer Nov 8, 2022
e5726a3
Add context.alertDetailsUrl to connector template for APM Failed Tran…
CoenWarmer Nov 8, 2022
3a8f524
Merge branch 'main' of github.com:elastic/kibana into feat/144439-add…
CoenWarmer Nov 8, 2022
e5be4e5
Add mock for getAlertsDetailConfig
CoenWarmer Nov 8, 2022
7ac391c
Update tests
CoenWarmer Nov 9, 2022
fbefd38
Merge branch 'main' of github.com:elastic/kibana into feat/144439-add…
CoenWarmer Nov 9, 2022
3a4ed3d
Expand types of createLifecycleRuleTypeFactory
dgieselaar Nov 14, 2022
7b56b75
Merge branch 'feat/144439-add-context-alertdetailsurl-to-apm-latency-…
CoenWarmer Nov 14, 2022
6011172
Make getAlertUuid idempotent
dgieselaar Nov 14, 2022
e1effd2
Merge branch 'feat/144439-add-context-alertdetailsurl-to-apm-latency-…
CoenWarmer Nov 14, 2022
2457b86
Revert changes to alerting plugin types
CoenWarmer Nov 14, 2022
aca90fc
Pass observability plugin to registerApmRule function
CoenWarmer Nov 14, 2022
c14712f
Update types
CoenWarmer Nov 14, 2022
817062b
Merge branch 'main' of github.com:elastic/kibana into feat/144439-add…
CoenWarmer Nov 14, 2022
29d9d95
getAlertUuid function in rules will always be available
CoenWarmer Nov 14, 2022
21d200b
Update types
CoenWarmer Nov 14, 2022
a77f557
Remove [ALERT_UUID] from alertWithLifecycle calls as uuid is already …
CoenWarmer Nov 14, 2022
a1cfd27
Merge branch 'main' of github.com:elastic/kibana into feat/144439-add…
CoenWarmer Nov 14, 2022
4eeaa61
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Nov 14, 2022
f90b645
Consolidate types for DefaultUptimeAlertInstance
dgieselaar Nov 14, 2022
0c78f52
Merge branch 'main' of github.com:elastic/kibana into feat/144439-add…
CoenWarmer Nov 14, 2022
83d3269
Merge branch 'feat/144439-add-context-alertdetailsurl-to-apm-latency-…
CoenWarmer Nov 14, 2022
a48b067
Revert change in rule registration as a FTR test wants rules register…
CoenWarmer Nov 14, 2022
39c9a54
Merge branch 'main' of github.com:elastic/kibana into feat/144439-add…
CoenWarmer Nov 14, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions x-pack/plugins/apm/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,12 +190,13 @@ export class APMPlugin

if (plugins.alerting) {
registerApmRuleTypes({
ruleDataClient,
alerting: plugins.alerting,
ml: plugins.ml,
basePath: core.http.basePath,
config$,
logger: this.logger!.get('rule'),
basePath: core.http.basePath,
ml: plugins.ml,
observability: plugins.observability,
ruleDataClient,
});
}

Expand Down
66 changes: 38 additions & 28 deletions x-pack/plugins/apm/server/routes/alerts/action_variables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,15 @@
import { i18n } from '@kbn/i18n';

export const apmActionVariables = {
serviceName: {
description: i18n.translate(
'xpack.apm.alerts.action_variables.serviceName',
{ defaultMessage: 'The service the alert is created for' }
),
name: 'serviceName' as const,
},
transactionType: {
alertDetailsUrl: {
description: i18n.translate(
'xpack.apm.alerts.action_variables.transactionType',
{ defaultMessage: 'The transaction type the alert is created for' }
'xpack.apm.alerts.action_variables.alertDetailsUrl',
{
defaultMessage:
'Link to the view within Elastic that shows further details and context surrounding this alert',
}
),
name: 'transactionType' as const,
name: 'alertDetailsUrl' as const,
},
environment: {
description: i18n.translate(
Expand All @@ -29,23 +25,6 @@ export const apmActionVariables = {
),
name: 'environment' as const,
},
threshold: {
description: i18n.translate('xpack.apm.alerts.action_variables.threshold', {
defaultMessage:
'Any trigger value above this value will cause the alert to fire',
}),
name: 'threshold' as const,
},
triggerValue: {
description: i18n.translate(
'xpack.apm.alerts.action_variables.triggerValue',
{
defaultMessage:
'The value that breached the threshold and triggered the alert',
}
),
name: 'triggerValue' as const,
},
interval: {
description: i18n.translate(
'xpack.apm.alerts.action_variables.intervalSize',
Expand All @@ -65,6 +44,37 @@ export const apmActionVariables = {
),
name: 'reason' as const,
},
serviceName: {
description: i18n.translate(
'xpack.apm.alerts.action_variables.serviceName',
{ defaultMessage: 'The service the alert is created for' }
),
name: 'serviceName' as const,
},
threshold: {
description: i18n.translate('xpack.apm.alerts.action_variables.threshold', {
defaultMessage:
'Any trigger value above this value will cause the alert to fire',
}),
name: 'threshold' as const,
},
transactionType: {
description: i18n.translate(
'xpack.apm.alerts.action_variables.transactionType',
{ defaultMessage: 'The transaction type the alert is created for' }
),
name: 'transactionType' as const,
},
triggerValue: {
description: i18n.translate(
'xpack.apm.alerts.action_variables.triggerValue',
{
defaultMessage:
'The value that breached the threshold and triggered the alert',
}
),
name: 'triggerValue' as const,
},
viewInAppUrl: {
description: i18n.translate(
'xpack.apm.alerts.action_variables.viewInAppUrl',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { Observable } from 'rxjs';
import { IBasePath, Logger } from '@kbn/core/server';
import { PluginSetupContract as AlertingPluginSetupContract } from '@kbn/alerting-plugin/server';
import { ObservabilityPluginSetup } from '@kbn/observability-plugin/server';
import { IRuleDataClient } from '@kbn/rule-registry-plugin/server';
import { MlPluginSetup } from '@kbn/ml-plugin/server';
import { registerTransactionDurationRuleType } from './rule_types/transaction_duration/register_transaction_duration_rule_type';
Expand All @@ -17,12 +18,13 @@ import { APMConfig } from '../..';
import { registerTransactionErrorRateRuleType } from './rule_types/transaction_error_rate/register_transaction_error_rate_rule_type';

export interface RegisterRuleDependencies {
ruleDataClient: IRuleDataClient;
ml?: MlPluginSetup;
alerting: AlertingPluginSetupContract;
basePath: IBasePath;
config$: Observable<APMConfig>;
logger: Logger;
basePath: IBasePath;
ml?: MlPluginSetup;
observability: ObservabilityPluginSetup;
ruleDataClient: IRuleDataClient;
}

export function registerApmRuleTypes(dependencies: RegisterRuleDependencies) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ describe('Transaction duration anomaly alert', () => {
);

expect(scheduleActions).toHaveBeenCalledWith('threshold_met', {
alertDetailsUrl: expect.stringContaining(
'http://localhost:5601/eyr/app/observability/alerts/'
),
serviceName: 'foo',
transactionType: 'type-foo',
environment: 'development',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,23 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import datemath from '@kbn/datemath';
import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { schema } from '@kbn/config-schema';
import { KibanaRequest } from '@kbn/core/server';
import datemath from '@kbn/datemath';
import type { ESSearchResponse } from '@kbn/es-types';
import { getAlertDetailsUrl } from '@kbn/infra-plugin/server/lib/alerting/common/utils';
import { ProcessorEvent } from '@kbn/observability-plugin/common';
import { termQuery } from '@kbn/observability-plugin/server';
import {
ALERT_EVALUATION_THRESHOLD,
ALERT_EVALUATION_VALUE,
ALERT_REASON,
ALERT_SEVERITY,
} from '@kbn/rule-data-utils';
import { compact } from 'lodash';
import type { ESSearchResponse } from '@kbn/es-types';
import { KibanaRequest } from '@kbn/core/server';
import { termQuery } from '@kbn/observability-plugin/server';
import { createLifecycleRuleTypeFactory } from '@kbn/rule-registry-plugin/server';
import { ProcessorEvent } from '@kbn/observability-plugin/common';
import {
ApmRuleType,
RULE_TYPES_CONFIG,
ANOMALY_ALERT_SEVERITY_TYPES,
formatAnomalyReason,
} from '../../../../../common/rules/apm_rule_types';
import { addSpaceIdToPath } from '@kbn/spaces-plugin/common';
import { compact } from 'lodash';
import { getSeverity } from '../../../../../common/anomaly_detection';
import {
ApmMlDetectorType,
Expand All @@ -41,6 +37,12 @@ import {
getEnvironmentLabel,
} from '../../../../../common/environment_filter_values';
import { ANOMALY_SEVERITY } from '../../../../../common/ml_constants';
import {
ANOMALY_ALERT_SEVERITY_TYPES,
ApmRuleType,
formatAnomalyReason,
RULE_TYPES_CONFIG,
} from '../../../../../common/rules/apm_rule_types';
import { asMutableArray } from '../../../../../common/utils/as_mutable_array';
import { getAlertUrlTransaction } from '../../../../../common/utils/formatters';
import { getMLJobs } from '../../../service_map/get_service_anomalies';
Expand All @@ -65,12 +67,13 @@ const paramsSchema = schema.object({
const ruleTypeConfig = RULE_TYPES_CONFIG[ApmRuleType.Anomaly];

export function registerAnomalyRuleType({
logger,
ruleDataClient,
config$,
alerting,
ml,
basePath,
config$,
logger,
ml,
observability,
ruleDataClient,
}: RegisterRuleDependencies) {
const createLifecycleRuleType = createLifecycleRuleTypeFactory({
logger,
Expand All @@ -88,32 +91,38 @@ export function registerAnomalyRuleType({
},
actionVariables: {
context: [
apmActionVariables.serviceName,
apmActionVariables.transactionType,
...(observability.getAlertDetailsConfig()?.apm.enabled
? [apmActionVariables.alertDetailsUrl]
: []),
apmActionVariables.environment,
apmActionVariables.reason,
apmActionVariables.serviceName,
apmActionVariables.threshold,
apmActionVariables.transactionType,
apmActionVariables.triggerValue,
apmActionVariables.reason,
apmActionVariables.viewInAppUrl,
],
},
producer: 'apm',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: async ({ services, params }) => {
executor: async ({ params, services, spaceId }) => {
if (!ml) {
return {};
}

const { savedObjectsClient, scopedClusterClient, getAlertUuid } =
services;

const ruleParams = params;
const request = {} as KibanaRequest;
const { mlAnomalySearch } = ml.mlSystemProvider(
request,
services.savedObjectsClient
savedObjectsClient
);
const anomalyDetectors = ml.anomalyDetectorsProvider(
request,
services.savedObjectsClient
savedObjectsClient
);

const mlJobs = await getMLJobs(
Expand Down Expand Up @@ -254,8 +263,8 @@ export function registerAnomalyRuleType({

const eventSourceFields = await getServiceGroupFieldsForAnomaly({
config$,
scopedClusterClient: services.scopedClusterClient,
savedObjectsClient: services.savedObjectsClient,
scopedClusterClient,
savedObjectsClient,
serviceName,
environment,
transactionType,
Expand All @@ -272,28 +281,38 @@ export function registerAnomalyRuleType({
windowUnit: params.windowUnit,
});

const id = [
ApmRuleType.Anomaly,
serviceName,
environment,
transactionType,
]
.filter((name) => name)
.join('_');

const relativeViewInAppUrl = getAlertUrlTransaction(
serviceName,
getEnvironmentEsField(environment)?.[SERVICE_ENVIRONMENT],
transactionType
);

const viewInAppUrl = basePath.publicBaseUrl
? new URL(
basePath.prepend(relativeViewInAppUrl),
basePath.publicBaseUrl
).toString()
: relativeViewInAppUrl;
const viewInAppUrl = addSpaceIdToPath(
basePath.publicBaseUrl,
spaceId,
relativeViewInAppUrl
);

const alertUuid = getAlertUuid(id);

const alertDetailsUrl = getAlertDetailsUrl(
basePath,
spaceId,
alertUuid
);

services
.alertWithLifecycle({
id: [
ApmRuleType.Anomaly,
serviceName,
environment,
transactionType,
]
.filter((name) => name)
.join('_'),
id,
fields: {
[SERVICE_NAME]: serviceName,
...getEnvironmentEsField(environment),
Expand All @@ -307,12 +326,13 @@ export function registerAnomalyRuleType({
},
})
.scheduleActions(ruleTypeConfig.defaultActionGroupId, {
serviceName,
transactionType,
alertDetailsUrl,
environment: getEnvironmentLabel(environment),
reason: reasonMessage,
serviceName,
threshold: selectedOption?.label,
transactionType,
triggerValue: severityLevel,
reason: reasonMessage,
viewInAppUrl,
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ describe('Error count alert', () => {
expect(scheduleActions).toHaveBeenCalledTimes(3);

expect(scheduleActions).toHaveBeenCalledWith('threshold_met', {
alertDetailsUrl: expect.stringContaining(
'http://localhost:5601/eyr/app/observability/alerts/'
),
serviceName: 'foo',
environment: 'env-foo',
threshold: 2,
Expand All @@ -148,6 +151,9 @@ describe('Error count alert', () => {
'http://localhost:5601/eyr/app/apm/services/foo/errors?environment=env-foo',
});
expect(scheduleActions).toHaveBeenCalledWith('threshold_met', {
alertDetailsUrl: expect.stringContaining(
'http://localhost:5601/eyr/app/observability/alerts/'
),
serviceName: 'foo',
environment: 'env-foo-2',
threshold: 2,
Expand All @@ -158,6 +164,9 @@ describe('Error count alert', () => {
'http://localhost:5601/eyr/app/apm/services/foo/errors?environment=env-foo-2',
});
expect(scheduleActions).toHaveBeenCalledWith('threshold_met', {
alertDetailsUrl: expect.stringContaining(
'http://localhost:5601/eyr/app/observability/alerts/'
),
serviceName: 'bar',
environment: 'env-bar',
reason: 'Error count is 3 in the last 5 mins for bar. Alert when > 2.',
Expand Down
Loading