From 008eae4bfb9cf5394985d6b177873ff48e364d05 Mon Sep 17 00:00:00 2001 From: Oliver Gupte Date: Fri, 12 Jun 2020 09:28:21 -0700 Subject: [PATCH] [APM] Service map fix missing ML health indicators for camelCased services (#68979) (#69023) * Closes #68978 by encoding service names before comparing them to ML job group names. * Code tweak for readbility Co-authored-by: Elastic Machine Co-authored-by: Elastic Machine --- .../service_map/get_service_anomalies.test.ts | 40 +++++++++++++++++++ .../lib/service_map/get_service_anomalies.ts | 27 +++++++++---- 2 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.test.ts diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.test.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.test.ts new file mode 100644 index 00000000000000..aefd074c373f95 --- /dev/null +++ b/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.test.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { getApmMlJobCategory } from './get_service_anomalies'; +import { Job as AnomalyDetectionJob } from '../../../../ml/server'; + +describe('getApmMlJobCategory', () => { + it('should match service names with different casings', () => { + const mlJob = { + job_id: 'testservice-request-high_mean_response_time', + groups: ['apm', 'testservice', 'request'], + } as AnomalyDetectionJob; + const serviceNames = ['testService']; + const apmMlJobCategory = getApmMlJobCategory(mlJob, serviceNames); + + expect(apmMlJobCategory).toEqual({ + jobId: 'testservice-request-high_mean_response_time', + serviceName: 'testService', + transactionType: 'request', + }); + }); + + it('should match service names with spaces', () => { + const mlJob = { + job_id: 'test_service-request-high_mean_response_time', + groups: ['apm', 'test_service', 'request'], + } as AnomalyDetectionJob; + const serviceNames = ['Test Service']; + const apmMlJobCategory = getApmMlJobCategory(mlJob, serviceNames); + + expect(apmMlJobCategory).toEqual({ + jobId: 'test_service-request-high_mean_response_time', + serviceName: 'Test Service', + transactionType: 'request', + }); + }); +}); diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.ts index c269ddc202b535..e96b27b10d240b 100644 --- a/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.ts +++ b/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.ts @@ -8,27 +8,40 @@ import { leftJoin } from '../../../common/utils/left_join'; import { Job as AnomalyDetectionJob } from '../../../../ml/server'; import { PromiseReturnType } from '../../../typings/common'; import { IEnvOptions } from './get_service_map'; -import { APM_ML_JOB_GROUP_NAME } from '../../../common/ml_job_constants'; +import { + APM_ML_JOB_GROUP_NAME, + encodeForMlApi, +} from '../../../common/ml_job_constants'; type ApmMlJobCategory = NonNullable>; -const getApmMlJobCategory = ( +export const getApmMlJobCategory = ( mlJob: AnomalyDetectionJob, serviceNames: string[] ) => { - const apmJobGroups = mlJob.groups.filter( - (groupName) => groupName !== APM_ML_JOB_GROUP_NAME + const serviceByGroupNameMap = new Map( + serviceNames.map((serviceName) => [ + encodeForMlApi(serviceName), + serviceName, + ]) ); - if (apmJobGroups.length === mlJob.groups.length) { + if (!mlJob.groups.includes(APM_ML_JOB_GROUP_NAME)) { // ML job missing "apm" group name return; } - const [serviceName] = intersection(apmJobGroups, serviceNames); + const apmJobGroups = mlJob.groups.filter( + (groupName) => groupName !== APM_ML_JOB_GROUP_NAME + ); + const apmJobServiceNames = apmJobGroups.map( + (groupName) => serviceByGroupNameMap.get(groupName) || groupName + ); + const [serviceName] = intersection(apmJobServiceNames, serviceNames); if (!serviceName) { // APM ML job service was not found return; } + const serviceGroupName = encodeForMlApi(serviceName); const [transactionType] = apmJobGroups.filter( - (groupName) => groupName !== serviceName + (groupName) => groupName !== serviceGroupName ); if (!transactionType) { // APM ML job transaction type was not found.