diff --git a/x-pack/plugins/apm/common/environment_filter_values.ts b/x-pack/plugins/apm/common/environment_filter_values.ts index e4f0b40607679..fa5c580e89785 100644 --- a/x-pack/plugins/apm/common/environment_filter_values.ts +++ b/x-pack/plugins/apm/common/environment_filter_values.ts @@ -6,63 +6,47 @@ */ import { i18n } from '@kbn/i18n'; +import { SERVICE_ENVIRONMENT } from './elasticsearch_fieldnames'; const ENVIRONMENT_ALL_VALUE = 'ENVIRONMENT_ALL'; const ENVIRONMENT_NOT_DEFINED_VALUE = 'ENVIRONMENT_NOT_DEFINED'; -const environmentLabels: Record = { - [ENVIRONMENT_ALL_VALUE]: i18n.translate( - 'xpack.apm.filter.environment.allLabel', - { defaultMessage: 'All' } - ), - [ENVIRONMENT_NOT_DEFINED_VALUE]: i18n.translate( - 'xpack.apm.filter.environment.notDefinedLabel', - { defaultMessage: 'Not defined' } - ), -}; +export function getEnvironmentLabel(environment: string) { + if (!environment || environment === ENVIRONMENT_NOT_DEFINED_VALUE) { + return i18n.translate('xpack.apm.filter.environment.notDefinedLabel', { + defaultMessage: 'Not defined', + }); + } + + if (environment === ENVIRONMENT_ALL_VALUE) { + return i18n.translate('xpack.apm.filter.environment.allLabel', { + defaultMessage: 'All', + }); + } + + return environment; +} export const ENVIRONMENT_ALL = { - esFieldValue: undefined, value: ENVIRONMENT_ALL_VALUE, - text: environmentLabels[ENVIRONMENT_ALL_VALUE], + text: getEnvironmentLabel(ENVIRONMENT_ALL_VALUE), }; export const ENVIRONMENT_NOT_DEFINED = { - esFieldValue: undefined, value: ENVIRONMENT_NOT_DEFINED_VALUE, - text: environmentLabels[ENVIRONMENT_NOT_DEFINED_VALUE], + text: getEnvironmentLabel(ENVIRONMENT_NOT_DEFINED_VALUE), }; -export function getEnvironmentLabel(environment: string) { - return environmentLabels[environment] || environment; -} - -export function omitEsFieldValue({ - esFieldValue, - value, - text, -}: { - esFieldValue?: string; - value: string; - text: string; -}) { - return { value, text }; -} - -export function parseEnvironmentUrlParam(environment: string) { - if (environment === ENVIRONMENT_ALL_VALUE) { - return ENVIRONMENT_ALL; - } - - if (environment === ENVIRONMENT_NOT_DEFINED_VALUE) { - return ENVIRONMENT_NOT_DEFINED; +export function getEnvironmentEsField(environment: string) { + if ( + !environment || + environment === ENVIRONMENT_NOT_DEFINED_VALUE || + environment === ENVIRONMENT_ALL_VALUE + ) { + return {}; } - return { - esFieldValue: environment, - value: environment, - text: environment, - }; + return { [SERVICE_ENVIRONMENT]: environment }; } // returns the environment url param that should be used diff --git a/x-pack/plugins/apm/public/components/shared/EnvironmentFilter/index.tsx b/x-pack/plugins/apm/public/components/shared/EnvironmentFilter/index.tsx index c1bef7ac407ff..d5a685c4ea70b 100644 --- a/x-pack/plugins/apm/public/components/shared/EnvironmentFilter/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/EnvironmentFilter/index.tsx @@ -13,7 +13,6 @@ import { useHistory, useLocation, useParams } from 'react-router-dom'; import { ENVIRONMENT_ALL, ENVIRONMENT_NOT_DEFINED, - omitEsFieldValue, } from '../../../../common/environment_filter_values'; import { useEnvironmentsFetcher } from '../../../hooks/use_environments_fetcher'; import { useUrlParams } from '../../../context/url_params_context/use_url_params'; @@ -52,9 +51,9 @@ function getOptions(environments: string[]) { })); return [ - omitEsFieldValue(ENVIRONMENT_ALL), + ENVIRONMENT_ALL, ...(environments.includes(ENVIRONMENT_NOT_DEFINED.value) - ? [omitEsFieldValue(ENVIRONMENT_NOT_DEFINED)] + ? [ENVIRONMENT_NOT_DEFINED] : []), ...(environmentOptions.length > 0 ? [SEPARATOR_OPTION] : []), ...environmentOptions, diff --git a/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.ts b/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.ts index 885b22ae343d8..2a63c53b626cd 100644 --- a/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.ts +++ b/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.ts @@ -12,8 +12,11 @@ import { ALERT_EVALUATION_VALUE, } from '@kbn/rule-data-utils/target/technical_field_names'; import { createLifecycleRuleTypeFactory } from '../../../../rule_registry/server'; -import { ENVIRONMENT_NOT_DEFINED } from '../../../common/environment_filter_values'; -import { asMutableArray } from '../../../common/utils/as_mutable_array'; +import { + ENVIRONMENT_NOT_DEFINED, + getEnvironmentEsField, + getEnvironmentLabel, +} from '../../../common/environment_filter_values'; import { AlertType, ALERT_TYPES_CONFIG } from '../../../common/alert_types'; import { PROCESSOR_EVENT, @@ -103,23 +106,13 @@ export function registerErrorCountAlertType({ multi_terms: { terms: [ { field: SERVICE_NAME }, - { field: SERVICE_ENVIRONMENT, missing: '' }, + { + field: SERVICE_ENVIRONMENT, + missing: ENVIRONMENT_NOT_DEFINED.value, + }, ], size: 10000, }, - aggs: { - latest: { - top_metrics: { - metrics: asMutableArray([ - { field: SERVICE_NAME }, - { field: SERVICE_ENVIRONMENT }, - ] as const), - sort: { - '@timestamp': 'desc' as const, - }, - }, - }, - }, }, }, }, @@ -132,13 +125,8 @@ export function registerErrorCountAlertType({ const errorCountResults = response.aggregations?.error_counts.buckets.map((bucket) => { - const latest = bucket.latest.top[0].metrics; - - return { - serviceName: latest['service.name'] as string, - environment: latest['service.environment'] as string | undefined, - errorCount: bucket.doc_count, - }; + const [serviceName, environment] = bucket.key; + return { serviceName, environment, errorCount: bucket.doc_count }; }) ?? []; errorCountResults @@ -153,9 +141,7 @@ export function registerErrorCountAlertType({ .join('_'), fields: { [SERVICE_NAME]: serviceName, - ...(environment - ? { [SERVICE_ENVIRONMENT]: environment } - : {}), + ...getEnvironmentEsField(environment), [PROCESSOR_EVENT]: ProcessorEvent.error, [ALERT_EVALUATION_VALUE]: errorCount, [ALERT_EVALUATION_THRESHOLD]: alertParams.threshold, @@ -163,7 +149,7 @@ export function registerErrorCountAlertType({ }) .scheduleActions(alertTypeConfig.defaultActionGroupId, { serviceName, - environment: environment || ENVIRONMENT_NOT_DEFINED.text, + environment: getEnvironmentLabel(environment), threshold: alertParams.threshold, triggerValue: errorCount, interval: `${alertParams.windowSize}${alertParams.windowUnit}`, diff --git a/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts b/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts index 3e870eb3e32c6..24a6376761a7d 100644 --- a/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts +++ b/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts @@ -13,11 +13,13 @@ import { ALERT_EVALUATION_VALUE, } from '@kbn/rule-data-utils/target/technical_field_names'; import { createLifecycleRuleTypeFactory } from '../../../../rule_registry/server'; -import { parseEnvironmentUrlParam } from '../../../common/environment_filter_values'; +import { + getEnvironmentLabel, + getEnvironmentEsField, +} from '../../../common/environment_filter_values'; import { AlertType, ALERT_TYPES_CONFIG } from '../../../common/alert_types'; import { PROCESSOR_EVENT, - SERVICE_ENVIRONMENT, SERVICE_NAME, TRANSACTION_DURATION, TRANSACTION_TYPE, @@ -150,20 +152,14 @@ export function registerTransactionDurationAlertType({ transactionDuration ).formatted; - const environmentParsed = parseEnvironmentUrlParam( - alertParams.environment - ); - services .alertWithLifecycle({ - id: `${AlertType.TransactionDuration}_${environmentParsed.text}`, + id: `${AlertType.TransactionDuration}_${getEnvironmentLabel( + alertParams.environment + )}`, fields: { [SERVICE_NAME]: alertParams.serviceName, - ...(environmentParsed.esFieldValue - ? { - [SERVICE_ENVIRONMENT]: environmentParsed.esFieldValue, - } - : {}), + ...getEnvironmentEsField(alertParams.environment), [TRANSACTION_TYPE]: alertParams.transactionType, [PROCESSOR_EVENT]: ProcessorEvent.transaction, [ALERT_EVALUATION_VALUE]: transactionDuration, @@ -173,7 +169,7 @@ export function registerTransactionDurationAlertType({ .scheduleActions(alertTypeConfig.defaultActionGroupId, { transactionType: alertParams.transactionType, serviceName: alertParams.serviceName, - environment: environmentParsed.text, + environment: getEnvironmentLabel(alertParams.environment), threshold, triggerValue: transactionDurationFormatted, interval: `${alertParams.windowSize}${alertParams.windowUnit}`, diff --git a/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_anomaly_alert_type.ts b/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_anomaly_alert_type.ts index 4cc2324f47b9d..4ced6e6abb251 100644 --- a/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_anomaly_alert_type.ts +++ b/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_anomaly_alert_type.ts @@ -20,7 +20,6 @@ import { ProcessorEvent } from '../../../common/processor_event'; import { getSeverity } from '../../../common/anomaly_detection'; import { PROCESSOR_EVENT, - SERVICE_ENVIRONMENT, SERVICE_NAME, TRANSACTION_TYPE, } from '../../../common/elasticsearch_fieldnames'; @@ -35,7 +34,10 @@ import { import { getMLJobs } from '../service_map/get_service_anomalies'; import { apmActionVariables } from './action_variables'; import { RegisterRuleDependencies } from './register_apm_alerts'; -import { parseEnvironmentUrlParam } from '../../../common/environment_filter_values'; +import { + getEnvironmentEsField, + getEnvironmentLabel, +} from '../../../common/environment_filter_values'; const paramsSchema = schema.object({ serviceName: schema.maybe(schema.string()), @@ -222,9 +224,6 @@ export function registerTransactionDurationAnomalyAlertType({ compact(anomalies).forEach((anomaly) => { const { serviceName, environment, transactionType, score } = anomaly; - - const parsedEnvironment = parseEnvironmentUrlParam(environment); - const severityLevel = getSeverity(score); services @@ -239,9 +238,7 @@ export function registerTransactionDurationAnomalyAlertType({ .join('_'), fields: { [SERVICE_NAME]: serviceName, - ...(parsedEnvironment.esFieldValue - ? { [SERVICE_ENVIRONMENT]: environment } - : {}), + ...getEnvironmentEsField(environment), [TRANSACTION_TYPE]: transactionType, [PROCESSOR_EVENT]: ProcessorEvent.transaction, [ALERT_SEVERITY_LEVEL]: severityLevel, @@ -253,7 +250,7 @@ export function registerTransactionDurationAnomalyAlertType({ .scheduleActions(alertTypeConfig.defaultActionGroupId, { serviceName, transactionType, - environment, + environment: getEnvironmentLabel(environment), threshold: selectedOption?.label, triggerValue: severityLevel, }); diff --git a/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.ts b/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.ts index 4d6a0685fd379..47ed5236ce74c 100644 --- a/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.ts +++ b/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.ts @@ -11,6 +11,11 @@ import { ALERT_EVALUATION_THRESHOLD, ALERT_EVALUATION_VALUE, } from '@kbn/rule-data-utils/target/technical_field_names'; +import { + ENVIRONMENT_NOT_DEFINED, + getEnvironmentEsField, + getEnvironmentLabel, +} from '../../../common/environment_filter_values'; import { createLifecycleRuleTypeFactory } from '../../../../rule_registry/server'; import { AlertType, ALERT_TYPES_CONFIG } from '../../../common/alert_types'; import { @@ -123,7 +128,10 @@ export function registerTransactionErrorRateAlertType({ multi_terms: { terms: [ { field: SERVICE_NAME }, - { field: SERVICE_ENVIRONMENT, missing: '' }, + { + field: SERVICE_ENVIRONMENT, + missing: ENVIRONMENT_NOT_DEFINED.value, + }, { field: TRANSACTION_TYPE }, ], size: 10000, @@ -191,7 +199,7 @@ export function registerTransactionErrorRateAlertType({ .join('_'), fields: { [SERVICE_NAME]: serviceName, - ...(environment ? { [SERVICE_ENVIRONMENT]: environment } : {}), + ...getEnvironmentEsField(environment), [TRANSACTION_TYPE]: transactionType, [PROCESSOR_EVENT]: ProcessorEvent.transaction, [ALERT_EVALUATION_VALUE]: errorRate, @@ -201,7 +209,7 @@ export function registerTransactionErrorRateAlertType({ .scheduleActions(alertTypeConfig.defaultActionGroupId, { serviceName, transactionType, - environment, + environment: getEnvironmentLabel(environment), threshold: alertParams.threshold, triggerValue: asDecimalOrInteger(errorRate), interval: `${alertParams.windowSize}${alertParams.windowUnit}`, diff --git a/x-pack/test/apm_api_integration/tests/alerts/rule_registry.ts b/x-pack/test/apm_api_integration/tests/alerts/rule_registry.ts index 1f8d1144349dd..bbe4a7df60b40 100644 --- a/x-pack/test/apm_api_integration/tests/alerts/rule_registry.ts +++ b/x-pack/test/apm_api_integration/tests/alerts/rule_registry.ts @@ -358,7 +358,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { 50, ], "kibana.rac.alert.id": Array [ - "apm.transaction_error_rate_opbeans-go_request", + "apm.transaction_error_rate_opbeans-go_request_ENVIRONMENT_NOT_DEFINED", ], "kibana.rac.alert.producer": Array [ "apm", @@ -428,7 +428,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { 50, ], "kibana.rac.alert.id": Array [ - "apm.transaction_error_rate_opbeans-go_request", + "apm.transaction_error_rate_opbeans-go_request_ENVIRONMENT_NOT_DEFINED", ], "kibana.rac.alert.producer": Array [ "apm", @@ -530,7 +530,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { 50, ], "kibana.rac.alert.id": Array [ - "apm.transaction_error_rate_opbeans-go_request", + "apm.transaction_error_rate_opbeans-go_request_ENVIRONMENT_NOT_DEFINED", ], "kibana.rac.alert.producer": Array [ "apm",