From f9c20a1702683ebe8e6affa15ab540cd2f48517e Mon Sep 17 00:00:00 2001 From: Shahzad Date: Wed, 3 Jun 2020 15:57:50 +0200 Subject: [PATCH 01/54] added rum filters and tab --- .../elasticsearch_fieldnames.test.ts.snap | 24 +++++++++++ .../apm/common/elasticsearch_fieldnames.ts | 6 +++ .../apm/common/projections/rum_overview.ts | 40 ++++++++++++++++++ .../plugins/apm/common/projections/typings.ts | 1 + .../apm/public/components/app/Home/index.tsx | 17 +++++++- .../app/Main/route_config/index.tsx | 9 ++++ .../app/Main/route_config/route_names.tsx | 1 + .../app/RumDashboard/RumDashboard.tsx | 21 ++++++++++ .../components/app/RumDashboard/index.tsx | 42 +++++++++++++++++++ .../shared/Links/apm/RumOverviewLink.tsx | 31 ++++++++++++++ .../lib/ui_filters/local_ui_filters/config.ts | 35 ++++++++++++++++ .../apm/server/routes/create_apm_api.ts | 6 ++- .../plugins/apm/server/routes/ui_filters.ts | 11 +++++ 13 files changed, 242 insertions(+), 2 deletions(-) create mode 100644 x-pack/plugins/apm/common/projections/rum_overview.ts create mode 100644 x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx create mode 100644 x-pack/plugins/apm/public/components/app/RumDashboard/index.tsx create mode 100644 x-pack/plugins/apm/public/components/shared/Links/apm/RumOverviewLink.tsx diff --git a/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap b/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap index 54dd4704edfc0..f3dc7abcf8239 100644 --- a/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap +++ b/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap @@ -4,6 +4,8 @@ exports[`Error AGENT_NAME 1`] = `"java"`; exports[`Error AGENT_VERSION 1`] = `"agent version"`; +exports[`Error CLIENT_GEO 1`] = `undefined`; + exports[`Error CLIENT_GEO_COUNTRY_ISO_CODE 1`] = `undefined`; exports[`Error CONTAINER_ID 1`] = `undefined`; @@ -122,18 +124,26 @@ exports[`Error TRANSACTION_SAMPLED 1`] = `undefined`; exports[`Error TRANSACTION_TYPE 1`] = `"request"`; +exports[`Error TRANSACTION_URL 1`] = `undefined`; + exports[`Error URL_FULL 1`] = `undefined`; +exports[`Error USER_AGENT_DEVICE 1`] = `undefined`; + exports[`Error USER_AGENT_NAME 1`] = `undefined`; exports[`Error USER_AGENT_ORIGINAL 1`] = `undefined`; +exports[`Error USER_AGENT_OS 1`] = `undefined`; + exports[`Error USER_ID 1`] = `undefined`; exports[`Span AGENT_NAME 1`] = `"java"`; exports[`Span AGENT_VERSION 1`] = `"agent version"`; +exports[`Span CLIENT_GEO 1`] = `undefined`; + exports[`Span CLIENT_GEO_COUNTRY_ISO_CODE 1`] = `undefined`; exports[`Span CONTAINER_ID 1`] = `undefined`; @@ -252,18 +262,26 @@ exports[`Span TRANSACTION_SAMPLED 1`] = `undefined`; exports[`Span TRANSACTION_TYPE 1`] = `undefined`; +exports[`Span TRANSACTION_URL 1`] = `undefined`; + exports[`Span URL_FULL 1`] = `undefined`; +exports[`Span USER_AGENT_DEVICE 1`] = `undefined`; + exports[`Span USER_AGENT_NAME 1`] = `undefined`; exports[`Span USER_AGENT_ORIGINAL 1`] = `undefined`; +exports[`Span USER_AGENT_OS 1`] = `undefined`; + exports[`Span USER_ID 1`] = `undefined`; exports[`Transaction AGENT_NAME 1`] = `"java"`; exports[`Transaction AGENT_VERSION 1`] = `"agent version"`; +exports[`Transaction CLIENT_GEO 1`] = `undefined`; + exports[`Transaction CLIENT_GEO_COUNTRY_ISO_CODE 1`] = `undefined`; exports[`Transaction CONTAINER_ID 1`] = `"container1234567890abcdef"`; @@ -382,10 +400,16 @@ exports[`Transaction TRANSACTION_SAMPLED 1`] = `true`; exports[`Transaction TRANSACTION_TYPE 1`] = `"transaction type"`; +exports[`Transaction TRANSACTION_URL 1`] = `undefined`; + exports[`Transaction URL_FULL 1`] = `"http://www.elastic.co"`; +exports[`Transaction USER_AGENT_DEVICE 1`] = `undefined`; + exports[`Transaction USER_AGENT_NAME 1`] = `"Other"`; exports[`Transaction USER_AGENT_ORIGINAL 1`] = `"test original"`; +exports[`Transaction USER_AGENT_OS 1`] = `undefined`; + exports[`Transaction USER_ID 1`] = `"1337"`; diff --git a/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts b/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts index d5c3f91eb9247..7537dba7f8411 100644 --- a/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts +++ b/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts @@ -87,3 +87,9 @@ export const CONTAINER_ID = 'container.id'; export const POD_NAME = 'kubernetes.pod.name'; export const CLIENT_GEO_COUNTRY_ISO_CODE = 'client.geo.country_iso_code'; + +// RUM Labels +export const TRANSACTION_URL = 'transaction.page.url'; +export const CLIENT_GEO = 'client.geo'; +export const USER_AGENT_DEVICE = 'user_agent.device.name'; +export const USER_AGENT_OS = 'user_agent.os.name'; diff --git a/x-pack/plugins/apm/common/projections/rum_overview.ts b/x-pack/plugins/apm/common/projections/rum_overview.ts new file mode 100644 index 0000000000000..3aa8b2aeab663 --- /dev/null +++ b/x-pack/plugins/apm/common/projections/rum_overview.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 { + Setup, + SetupTimeRange, + SetupUIFilters, + // eslint-disable-next-line @kbn/eslint/no-restricted-paths +} from '../../server/lib/helpers/setup_request'; +import { PROCESSOR_EVENT } from '../elasticsearch_fieldnames'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { rangeFilter } from '../../server/lib/helpers/range_filter'; + +export function getRumOverviewProjection({ + setup, +}: { + setup: Setup & SetupTimeRange & SetupUIFilters; +}) { + const { start, end, uiFiltersES, indices } = setup; + + const bool = { + filter: [ + { range: rangeFilter(start, end) }, + { term: { [PROCESSOR_EVENT]: 'transaction' } }, + ...uiFiltersES, + ], + }; + + return { + index: indices['apm_oss.transactionIndices'], + body: { + query: { + bool, + }, + }, + }; +} diff --git a/x-pack/plugins/apm/common/projections/typings.ts b/x-pack/plugins/apm/common/projections/typings.ts index 3361770336dde..693795b09e1d0 100644 --- a/x-pack/plugins/apm/common/projections/typings.ts +++ b/x-pack/plugins/apm/common/projections/typings.ts @@ -29,4 +29,5 @@ export enum PROJECTION { METRICS = 'metrics', ERROR_GROUPS = 'errorGroups', SERVICE_NODES = 'serviceNodes', + RUM_OVERVIEW = 'rumOverview', } diff --git a/x-pack/plugins/apm/public/components/app/Home/index.tsx b/x-pack/plugins/apm/public/components/app/Home/index.tsx index 74cbc00b17889..b47d52a8cd2e0 100644 --- a/x-pack/plugins/apm/public/components/app/Home/index.tsx +++ b/x-pack/plugins/apm/public/components/app/Home/index.tsx @@ -25,6 +25,8 @@ import { SetupInstructionsLink } from '../../shared/Links/SetupInstructionsLink' import { ServiceMap } from '../ServiceMap'; import { ServiceOverview } from '../ServiceOverview'; import { TraceOverview } from '../TraceOverview'; +import { RumOverview } from '../RumDashboard'; +import { RumOverviewLink } from '../../shared/Links/apm/RumOverviewLink'; function getHomeTabs({ serviceMapEnabled = true, @@ -68,16 +70,29 @@ function getHomeTabs({ render: () => , name: 'service-map', }); + + homeTabs.push({ + link: ( + + {i18n.translate('xpack.apm.home.rumTabLabel', { + defaultMessage: 'Real User Monitoring', + })} + + ), + render: () => , + name: 'rum-overview', + }); } return homeTabs; } + const SETTINGS_LINK_LABEL = i18n.translate('xpack.apm.settingsLinkLabel', { defaultMessage: 'Settings', }); interface Props { - tab: 'traces' | 'services' | 'service-map'; + tab: 'traces' | 'services' | 'service-map' | 'rum-overview'; } export function Home({ tab }: Props) { diff --git a/x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx b/x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx index 577af75e92d9e..295f343b411a9 100644 --- a/x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx +++ b/x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx @@ -250,4 +250,13 @@ export const routes: BreadcrumbRoute[] = [ }), name: RouteName.CUSTOMIZE_UI, }, + { + exact: true, + path: '/rum-overview', + component: () => , + breadcrumb: i18n.translate('xpack.apm.home.rumOverview.title', { + defaultMessage: 'Real User Monitoring', + }), + name: RouteName.RUM_OVERVIEW, + }, ]; diff --git a/x-pack/plugins/apm/public/components/app/Main/route_config/route_names.tsx b/x-pack/plugins/apm/public/components/app/Main/route_config/route_names.tsx index 167de1a37f427..4965aa9db8760 100644 --- a/x-pack/plugins/apm/public/components/app/Main/route_config/route_names.tsx +++ b/x-pack/plugins/apm/public/components/app/Main/route_config/route_names.tsx @@ -26,4 +26,5 @@ export enum RouteName { SERVICE_NODES = 'nodes', LINK_TO_TRACE = 'link_to_trace', CUSTOMIZE_UI = 'customize_ui', + RUM_OVERVIEW = 'rum_overview', } diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx new file mode 100644 index 0000000000000..25f62fe83a468 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx @@ -0,0 +1,21 @@ +/* + * 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 { EuiTitle } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; + +export function RumDashboard() { + return ( + +

+ {i18n.translate('xpack.apm.rum.dashboard.title', { + defaultMessage: 'End User Experience', + })} +

+
+ ); +} diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/index.tsx new file mode 100644 index 0000000000000..a84e8d4aefd7a --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/index.tsx @@ -0,0 +1,42 @@ +/* + * 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 { EuiPanel, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; +import React, { useMemo } from 'react'; +import { useTrackPageview } from '../../../../../observability/public'; +import { LocalUIFilters } from '../../shared/LocalUIFilters'; +import { PROJECTION } from '../../../../common/projections/typings'; +import { RumDashboard } from './RumOverview'; + +export function RumOverview() { + useTrackPageview({ app: 'apm', path: 'rum_overview' }); + useTrackPageview({ app: 'apm', path: 'rum_overview', delay: 15000 }); + + const localUIFiltersConfig = useMemo(() => { + const config: React.ComponentProps = { + filterNames: ['transactionUrl', 'location', 'device', 'os', 'browser'], + projection: PROJECTION.RUM_OVERVIEW, + }; + + return config; + }, []); + + return ( + <> + + + + + + + + + + + + + ); +} diff --git a/x-pack/plugins/apm/public/components/shared/Links/apm/RumOverviewLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/apm/RumOverviewLink.tsx new file mode 100644 index 0000000000000..abca9817bd69d --- /dev/null +++ b/x-pack/plugins/apm/public/components/shared/Links/apm/RumOverviewLink.tsx @@ -0,0 +1,31 @@ +/* + * 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. + */ + +/* + * 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 React from 'react'; +import { APMLink, APMLinkExtendProps } from './APMLink'; +import { useUrlParams } from '../../../../hooks/useUrlParams'; +import { pickKeys } from '../../../../../common/utils/pick_keys'; + +const RumOverviewLink = (props: APMLinkExtendProps) => { + const { urlParams } = useUrlParams(); + + const persistedFilters = pickKeys( + urlParams, + 'transactionResult', + 'host', + 'containerId', + 'podName' + ); + + return ; +}; + +export { RumOverviewLink }; diff --git a/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts b/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts index 8f35664c2599c..25a559cb07a3d 100644 --- a/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts +++ b/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts @@ -11,6 +11,11 @@ import { HOST_NAME, TRANSACTION_RESULT, SERVICE_VERSION, + TRANSACTION_URL, + USER_AGENT_NAME, + USER_AGENT_DEVICE, + CLIENT_GEO, + USER_AGENT_OS, } from '../../../../common/elasticsearch_fieldnames'; const filtersByName = { @@ -50,6 +55,36 @@ const filtersByName = { }), fieldName: SERVICE_VERSION, }, + transactionUrl: { + title: i18n.translate('xpack.apm.localFilters.titles.transactionUrl', { + defaultMessage: 'Url', + }), + fieldName: TRANSACTION_URL, + }, + browser: { + title: i18n.translate('xpack.apm.localFilters.titles.browser', { + defaultMessage: 'Browser', + }), + fieldName: USER_AGENT_NAME, + }, + device: { + title: i18n.translate('xpack.apm.localFilters.titles.device', { + defaultMessage: 'Device', + }), + fieldName: USER_AGENT_DEVICE, + }, + location: { + title: i18n.translate('xpack.apm.localFilters.titles.location', { + defaultMessage: 'Location', + }), + fieldName: CLIENT_GEO, + }, + os: { + title: i18n.translate('xpack.apm.localFilters.titles.os', { + defaultMessage: 'OS', + }), + fieldName: USER_AGENT_OS, + }, }; export type LocalUIFilterName = keyof typeof filtersByName; diff --git a/x-pack/plugins/apm/server/routes/create_apm_api.ts b/x-pack/plugins/apm/server/routes/create_apm_api.ts index 774f1f27435a2..223ebdf8dde05 100644 --- a/x-pack/plugins/apm/server/routes/create_apm_api.ts +++ b/x-pack/plugins/apm/server/routes/create_apm_api.ts @@ -58,6 +58,7 @@ import { transactionsLocalFiltersRoute, serviceNodesLocalFiltersRoute, uiFiltersEnvironmentsRoute, + rumOverviewLocalFiltersRoute, } from './ui_filters'; import { createApi } from './create_api'; import { serviceMapRoute, serviceMapServiceNodeRoute } from './service_map'; @@ -146,7 +147,10 @@ const createApmApi = () => { .add(updateCustomLinkRoute) .add(deleteCustomLinkRoute) .add(listCustomLinksRoute) - .add(customLinkTransactionRoute); + .add(customLinkTransactionRoute) + + // Rum Overview + .add(rumOverviewLocalFiltersRoute); return api; }; diff --git a/x-pack/plugins/apm/server/routes/ui_filters.ts b/x-pack/plugins/apm/server/routes/ui_filters.ts index 1b3ee8ad0df0b..97e5495a0e0aa 100644 --- a/x-pack/plugins/apm/server/routes/ui_filters.ts +++ b/x-pack/plugins/apm/server/routes/ui_filters.ts @@ -29,6 +29,7 @@ import { createRoute } from './create_route'; import { uiFiltersRt, rangeRt } from './default_api_types'; import { jsonRt } from '../../common/runtime_types/json_rt'; import { getServiceNodesProjection } from '../../common/projections/service_nodes'; +import { getRumOverviewProjection } from '../../common/projections/rum_overview'; export const uiFiltersEnvironmentsRoute = createRoute(() => ({ path: '/api/apm/ui_filters/environments', @@ -217,6 +218,16 @@ export const serviceNodesLocalFiltersRoute = createLocalFiltersRoute({ }), }); +export const rumOverviewLocalFiltersRoute = createLocalFiltersRoute({ + path: '/api/apm/ui_filters/local_filters/rumOverview', + getProjection: ({ setup }) => { + return getRumOverviewProjection({ + setup, + }); + }, + queryRt: t.type({}), +}); + type BaseQueryType = typeof localUiBaseQueryRt; type GetProjection< From 1f753716a537589ff0e6baf7158498648da9adc8 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Wed, 3 Jun 2020 16:58:39 +0200 Subject: [PATCH 02/54] update --- x-pack/plugins/apm/public/components/app/RumDashboard/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/index.tsx index a84e8d4aefd7a..3591c71c5abf0 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/index.tsx @@ -9,7 +9,7 @@ import React, { useMemo } from 'react'; import { useTrackPageview } from '../../../../../observability/public'; import { LocalUIFilters } from '../../shared/LocalUIFilters'; import { PROJECTION } from '../../../../common/projections/typings'; -import { RumDashboard } from './RumOverview'; +import { RumDashboard } from './RumDashboard'; export function RumOverview() { useTrackPageview({ app: 'apm', path: 'rum_overview' }); From f1c9bcf7cd15674d375824323f98db355aaf0240 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Fri, 5 Jun 2020 13:37:53 +0200 Subject: [PATCH 03/54] move range filter into common --- x-pack/plugins/apm/common/projections/errors.ts | 2 +- x-pack/plugins/apm/common/projections/metrics.ts | 2 +- x-pack/plugins/apm/common/projections/rum_overview.ts | 3 +-- x-pack/plugins/apm/common/projections/services.ts | 2 +- x-pack/plugins/apm/common/projections/transactions.ts | 2 +- .../apm/{server/lib/helpers => common/utils}/range_filter.ts | 0 .../plugins/apm/server/lib/errors/distribution/get_buckets.ts | 2 +- x-pack/plugins/apm/server/lib/errors/get_error_group.ts | 2 +- x-pack/plugins/apm/server/lib/service_map/get_service_map.ts | 2 +- .../lib/service_map/get_service_map_service_node_info.ts | 2 +- .../plugins/apm/server/lib/service_map/get_trace_sample_ids.ts | 2 +- .../services/annotations/get_derived_service_annotations.ts | 2 +- .../plugins/apm/server/lib/services/get_service_agent_name.ts | 2 +- .../apm/server/lib/services/get_service_transaction_types.ts | 2 +- x-pack/plugins/apm/server/lib/traces/get_trace_items.ts | 2 +- .../server/lib/transactions/avg_duration_by_browser/fetcher.ts | 2 +- .../server/lib/transactions/avg_duration_by_country/index.ts | 2 +- x-pack/plugins/apm/server/lib/transactions/breakdown/index.ts | 2 +- .../lib/transactions/charts/get_timeseries_data/fetcher.ts | 2 +- .../lib/transactions/distribution/get_buckets/fetcher.ts | 2 +- .../apm/server/lib/transactions/get_transaction/index.ts | 2 +- x-pack/plugins/apm/server/lib/ui_filters/get_environments.ts | 2 +- 22 files changed, 21 insertions(+), 22 deletions(-) rename x-pack/plugins/apm/{server/lib/helpers => common/utils}/range_filter.ts (100%) diff --git a/x-pack/plugins/apm/common/projections/errors.ts b/x-pack/plugins/apm/common/projections/errors.ts index bd397afae2243..390a8a0968102 100644 --- a/x-pack/plugins/apm/common/projections/errors.ts +++ b/x-pack/plugins/apm/common/projections/errors.ts @@ -16,7 +16,7 @@ import { ERROR_GROUP_ID, } from '../elasticsearch_fieldnames'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { rangeFilter } from '../../server/lib/helpers/range_filter'; +import { rangeFilter } from '../utils/range_filter'; export function getErrorGroupsProjection({ setup, diff --git a/x-pack/plugins/apm/common/projections/metrics.ts b/x-pack/plugins/apm/common/projections/metrics.ts index b05ec5f2ba876..45998bfe82e96 100644 --- a/x-pack/plugins/apm/common/projections/metrics.ts +++ b/x-pack/plugins/apm/common/projections/metrics.ts @@ -16,7 +16,7 @@ import { SERVICE_NODE_NAME, } from '../elasticsearch_fieldnames'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { rangeFilter } from '../../server/lib/helpers/range_filter'; +import { rangeFilter } from '../utils/range_filter'; import { SERVICE_NODE_NAME_MISSING } from '../service_nodes'; function getServiceNodeNameFilters(serviceNodeName?: string) { diff --git a/x-pack/plugins/apm/common/projections/rum_overview.ts b/x-pack/plugins/apm/common/projections/rum_overview.ts index 3aa8b2aeab663..2e17750929497 100644 --- a/x-pack/plugins/apm/common/projections/rum_overview.ts +++ b/x-pack/plugins/apm/common/projections/rum_overview.ts @@ -11,8 +11,7 @@ import { // eslint-disable-next-line @kbn/eslint/no-restricted-paths } from '../../server/lib/helpers/setup_request'; import { PROCESSOR_EVENT } from '../elasticsearch_fieldnames'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { rangeFilter } from '../../server/lib/helpers/range_filter'; +import { rangeFilter } from '../utils/range_filter'; export function getRumOverviewProjection({ setup, diff --git a/x-pack/plugins/apm/common/projections/services.ts b/x-pack/plugins/apm/common/projections/services.ts index bcfc27d720ba9..80a3471e9c30d 100644 --- a/x-pack/plugins/apm/common/projections/services.ts +++ b/x-pack/plugins/apm/common/projections/services.ts @@ -12,7 +12,7 @@ import { } from '../../server/lib/helpers/setup_request'; import { SERVICE_NAME, PROCESSOR_EVENT } from '../elasticsearch_fieldnames'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { rangeFilter } from '../../server/lib/helpers/range_filter'; +import { rangeFilter } from '../utils/range_filter'; export function getServicesProjection({ setup, diff --git a/x-pack/plugins/apm/common/projections/transactions.ts b/x-pack/plugins/apm/common/projections/transactions.ts index 99d5a04c1e722..b6cd73ca9aaad 100644 --- a/x-pack/plugins/apm/common/projections/transactions.ts +++ b/x-pack/plugins/apm/common/projections/transactions.ts @@ -17,7 +17,7 @@ import { TRANSACTION_NAME, } from '../elasticsearch_fieldnames'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { rangeFilter } from '../../server/lib/helpers/range_filter'; +import { rangeFilter } from '../utils/range_filter'; export function getTransactionsProjection({ setup, diff --git a/x-pack/plugins/apm/server/lib/helpers/range_filter.ts b/x-pack/plugins/apm/common/utils/range_filter.ts similarity index 100% rename from x-pack/plugins/apm/server/lib/helpers/range_filter.ts rename to x-pack/plugins/apm/common/utils/range_filter.ts diff --git a/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.ts b/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.ts index 7d96c490fcd70..db36ad1ede91c 100644 --- a/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.ts +++ b/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.ts @@ -10,7 +10,7 @@ import { PROCESSOR_EVENT, SERVICE_NAME, } from '../../../../common/elasticsearch_fieldnames'; -import { rangeFilter } from '../../helpers/range_filter'; +import { rangeFilter } from '../../../../common/utils/range_filter'; import { Setup, SetupTimeRange, diff --git a/x-pack/plugins/apm/server/lib/errors/get_error_group.ts b/x-pack/plugins/apm/server/lib/errors/get_error_group.ts index b157abd0b7e76..3d20f84ccfbc2 100644 --- a/x-pack/plugins/apm/server/lib/errors/get_error_group.ts +++ b/x-pack/plugins/apm/server/lib/errors/get_error_group.ts @@ -12,7 +12,7 @@ import { } from '../../../common/elasticsearch_fieldnames'; import { PromiseReturnType } from '../../../typings/common'; import { APMError } from '../../../typings/es_schemas/ui/apm_error'; -import { rangeFilter } from '../helpers/range_filter'; +import { rangeFilter } from '../../../common/utils/range_filter'; import { Setup, SetupTimeRange, diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts index 47ba9ecc78ffc..b56e3e7d2d24c 100644 --- a/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts +++ b/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts @@ -13,7 +13,7 @@ import { getMlIndex } from '../../../common/ml_job_constants'; import { getServicesProjection } from '../../../common/projections/services'; import { mergeProjection } from '../../../common/projections/util/merge_projection'; import { PromiseReturnType } from '../../../typings/common'; -import { rangeFilter } from '../helpers/range_filter'; +import { rangeFilter } from '../../../common/utils/range_filter'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { transformServiceMapResponses } from './transform_service_map_responses'; import { getServiceMapFromTraceIds } from './get_service_map_from_trace_ids'; diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.ts index d069e93397611..e521efa687388 100644 --- a/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.ts +++ b/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.ts @@ -6,7 +6,7 @@ import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { ESFilter } from '../../../typings/elasticsearch'; -import { rangeFilter } from '../helpers/range_filter'; +import { rangeFilter } from '../../../common/utils/range_filter'; import { PROCESSOR_EVENT, SERVICE_ENVIRONMENT, diff --git a/x-pack/plugins/apm/server/lib/service_map/get_trace_sample_ids.ts b/x-pack/plugins/apm/server/lib/service_map/get_trace_sample_ids.ts index 6eba84f2205a1..11c3a00f32980 100644 --- a/x-pack/plugins/apm/server/lib/service_map/get_trace_sample_ids.ts +++ b/x-pack/plugins/apm/server/lib/service_map/get_trace_sample_ids.ts @@ -5,7 +5,7 @@ */ import { uniq, take, sortBy } from 'lodash'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; -import { rangeFilter } from '../helpers/range_filter'; +import { rangeFilter } from '../../../common/utils/range_filter'; import { ESFilter } from '../../../typings/elasticsearch'; import { PROCESSOR_EVENT, diff --git a/x-pack/plugins/apm/server/lib/services/annotations/get_derived_service_annotations.ts b/x-pack/plugins/apm/server/lib/services/annotations/get_derived_service_annotations.ts index 9829c5cb25182..6da5d195cf194 100644 --- a/x-pack/plugins/apm/server/lib/services/annotations/get_derived_service_annotations.ts +++ b/x-pack/plugins/apm/server/lib/services/annotations/get_derived_service_annotations.ts @@ -7,7 +7,7 @@ import { isNumber } from 'lodash'; import { Annotation, AnnotationType } from '../../../../common/annotations'; import { SetupTimeRange, Setup } from '../../helpers/setup_request'; import { ESFilter } from '../../../../typings/elasticsearch'; -import { rangeFilter } from '../../helpers/range_filter'; +import { rangeFilter } from '../../../../common/utils/range_filter'; import { PROCESSOR_EVENT, SERVICE_NAME, diff --git a/x-pack/plugins/apm/server/lib/services/get_service_agent_name.ts b/x-pack/plugins/apm/server/lib/services/get_service_agent_name.ts index 0b016828d5f00..8d75d746c7fca 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_agent_name.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_agent_name.ts @@ -8,7 +8,7 @@ import { AGENT_NAME, SERVICE_NAME, } from '../../../common/elasticsearch_fieldnames'; -import { rangeFilter } from '../helpers/range_filter'; +import { rangeFilter } from '../../../common/utils/range_filter'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; export async function getServiceAgentName( diff --git a/x-pack/plugins/apm/server/lib/services/get_service_transaction_types.ts b/x-pack/plugins/apm/server/lib/services/get_service_transaction_types.ts index 963dea4d8322c..d88be4055dc21 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_transaction_types.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_transaction_types.ts @@ -8,7 +8,7 @@ import { SERVICE_NAME, TRANSACTION_TYPE, } from '../../../common/elasticsearch_fieldnames'; -import { rangeFilter } from '../helpers/range_filter'; +import { rangeFilter } from '../../../common/utils/range_filter'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; export async function getServiceTransactionTypes( diff --git a/x-pack/plugins/apm/server/lib/traces/get_trace_items.ts b/x-pack/plugins/apm/server/lib/traces/get_trace_items.ts index e96b323958fd7..f9374558dfeeb 100644 --- a/x-pack/plugins/apm/server/lib/traces/get_trace_items.ts +++ b/x-pack/plugins/apm/server/lib/traces/get_trace_items.ts @@ -16,7 +16,7 @@ import { import { Span } from '../../../typings/es_schemas/ui/span'; import { Transaction } from '../../../typings/es_schemas/ui/transaction'; import { APMError } from '../../../typings/es_schemas/ui/apm_error'; -import { rangeFilter } from '../helpers/range_filter'; +import { rangeFilter } from '../../../common/utils/range_filter'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { PromiseValueType } from '../../../typings/common'; diff --git a/x-pack/plugins/apm/server/lib/transactions/avg_duration_by_browser/fetcher.ts b/x-pack/plugins/apm/server/lib/transactions/avg_duration_by_browser/fetcher.ts index 90dd41cb9b0c8..e3d688b694380 100644 --- a/x-pack/plugins/apm/server/lib/transactions/avg_duration_by_browser/fetcher.ts +++ b/x-pack/plugins/apm/server/lib/transactions/avg_duration_by_browser/fetcher.ts @@ -13,7 +13,7 @@ import { USER_AGENT_NAME, TRANSACTION_DURATION, } from '../../../../common/elasticsearch_fieldnames'; -import { rangeFilter } from '../../helpers/range_filter'; +import { rangeFilter } from '../../../../common/utils/range_filter'; import { getBucketSize } from '../../helpers/get_bucket_size'; import { Options } from '.'; import { TRANSACTION_PAGE_LOAD } from '../../../../common/transaction_types'; diff --git a/x-pack/plugins/apm/server/lib/transactions/avg_duration_by_country/index.ts b/x-pack/plugins/apm/server/lib/transactions/avg_duration_by_country/index.ts index cc23055e34672..ea6213f64ee36 100644 --- a/x-pack/plugins/apm/server/lib/transactions/avg_duration_by_country/index.ts +++ b/x-pack/plugins/apm/server/lib/transactions/avg_duration_by_country/index.ts @@ -17,7 +17,7 @@ import { SetupTimeRange, SetupUIFilters, } from '../../helpers/setup_request'; -import { rangeFilter } from '../../helpers/range_filter'; +import { rangeFilter } from '../../../../common/utils/range_filter'; import { TRANSACTION_PAGE_LOAD } from '../../../../common/transaction_types'; export async function getTransactionAvgDurationByCountry({ diff --git a/x-pack/plugins/apm/server/lib/transactions/breakdown/index.ts b/x-pack/plugins/apm/server/lib/transactions/breakdown/index.ts index 713423f8953d5..5af8b9f78cec1 100644 --- a/x-pack/plugins/apm/server/lib/transactions/breakdown/index.ts +++ b/x-pack/plugins/apm/server/lib/transactions/breakdown/index.ts @@ -20,7 +20,7 @@ import { SetupTimeRange, SetupUIFilters, } from '../../helpers/setup_request'; -import { rangeFilter } from '../../helpers/range_filter'; +import { rangeFilter } from '../../../../common/utils/range_filter'; import { getMetricsDateHistogramParams } from '../../helpers/metrics'; import { MAX_KPIS } from './constants'; import { getVizColorForIndex } from '../../../../common/viz_colors'; diff --git a/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.ts b/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.ts index 71c40010a2a3f..8e19af926ce02 100644 --- a/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.ts +++ b/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.ts @@ -15,7 +15,7 @@ import { } from '../../../../../common/elasticsearch_fieldnames'; import { PromiseReturnType } from '../../../../../../observability/typings/common'; import { getBucketSize } from '../../../helpers/get_bucket_size'; -import { rangeFilter } from '../../../helpers/range_filter'; +import { rangeFilter } from '../../../../../common/utils/range_filter'; import { Setup, SetupTimeRange, diff --git a/x-pack/plugins/apm/server/lib/transactions/distribution/get_buckets/fetcher.ts b/x-pack/plugins/apm/server/lib/transactions/distribution/get_buckets/fetcher.ts index 920552d1c1aeb..3f8bf635712be 100644 --- a/x-pack/plugins/apm/server/lib/transactions/distribution/get_buckets/fetcher.ts +++ b/x-pack/plugins/apm/server/lib/transactions/distribution/get_buckets/fetcher.ts @@ -15,7 +15,7 @@ import { TRANSACTION_SAMPLED, TRANSACTION_TYPE, } from '../../../../../common/elasticsearch_fieldnames'; -import { rangeFilter } from '../../../helpers/range_filter'; +import { rangeFilter } from '../../../../../common/utils/range_filter'; import { Setup, SetupTimeRange, diff --git a/x-pack/plugins/apm/server/lib/transactions/get_transaction/index.ts b/x-pack/plugins/apm/server/lib/transactions/get_transaction/index.ts index 60dc16b6a546c..a7de93a3bf650 100644 --- a/x-pack/plugins/apm/server/lib/transactions/get_transaction/index.ts +++ b/x-pack/plugins/apm/server/lib/transactions/get_transaction/index.ts @@ -10,7 +10,7 @@ import { TRANSACTION_ID, } from '../../../../common/elasticsearch_fieldnames'; import { Transaction } from '../../../../typings/es_schemas/ui/transaction'; -import { rangeFilter } from '../../helpers/range_filter'; +import { rangeFilter } from '../../../../common/utils/range_filter'; import { Setup, SetupTimeRange, diff --git a/x-pack/plugins/apm/server/lib/ui_filters/get_environments.ts b/x-pack/plugins/apm/server/lib/ui_filters/get_environments.ts index ccbe7a19d2f82..3fca30634be6a 100644 --- a/x-pack/plugins/apm/server/lib/ui_filters/get_environments.ts +++ b/x-pack/plugins/apm/server/lib/ui_filters/get_environments.ts @@ -9,7 +9,7 @@ import { SERVICE_ENVIRONMENT, SERVICE_NAME, } from '../../../common/elasticsearch_fieldnames'; -import { rangeFilter } from '../helpers/range_filter'; +import { rangeFilter } from '../../../common/utils/range_filter'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { ENVIRONMENT_NOT_DEFINED } from '../../../common/environment_filter_values'; import { ESFilter } from '../../../typings/elasticsearch'; From 22140011618c480663571741c987c95b4402eced Mon Sep 17 00:00:00 2001 From: Shahzad Date: Fri, 5 Jun 2020 18:50:10 +0200 Subject: [PATCH 04/54] fix issue in tab condition --- .../apm/public/components/app/Home/index.tsx | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/Home/index.tsx b/x-pack/plugins/apm/public/components/app/Home/index.tsx index b47d52a8cd2e0..f612ac0d383ef 100644 --- a/x-pack/plugins/apm/public/components/app/Home/index.tsx +++ b/x-pack/plugins/apm/public/components/app/Home/index.tsx @@ -70,20 +70,20 @@ function getHomeTabs({ render: () => , name: 'service-map', }); - - homeTabs.push({ - link: ( - - {i18n.translate('xpack.apm.home.rumTabLabel', { - defaultMessage: 'Real User Monitoring', - })} - - ), - render: () => , - name: 'rum-overview', - }); } + homeTabs.push({ + link: ( + + {i18n.translate('xpack.apm.home.rumTabLabel', { + defaultMessage: 'Real User Monitoring', + })} + + ), + render: () => , + name: 'rum-overview', + }); + return homeTabs; } From 95b510b84c9b7fd457cf1b7adba031a550e5ed59 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Fri, 5 Jun 2020 22:35:54 +0200 Subject: [PATCH 05/54] add clinet --- .../app/RumDashboard/RumDashboard.tsx | 29 +++++++--- .../lib/rum_client/get_client_metrics.ts | 57 +++++++++++++++++++ .../apm/server/routes/create_apm_api.ts | 4 +- .../plugins/apm/server/routes/rum_client.ts | 33 +++++++++++ 4 files changed, 114 insertions(+), 9 deletions(-) create mode 100644 x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts create mode 100644 x-pack/plugins/apm/server/routes/rum_client.ts diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx index 25f62fe83a468..06ac9090fc030 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx @@ -4,18 +4,31 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiTitle } from '@elastic/eui'; +import { EuiStat, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; +import { useFetcher } from '../../../hooks/useFetcher'; export function RumDashboard() { + const { + date: { avg }, + } = useFetcher((callApmApi) => { + return callApmApi({ + pathname: '/api/apm/rum-client/metrics', + params: {}, + }); + }, []); + return ( - -

- {i18n.translate('xpack.apm.rum.dashboard.title', { - defaultMessage: 'End User Experience', - })} -

-
+ <> + +

+ {i18n.translate('xpack.apm.rum.dashboard.title', { + defaultMessage: 'End User Experience', + })} +

+
+ + ); } diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts b/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts new file mode 100644 index 0000000000000..ba3bbffb5a07f --- /dev/null +++ b/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts @@ -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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { getServicesProjection } from '../../../common/projections/services'; +import { mergeProjection } from '../../../common/projections/util/merge_projection'; +import { + AGENT_NAME, + SERVICE_ENVIRONMENT, + SERVICE_NAME, +} from '../../../common/elasticsearch_fieldnames'; +import { IEnvOptions } from '../service_map/get_service_map'; + +export async function getClientMetrics(options: IEnvOptions) { + const { setup } = options; + + const projection = getServicesProjection({ + setup: { ...setup, uiFiltersES: [] }, + }); + + const { filter } = projection.body.query.bool; + + const params = mergeProjection(projection, { + body: { + size: 0, + query: { + bool: { + ...projection.body.query.bool, + filter: options.serviceName + ? filter.concat({ + term: { + [SERVICE_NAME]: options.serviceName, + }, + }) + : filter, + }, + }, + aggs: { + metrics: { + stats: { + field: 'transaction.marks.agent.timeToFirstByte', + // field: projection.body.aggs.services.terms.field, + missing: 0, + }, + }, + }, + }, + }); + + const { client } = setup; + + const response = await client.search(params); + + return response.aggregations?.metrics; +} diff --git a/x-pack/plugins/apm/server/routes/create_apm_api.ts b/x-pack/plugins/apm/server/routes/create_apm_api.ts index 223ebdf8dde05..0d9f35d88c578 100644 --- a/x-pack/plugins/apm/server/routes/create_apm_api.ts +++ b/x-pack/plugins/apm/server/routes/create_apm_api.ts @@ -70,6 +70,7 @@ import { listCustomLinksRoute, customLinkTransactionRoute, } from './settings/custom_link'; +import { rumClientRoute } from './rum_client'; const createApmApi = () => { const api = createApi() @@ -150,7 +151,8 @@ const createApmApi = () => { .add(customLinkTransactionRoute) // Rum Overview - .add(rumOverviewLocalFiltersRoute); + .add(rumOverviewLocalFiltersRoute) + .add(rumClientRoute); return api; }; diff --git a/x-pack/plugins/apm/server/routes/rum_client.ts b/x-pack/plugins/apm/server/routes/rum_client.ts new file mode 100644 index 0000000000000..f428bb4a7920e --- /dev/null +++ b/x-pack/plugins/apm/server/routes/rum_client.ts @@ -0,0 +1,33 @@ +/* + * 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 Boom from 'boom'; +import { createRoute } from './create_route'; +import { + invalidLicenseMessage, + isValidPlatinumLicense, +} from '../../common/service_map'; +import { setupRequest } from '../lib/helpers/setup_request'; +import { getClientMetrics } from '../lib/rum_client/get_client_metrics'; + +export const rumClientRoute = createRoute(() => ({ + path: '/api/apm/rum-client/metrics', + params: {}, + handler: async ({ context, request }) => { + if (!context.config['xpack.apm.serviceMapEnabled']) { + throw Boom.notFound(); + } + if (!isValidPlatinumLicense(context.licensing.license)) { + throw Boom.forbidden(invalidLicenseMessage); + } + + const setup = await setupRequest(context, request); + const { + query: { serviceName, environment }, + } = context.params; + return getClientMetrics({ setup, serviceName, environment }); + }, +})); From b818fbd26588895eff3bed217097ed9a3768631e Mon Sep 17 00:00:00 2001 From: Shahzad Date: Mon, 8 Jun 2020 09:25:59 +0200 Subject: [PATCH 06/54] update --- .../app/RumDashboard/ClientMetrics/index.tsx | 54 +++++++ .../RumDashboard/ImpressionTrend/index.tsx | 73 +++++++++ .../PageLoadDistribution/index.tsx | 94 ++++++++++++ .../app/RumDashboard/RumDashboard.tsx | 25 ++-- .../lib/rum_client/get_client_metrics.ts | 29 ++-- .../lib/rum_client/get_impression_trends.ts | 65 +++++++++ .../rum_client/get_page_load_distribution.ts | 138 ++++++++++++++++++ .../apm/server/routes/create_apm_api.ts | 10 +- .../plugins/apm/server/routes/rum_client.ts | 39 ++++- 9 files changed, 498 insertions(+), 29 deletions(-) create mode 100644 x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx create mode 100644 x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx create mode 100644 x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx create mode 100644 x-pack/plugins/apm/server/lib/rum_client/get_impression_trends.ts create mode 100644 x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx new file mode 100644 index 0000000000000..5f51d4e7e426c --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx @@ -0,0 +1,54 @@ +/* + * 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. + */ +// @flow +import * as React from 'react'; +import { EuiSpacer, EuiStat } from '@elastic/eui'; +import { useFetcher } from '../../../../hooks/useFetcher'; +import { useUrlParams } from '../../../../hooks/useUrlParams'; + +export const ClientMetrics = () => { + const { urlParams, uiFilters } = useUrlParams(); + + const { serviceName, start, end } = urlParams; + + const { data } = useFetcher((callApmApi) => { + return callApmApi({ + pathname: '/api/apm/rum-client/metrics', + params: { + // path: { + // serviceName, + // }, + query: { + // start, + // end, + // uiFilters: JSON.stringify(uiFilters), + }, + }, + }); + }, []); + return ( + <> + + + + + + + + ); +}; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx new file mode 100644 index 0000000000000..58e5b54ca897b --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx @@ -0,0 +1,73 @@ +/* + * 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. + */ +// @flow +import * as React from 'react'; +import { EuiSpacer, EuiStat } from '@elastic/eui'; +import { + Axis, + BarSeries, + Chart, + niceTimeFormatByDay, + ScaleType, + Settings, + timeFormatter, +} from '@elastic/charts'; +import { Position } from '@elastic/charts/dist/utils/commons'; +import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import { useUrlParams } from '../../../../hooks/useUrlParams'; +import { useFetcher } from '../../../../hooks/useFetcher'; + +export const ImpressionTrend = () => { + const { urlParams, uiFilters } = useUrlParams(); + + const { serviceName, start, end } = urlParams; + + const { data } = useFetcher((callApmApi) => { + return callApmApi({ + pathname: '/api/apm/rum-client/impression-trend', + params: { + // path: { + // serviceName, + // }, + query: { + // start, + // end, + // uiFilters: JSON.stringify(uiFilters), + }, + }, + }); + }, []); + const formatter = timeFormatter(niceTimeFormatByDay(2)); + + return ( +
+ + + + + + + +
+ ); +}; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx new file mode 100644 index 0000000000000..7634bc998ffcd --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx @@ -0,0 +1,94 @@ +/* + * 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. + */ +// @flow +import * as React from 'react'; +import { EuiSpacer, EuiStat } from '@elastic/eui'; +import { + AnnotationDomainTypes, + AreaSeries, + Axis, + Chart, + LineAnnotation, + LineAnnotationDatum, + ScaleType, +} from '@elastic/charts'; +import { Position } from '@elastic/charts/dist/utils/commons'; +import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import { useUrlParams } from '../../../../hooks/useUrlParams'; +import { useFetcher } from '../../../../hooks/useFetcher'; + +function generateAnnotationData(values: any[]): LineAnnotationDatum[] { + return Object.entries(values).map((value, index) => ({ + dataValue: value[1], + details: `detail-${value[0]}`, + })); +} + +export const PageLoadDistribution = () => { + const { urlParams, uiFilters } = useUrlParams(); + + const { serviceName, start, end } = urlParams; + + const { data } = useFetcher((callApmApi) => { + return callApmApi({ + pathname: '/api/apm/rum-client/page-load-distribution', + params: { + // path: { + // serviceName, + // }, + query: { + // start, + // end, + // uiFilters: JSON.stringify(uiFilters), + }, + }, + }); + }, []); + const dataValues = generateAnnotationData(data?.percentiles ?? []); + const style = { + line: { + strokeWidth: 3, + stroke: euiLightVars.euiColorLightShade, + opacity: 1, + }, + details: { + fontSize: 12, + fontFamily: 'Arial', + fontStyle: 'bold', + fill: 'gray', + padding: 0, + }, + }; + return ( +
+ + + %} + /> + + Number(d).toFixed(2) + '%'} + /> + + +
+ ); +}; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx index 06ac9090fc030..5bf2f46444add 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx @@ -4,21 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiStat, EuiTitle } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; -import { useFetcher } from '../../../hooks/useFetcher'; +import { ClientMetrics } from './ClientMetrics'; +import { ImpressionTrend } from './ImpressionTrend'; +import { PageLoadDistribution } from './PageLoadDistribution'; export function RumDashboard() { - const { - date: { avg }, - } = useFetcher((callApmApi) => { - return callApmApi({ - pathname: '/api/apm/rum-client/metrics', - params: {}, - }); - }, []); - return ( <> @@ -28,7 +21,15 @@ export function RumDashboard() { })} - + + + + + + + + + ); } diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts b/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts index ba3bbffb5a07f..31042fe5b8aba 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts @@ -28,23 +28,32 @@ export async function getClientMetrics(options: IEnvOptions) { query: { bool: { ...projection.body.query.bool, - filter: options.serviceName - ? filter.concat({ - term: { - [SERVICE_NAME]: options.serviceName, - }, - }) - : filter, + filter: filter.concat({ + term: { + 'transaction.type': 'page-load', + }, + }), }, }, aggs: { - metrics: { + pageViews: { value_count: { field: 'transaction.type' } }, + backEnd: { stats: { field: 'transaction.marks.agent.timeToFirstByte', - // field: projection.body.aggs.services.terms.field, missing: 0, }, }, + frontEnd: { + stats: { + script: { + lang: 'painless', + source: ` + if(doc[\'transaction.marks.agent.timeToFirstByte\'].size()!==0 && doc[\'transaction.marks.agent.domInteractive\'].size()!==0) { + doc[\'transaction.marks.agent.domInteractive\'].value - doc[\'transaction.marks.agent.timeToFirstByte\'].value + }`, + }, + }, + }, }, }, }); @@ -53,5 +62,5 @@ export async function getClientMetrics(options: IEnvOptions) { const response = await client.search(params); - return response.aggregations?.metrics; + return response.aggregations; } diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_impression_trends.ts b/x-pack/plugins/apm/server/lib/rum_client/get_impression_trends.ts new file mode 100644 index 0000000000000..70b0a61d35c8e --- /dev/null +++ b/x-pack/plugins/apm/server/lib/rum_client/get_impression_trends.ts @@ -0,0 +1,65 @@ +/* + * 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 { getServicesProjection } from '../../../common/projections/services'; +import { mergeProjection } from '../../../common/projections/util/merge_projection'; +import { + AGENT_NAME, + SERVICE_ENVIRONMENT, + SERVICE_NAME, +} from '../../../common/elasticsearch_fieldnames'; +import { IEnvOptions } from '../service_map/get_service_map'; + +export async function getImpressionTrends(options: IEnvOptions) { + const { setup } = options; + + const projection = getServicesProjection({ + setup: { ...setup, uiFiltersES: [] }, + }); + + const { filter } = projection.body.query.bool; + + const params = mergeProjection(projection, { + body: { + size: 0, + query: { + bool: { + ...projection.body.query.bool, + filter: filter.concat({ + term: { + 'transaction.type': 'page-load', + }, + }), + }, + }, + aggs: { + impressions: { + auto_date_histogram: { + field: '@timestamp', + buckets: 50, + }, + aggs: { + trans_count: { + value_count: { + field: 'transaction.type', + }, + }, + }, + }, + }, + }, + }); + + const { client } = setup; + + const response = await client.search(params); + + const result = response.aggregations.impressions.buckets; + return result.map(({ key, trans_count }) => ({ + x: key, + y: trans_count.value, + })); +} diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts b/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts new file mode 100644 index 0000000000000..dc50314e3e86c --- /dev/null +++ b/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts @@ -0,0 +1,138 @@ +/* + * 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 { getServicesProjection } from '../../../common/projections/services'; +import { mergeProjection } from '../../../common/projections/util/merge_projection'; +import { + AGENT_NAME, + SERVICE_ENVIRONMENT, + SERVICE_NAME, +} from '../../../common/elasticsearch_fieldnames'; +import { IEnvOptions } from '../service_map/get_service_map'; + +export async function getPageLoadDistribution(options: IEnvOptions) { + const { setup } = options; + + const projection = getServicesProjection({ + setup: { ...setup, uiFiltersES: [] }, + }); + + const { filter } = projection.body.query.bool; + + const params = mergeProjection(projection, { + body: { + size: 0, + query: { + bool: { + ...projection.body.query.bool, + filter: filter.concat({ + term: { + 'transaction.type': 'page-load', + }, + }), + }, + }, + aggs: { + durationMinMax: { + stats: { + field: 'transaction.duration.us', + }, + }, + durationPercentiles: { + percentiles: { + field: 'transaction.duration.us', + percents: [50, 80, 90, 95, 96], + script: { + lang: 'painless', + source: "doc['transaction.duration.us'].value / params.timeUnit", + params: { + timeUnit: 1000, + }, + }, + }, + }, + }, + }, + }); + + const { client } = setup; + + const response = await client.search(params); + + const minDuration = response.aggregations.durationMinMax.min / 1000; + const durationPercentiles = response.aggregations.durationPercentiles.values; + const maxPercentile = durationPercentiles['96.0']; + const pageDist = await getPercentilesDistribution( + options, + minDuration, + maxPercentile + ); + return { pageLoadDistribution: pageDist, percentiles: durationPercentiles }; +} + +const getPercentilesDistribution = async ( + options: IEnvOptions, + minPercentiles: number, + maxPercentile: number +) => { + const stepValue = (maxPercentile - minPercentiles) / 100; + const stepValues = []; + for (let i = 1; i < 100; i++) { + stepValues.push((stepValue * i + minPercentiles).toFixed(2)); + } + + const { setup } = options; + + const projection = getServicesProjection({ + setup: { ...setup, uiFiltersES: [] }, + }); + + const { filter } = projection.body.query.bool; + + const params = mergeProjection(projection, { + body: { + size: 0, + query: { + bool: { + ...projection.body.query.bool, + filter: filter.concat({ + term: { + 'transaction.type': 'page-load', + }, + }), + }, + }, + aggs: { + loadDistribution: { + percentile_ranks: { + field: 'transaction.duration.us', + values: stepValues, + keyed: false, + script: { + lang: 'painless', + source: "doc['transaction.duration.us'].value / params.timeUnit", + params: { + timeUnit: 1000, + }, + }, + }, + }, + }, + }, + }); + + const { client } = setup; + + const response = await client.search(params); + + const pageDist = response.aggregations.loadDistribution.values; + return pageDist.map(({ key, value }, index, arr) => { + return { + x: key, + y: index === 0 ? value : value - arr[index - 1].value, + }; + }); +}; diff --git a/x-pack/plugins/apm/server/routes/create_apm_api.ts b/x-pack/plugins/apm/server/routes/create_apm_api.ts index 0d9f35d88c578..6ecc5e6ae5d5d 100644 --- a/x-pack/plugins/apm/server/routes/create_apm_api.ts +++ b/x-pack/plugins/apm/server/routes/create_apm_api.ts @@ -70,7 +70,11 @@ import { listCustomLinksRoute, customLinkTransactionRoute, } from './settings/custom_link'; -import { rumClientRoute } from './rum_client'; +import { + rumClientMetricsRoute, + rumImpressionTrendRoute, + rumPageLoadDistributionRoute, +} from './rum_client'; const createApmApi = () => { const api = createApi() @@ -152,7 +156,9 @@ const createApmApi = () => { // Rum Overview .add(rumOverviewLocalFiltersRoute) - .add(rumClientRoute); + .add(rumImpressionTrendRoute) + .add(rumPageLoadDistributionRoute) + .add(rumClientMetricsRoute); return api; }; diff --git a/x-pack/plugins/apm/server/routes/rum_client.ts b/x-pack/plugins/apm/server/routes/rum_client.ts index f428bb4a7920e..fe8c7e830da01 100644 --- a/x-pack/plugins/apm/server/routes/rum_client.ts +++ b/x-pack/plugins/apm/server/routes/rum_client.ts @@ -12,14 +12,13 @@ import { } from '../../common/service_map'; import { setupRequest } from '../lib/helpers/setup_request'; import { getClientMetrics } from '../lib/rum_client/get_client_metrics'; +import { rangeRt } from './default_api_types'; +import { getImpressionTrends } from '../lib/rum_client/get_impression_trends'; +import { getPageLoadDistribution } from '../lib/rum_client/get_page_load_distribution'; -export const rumClientRoute = createRoute(() => ({ +export const rumClientMetricsRoute = createRoute(() => ({ path: '/api/apm/rum-client/metrics', - params: {}, handler: async ({ context, request }) => { - if (!context.config['xpack.apm.serviceMapEnabled']) { - throw Boom.notFound(); - } if (!isValidPlatinumLicense(context.licensing.license)) { throw Boom.forbidden(invalidLicenseMessage); } @@ -31,3 +30,33 @@ export const rumClientRoute = createRoute(() => ({ return getClientMetrics({ setup, serviceName, environment }); }, })); + +export const rumPageLoadDistributionRoute = createRoute(() => ({ + path: '/api/apm/rum-client/page-load-distribution', + handler: async ({ context, request }) => { + if (!isValidPlatinumLicense(context.licensing.license)) { + throw Boom.forbidden(invalidLicenseMessage); + } + + const setup = await setupRequest(context, request); + const { + query: { serviceName, environment }, + } = context.params; + return getPageLoadDistribution({ setup, serviceName, environment }); + }, +})); + +export const rumImpressionTrendRoute = createRoute(() => ({ + path: '/api/apm/rum-client/impression-trend', + handler: async ({ context, request }) => { + if (!isValidPlatinumLicense(context.licensing.license)) { + throw Boom.forbidden(invalidLicenseMessage); + } + + const setup = await setupRequest(context, request); + const { + query: { serviceName, environment }, + } = context.params; + return getImpressionTrends({ setup, serviceName, environment }); + }, +})); From 3cd29fb0176472e178e149bbcb69b532756024d0 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Mon, 8 Jun 2020 14:56:29 +0200 Subject: [PATCH 07/54] added transactiont type filter --- x-pack/plugins/apm/common/projections/rum_overview.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/apm/common/projections/rum_overview.ts b/x-pack/plugins/apm/common/projections/rum_overview.ts index 2e17750929497..e6e674671f54b 100644 --- a/x-pack/plugins/apm/common/projections/rum_overview.ts +++ b/x-pack/plugins/apm/common/projections/rum_overview.ts @@ -10,7 +10,7 @@ import { SetupUIFilters, // eslint-disable-next-line @kbn/eslint/no-restricted-paths } from '../../server/lib/helpers/setup_request'; -import { PROCESSOR_EVENT } from '../elasticsearch_fieldnames'; +import { PROCESSOR_EVENT, TRANSACTION_TYPE } from '../elasticsearch_fieldnames'; import { rangeFilter } from '../utils/range_filter'; export function getRumOverviewProjection({ @@ -24,6 +24,7 @@ export function getRumOverviewProjection({ filter: [ { range: rangeFilter(start, end) }, { term: { [PROCESSOR_EVENT]: 'transaction' } }, + { term: { [TRANSACTION_TYPE]: 'page-load' } }, ...uiFiltersES, ], }; From 5a6c41a730ef1335ca80623b852709b1e7c4db44 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Mon, 8 Jun 2020 19:57:25 +0200 Subject: [PATCH 08/54] update --- .../app/RumDashboard/ChartWrapper/index.tsx | 63 +++++++++++++++ .../app/RumDashboard/ClientMetrics/index.tsx | 31 ++++---- .../PageLoadDistribution/index.tsx | 79 ++++++++++--------- .../lib/rum_client/get_client_metrics.ts | 27 ++++--- .../rum_client/get_page_load_distribution.ts | 42 +++++----- .../plugins/apm/server/routes/rum_client.ts | 31 ++++---- 6 files changed, 171 insertions(+), 102 deletions(-) create mode 100644 x-pack/plugins/apm/public/components/app/RumDashboard/ChartWrapper/index.tsx diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ChartWrapper/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ChartWrapper/index.tsx new file mode 100644 index 0000000000000..a3cfbb28abee2 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ChartWrapper/index.tsx @@ -0,0 +1,63 @@ +/* + * 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 React, { FC, HTMLAttributes } from 'react'; +import { + EuiErrorBoundary, + EuiFlexGroup, + EuiFlexItem, + EuiLoadingChart, +} from '@elastic/eui'; + +interface Props { + /** + * Height for the chart + */ + height?: string; + /** + * if chart data source is still loading + */ + loading?: boolean; + /** + * aria-label for accessibility + */ + 'aria-label'?: string; +} + +export const ChartWrapper: FC = ({ + loading = false, + height = '100%', + children, + ...rest +}) => { + const opacity = loading === true ? 0.3 : 1; + + return ( + +
)} + > + {children} +
+ {loading === true && ( + + + + + + )} +
+ ); +}; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx index 5f51d4e7e426c..2e4047498d172 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx @@ -12,29 +12,26 @@ import { useUrlParams } from '../../../../hooks/useUrlParams'; export const ClientMetrics = () => { const { urlParams, uiFilters } = useUrlParams(); - const { serviceName, start, end } = urlParams; + const { start, end } = urlParams; - const { data } = useFetcher((callApmApi) => { - return callApmApi({ - pathname: '/api/apm/rum-client/metrics', - params: { - // path: { - // serviceName, - // }, - query: { - // start, - // end, - // uiFilters: JSON.stringify(uiFilters), + const { data } = useFetcher( + (callApmApi) => { + return callApmApi({ + pathname: '/api/apm/rum/client-metrics', + params: { + query: { start, end, uiFilters: JSON.stringify(uiFilters) }, }, - }, - }); - }, []); + }); + }, + [start, end, uiFilters] + ); + return ( <> @@ -46,7 +43,7 @@ export const ClientMetrics = () => { diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx index 7634bc998ffcd..5524ebc1799ce 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx @@ -19,6 +19,7 @@ import { Position } from '@elastic/charts/dist/utils/commons'; import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; import { useUrlParams } from '../../../../hooks/useUrlParams'; import { useFetcher } from '../../../../hooks/useFetcher'; +import { ChartWrapper } from '../ChartWrapper'; function generateAnnotationData(values: any[]): LineAnnotationDatum[] { return Object.entries(values).map((value, index) => ({ @@ -30,23 +31,23 @@ function generateAnnotationData(values: any[]): LineAnnotationDatum[] { export const PageLoadDistribution = () => { const { urlParams, uiFilters } = useUrlParams(); - const { serviceName, start, end } = urlParams; + const { start, end } = urlParams; - const { data } = useFetcher((callApmApi) => { - return callApmApi({ - pathname: '/api/apm/rum-client/page-load-distribution', - params: { - // path: { - // serviceName, - // }, - query: { - // start, - // end, - // uiFilters: JSON.stringify(uiFilters), + const { data, status } = useFetcher( + (callApmApi) => { + return callApmApi({ + pathname: '/api/apm/rum-client/page-load-distribution', + params: { + query: { + start, + end, + uiFilters: JSON.stringify(uiFilters), + }, }, - }, - }); - }, []); + }); + }, + [end, start, uiFilters] + ); const dataValues = generateAnnotationData(data?.percentiles ?? []); const style = { line: { @@ -65,30 +66,30 @@ export const PageLoadDistribution = () => { return (
- - %} - /> - - Number(d).toFixed(2) + '%'} - /> - - + + + %} + /> + + Number(d).toFixed(2) + '%'} + /> + + +
); }; diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts b/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts index 31042fe5b8aba..577b2f0870a71 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts @@ -4,20 +4,21 @@ * you may not use this file except in compliance with the Elastic License. */ -import { getServicesProjection } from '../../../common/projections/services'; +import { getRumOverviewProjection } from '../../../common/projections/rum_overview'; import { mergeProjection } from '../../../common/projections/util/merge_projection'; import { - AGENT_NAME, - SERVICE_ENVIRONMENT, - SERVICE_NAME, -} from '../../../common/elasticsearch_fieldnames'; -import { IEnvOptions } from '../service_map/get_service_map'; + Setup, + SetupTimeRange, + SetupUIFilters, +} from '../helpers/setup_request'; -export async function getClientMetrics(options: IEnvOptions) { - const { setup } = options; - - const projection = getServicesProjection({ - setup: { ...setup, uiFiltersES: [] }, +export async function getClientMetrics({ + setup, +}: { + setup: Setup & SetupTimeRange & SetupUIFilters; +}) { + const projection = getRumOverviewProjection({ + setup, }); const { filter } = projection.body.query.bool; @@ -38,13 +39,13 @@ export async function getClientMetrics(options: IEnvOptions) { aggs: { pageViews: { value_count: { field: 'transaction.type' } }, backEnd: { - stats: { + avg: { field: 'transaction.marks.agent.timeToFirstByte', missing: 0, }, }, frontEnd: { - stats: { + avg: { script: { lang: 'painless', source: ` diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts b/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts index dc50314e3e86c..82f7dbd146d6c 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts @@ -4,20 +4,22 @@ * you may not use this file except in compliance with the Elastic License. */ +import { getRumOverviewProjection } from '../../../common/projections/rum_overview'; import { getServicesProjection } from '../../../common/projections/services'; import { mergeProjection } from '../../../common/projections/util/merge_projection'; import { - AGENT_NAME, - SERVICE_ENVIRONMENT, - SERVICE_NAME, -} from '../../../common/elasticsearch_fieldnames'; -import { IEnvOptions } from '../service_map/get_service_map'; - -export async function getPageLoadDistribution(options: IEnvOptions) { - const { setup } = options; - - const projection = getServicesProjection({ - setup: { ...setup, uiFiltersES: [] }, + Setup, + SetupTimeRange, + SetupUIFilters, +} from '../helpers/setup_request'; + +export async function getPageLoadDistribution({ + setup, +}: { + setup: Setup & SetupTimeRange & SetupUIFilters; +}) { + const projection = getRumOverviewProjection({ + setup, }); const { filter } = projection.body.query.bool; @@ -37,8 +39,9 @@ export async function getPageLoadDistribution(options: IEnvOptions) { }, aggs: { durationMinMax: { - stats: { + min: { field: 'transaction.duration.us', + missing: 0, }, }, durationPercentiles: { @@ -62,7 +65,7 @@ export async function getPageLoadDistribution(options: IEnvOptions) { const response = await client.search(params); - const minDuration = response.aggregations.durationMinMax.min / 1000; + const minDuration = response.aggregations.durationMinMax.value! / 1000; const durationPercentiles = response.aggregations.durationPercentiles.values; const maxPercentile = durationPercentiles['96.0']; const pageDist = await getPercentilesDistribution( @@ -70,11 +73,14 @@ export async function getPageLoadDistribution(options: IEnvOptions) { minDuration, maxPercentile ); - return { pageLoadDistribution: pageDist, percentiles: durationPercentiles }; + return { + pageLoadDistribution: pageDist, + percentiles: durationPercentiles, + }; } const getPercentilesDistribution = async ( - options: IEnvOptions, + setup: Setup & SetupTimeRange & SetupUIFilters, minPercentiles: number, maxPercentile: number ) => { @@ -84,10 +90,8 @@ const getPercentilesDistribution = async ( stepValues.push((stepValue * i + minPercentiles).toFixed(2)); } - const { setup } = options; - - const projection = getServicesProjection({ - setup: { ...setup, uiFiltersES: [] }, + const projection = getRumOverviewProjection({ + setup, }); const { filter } = projection.body.query.bool; diff --git a/x-pack/plugins/apm/server/routes/rum_client.ts b/x-pack/plugins/apm/server/routes/rum_client.ts index fe8c7e830da01..5b125803653f6 100644 --- a/x-pack/plugins/apm/server/routes/rum_client.ts +++ b/x-pack/plugins/apm/server/routes/rum_client.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import * as t from 'io-ts'; import Boom from 'boom'; import { createRoute } from './create_route'; import { @@ -12,51 +13,53 @@ import { } from '../../common/service_map'; import { setupRequest } from '../lib/helpers/setup_request'; import { getClientMetrics } from '../lib/rum_client/get_client_metrics'; -import { rangeRt } from './default_api_types'; +import { rangeRt, uiFiltersRt } from './default_api_types'; import { getImpressionTrends } from '../lib/rum_client/get_impression_trends'; import { getPageLoadDistribution } from '../lib/rum_client/get_page_load_distribution'; export const rumClientMetricsRoute = createRoute(() => ({ - path: '/api/apm/rum-client/metrics', + path: '/api/apm/rum/client-metrics', + params: { + query: t.intersection([uiFiltersRt, rangeRt]), + }, handler: async ({ context, request }) => { if (!isValidPlatinumLicense(context.licensing.license)) { throw Boom.forbidden(invalidLicenseMessage); } const setup = await setupRequest(context, request); - const { - query: { serviceName, environment }, - } = context.params; - return getClientMetrics({ setup, serviceName, environment }); + + return getClientMetrics({ setup }); }, })); export const rumPageLoadDistributionRoute = createRoute(() => ({ path: '/api/apm/rum-client/page-load-distribution', + params: { + query: t.intersection([uiFiltersRt, rangeRt]), + }, handler: async ({ context, request }) => { if (!isValidPlatinumLicense(context.licensing.license)) { throw Boom.forbidden(invalidLicenseMessage); } const setup = await setupRequest(context, request); - const { - query: { serviceName, environment }, - } = context.params; - return getPageLoadDistribution({ setup, serviceName, environment }); + + return getPageLoadDistribution({ setup }); }, })); export const rumImpressionTrendRoute = createRoute(() => ({ path: '/api/apm/rum-client/impression-trend', + params: { + query: t.intersection([uiFiltersRt, rangeRt]), + }, handler: async ({ context, request }) => { if (!isValidPlatinumLicense(context.licensing.license)) { throw Boom.forbidden(invalidLicenseMessage); } const setup = await setupRequest(context, request); - const { - query: { serviceName, environment }, - } = context.params; - return getImpressionTrends({ setup, serviceName, environment }); + return getImpressionTrends({ setup }); }, })); From 60ac2ebcdb8b3dc304474e458b26f103f24038cf Mon Sep 17 00:00:00 2001 From: Shahzad Date: Tue, 9 Jun 2020 16:07:48 +0200 Subject: [PATCH 09/54] update --- .../RumDashboard/ImpressionTrend/index.tsx | 90 ++++++++++--------- .../PageLoadDistribution/index.tsx | 17 ++-- .../app/RumDashboard/RumDashboard.tsx | 3 +- .../lib/rum_client/get_client_metrics.ts | 29 +++--- .../lib/rum_client/get_impression_trends.ts | 38 ++++---- .../rum_client/get_page_load_distribution.ts | 52 ++++------- .../plugins/apm/server/routes/rum_client.ts | 17 ---- .../apm/typings/elasticsearch/aggregations.ts | 26 ++++++ 8 files changed, 133 insertions(+), 139 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx index 58e5b54ca897b..0a31de1b66d7e 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx @@ -5,7 +5,7 @@ */ // @flow import * as React from 'react'; -import { EuiSpacer, EuiStat } from '@elastic/eui'; +import { EuiSpacer, EuiTitle } from '@elastic/eui'; import { Axis, BarSeries, @@ -19,55 +19,65 @@ import { Position } from '@elastic/charts/dist/utils/commons'; import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; import { useUrlParams } from '../../../../hooks/useUrlParams'; import { useFetcher } from '../../../../hooks/useFetcher'; +import { ChartWrapper } from '../ChartWrapper'; export const ImpressionTrend = () => { const { urlParams, uiFilters } = useUrlParams(); - const { serviceName, start, end } = urlParams; + const { start, end } = urlParams; - const { data } = useFetcher((callApmApi) => { - return callApmApi({ - pathname: '/api/apm/rum-client/impression-trend', - params: { - // path: { - // serviceName, - // }, - query: { - // start, - // end, - // uiFilters: JSON.stringify(uiFilters), + const { data, status } = useFetcher( + (callApmApi) => { + return callApmApi({ + pathname: '/api/apm/rum-client/impression-trend', + params: { + query: { + start, + end, + uiFilters: JSON.stringify(uiFilters), + }, }, - }, - }); - }, []); + }); + }, + [end, start, uiFilters] + ); const formatter = timeFormatter(niceTimeFormatByDay(2)); return ( -
+
- - - - - - + +

Impressions trends

+
+ + + + + + + +
); }; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx index 5524ebc1799ce..b11171692d2d3 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx @@ -5,15 +5,16 @@ */ // @flow import * as React from 'react'; -import { EuiSpacer, EuiStat } from '@elastic/eui'; +import { EuiSpacer, EuiTitle } from '@elastic/eui'; import { AnnotationDomainTypes, - AreaSeries, Axis, Chart, LineAnnotation, LineAnnotationDatum, ScaleType, + LineSeries, + CurveType, } from '@elastic/charts'; import { Position } from '@elastic/charts/dist/utils/commons'; import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; @@ -64,8 +65,11 @@ export const PageLoadDistribution = () => { }, }; return ( -
+
+ +

Page load distribution

+
{ Number(d).toFixed(2) + '%'} /> - diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx index 5bf2f46444add..354532f900d7a 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiTitle, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; import { ClientMetrics } from './ClientMetrics'; @@ -27,6 +27,7 @@ export function RumDashboard() { + diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts b/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts index 577b2f0870a71..6d231e6f58430 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts @@ -21,20 +21,11 @@ export async function getClientMetrics({ setup, }); - const { filter } = projection.body.query.bool; - const params = mergeProjection(projection, { body: { size: 0, query: { - bool: { - ...projection.body.query.bool, - filter: filter.concat({ - term: { - 'transaction.type': 'page-load', - }, - }), - }, + bool: projection.body.query.bool, }, aggs: { pageViews: { value_count: { field: 'transaction.type' } }, @@ -44,15 +35,10 @@ export async function getClientMetrics({ missing: 0, }, }, - frontEnd: { + domInteractive: { avg: { - script: { - lang: 'painless', - source: ` - if(doc[\'transaction.marks.agent.timeToFirstByte\'].size()!==0 && doc[\'transaction.marks.agent.domInteractive\'].size()!==0) { - doc[\'transaction.marks.agent.domInteractive\'].value - doc[\'transaction.marks.agent.timeToFirstByte\'].value - }`, - }, + field: 'transaction.marks.agent.domInteractive', + missing: 0, }, }, }, @@ -62,6 +48,11 @@ export async function getClientMetrics({ const { client } = setup; const response = await client.search(params); + const { backEnd, domInteractive, pageViews } = response.aggregations!; - return response.aggregations; + return { + pageViews, + backEnd, + frontEnd: { value: domInteractive.value! - backEnd.value! }, + }; } diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_impression_trends.ts b/x-pack/plugins/apm/server/lib/rum_client/get_impression_trends.ts index 70b0a61d35c8e..db26046c37582 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_impression_trends.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_impression_trends.ts @@ -4,36 +4,28 @@ * you may not use this file except in compliance with the Elastic License. */ -import { getServicesProjection } from '../../../common/projections/services'; +import { getRumOverviewProjection } from '../../../common/projections/rum_overview'; import { mergeProjection } from '../../../common/projections/util/merge_projection'; import { - AGENT_NAME, - SERVICE_ENVIRONMENT, - SERVICE_NAME, -} from '../../../common/elasticsearch_fieldnames'; -import { IEnvOptions } from '../service_map/get_service_map'; - -export async function getImpressionTrends(options: IEnvOptions) { - const { setup } = options; - - const projection = getServicesProjection({ - setup: { ...setup, uiFiltersES: [] }, + Setup, + SetupTimeRange, + SetupUIFilters, +} from '../helpers/setup_request'; + +export async function getImpressionTrends({ + setup, +}: { + setup: Setup & SetupTimeRange & SetupUIFilters; +}) { + const projection = getRumOverviewProjection({ + setup, }); - const { filter } = projection.body.query.bool; - const params = mergeProjection(projection, { body: { size: 0, query: { - bool: { - ...projection.body.query.bool, - filter: filter.concat({ - term: { - 'transaction.type': 'page-load', - }, - }), - }, + bool: projection.body.query.bool, }, aggs: { impressions: { @@ -57,7 +49,7 @@ export async function getImpressionTrends(options: IEnvOptions) { const response = await client.search(params); - const result = response.aggregations.impressions.buckets; + const result = response.aggregations.impressions.buckets ?? []; return result.map(({ key, trans_count }) => ({ x: key, y: trans_count.value, diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts b/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts index 82f7dbd146d6c..d3bdaed66ff40 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts @@ -5,7 +5,6 @@ */ import { getRumOverviewProjection } from '../../../common/projections/rum_overview'; -import { getServicesProjection } from '../../../common/projections/services'; import { mergeProjection } from '../../../common/projections/util/merge_projection'; import { Setup, @@ -22,20 +21,11 @@ export async function getPageLoadDistribution({ setup, }); - const { filter } = projection.body.query.bool; - const params = mergeProjection(projection, { body: { size: 0, query: { - bool: { - ...projection.body.query.bool, - filter: filter.concat({ - term: { - 'transaction.type': 'page-load', - }, - }), - }, + bool: projection.body.query.bool, }, aggs: { durationMinMax: { @@ -47,7 +37,7 @@ export async function getPageLoadDistribution({ durationPercentiles: { percentiles: { field: 'transaction.duration.us', - percents: [50, 80, 90, 95, 96], + percents: [50, 80, 90, 95, 99], script: { lang: 'painless', source: "doc['transaction.duration.us'].value / params.timeUnit", @@ -63,19 +53,20 @@ export async function getPageLoadDistribution({ const { client } = setup; - const response = await client.search(params); + const { aggregations } = await client.search(params); + + const minDuration = aggregations?.durationMinMax.value ?? 0 / 1000; + + const maxPercentile = aggregations?.durationPercentiles.values['99.0'] ?? 100; - const minDuration = response.aggregations.durationMinMax.value! / 1000; - const durationPercentiles = response.aggregations.durationPercentiles.values; - const maxPercentile = durationPercentiles['96.0']; const pageDist = await getPercentilesDistribution( - options, + setup, minDuration, maxPercentile ); return { pageLoadDistribution: pageDist, - percentiles: durationPercentiles, + percentiles: aggregations?.durationPercentiles, }; } @@ -84,9 +75,9 @@ const getPercentilesDistribution = async ( minPercentiles: number, maxPercentile: number ) => { - const stepValue = (maxPercentile - minPercentiles) / 100; + const stepValue = (maxPercentile - minPercentiles) / 50; const stepValues = []; - for (let i = 1; i < 100; i++) { + for (let i = 1; i < 50; i++) { stepValues.push((stepValue * i + minPercentiles).toFixed(2)); } @@ -94,20 +85,11 @@ const getPercentilesDistribution = async ( setup, }); - const { filter } = projection.body.query.bool; - const params = mergeProjection(projection, { body: { size: 0, query: { - bool: { - ...projection.body.query.bool, - filter: filter.concat({ - term: { - 'transaction.type': 'page-load', - }, - }), - }, + bool: projection.body.query.bool, }, aggs: { loadDistribution: { @@ -130,10 +112,14 @@ const getPercentilesDistribution = async ( const { client } = setup; - const response = await client.search(params); + const { aggregations } = await client.search(params); + + const pageDist = (aggregations?.loadDistribution.values ?? []) as Array<{ + key: number; + value: number; + }>; - const pageDist = response.aggregations.loadDistribution.values; - return pageDist.map(({ key, value }, index, arr) => { + return pageDist.map(({ key, value }, index: number, arr) => { return { x: key, y: index === 0 ? value : value - arr[index - 1].value, diff --git a/x-pack/plugins/apm/server/routes/rum_client.ts b/x-pack/plugins/apm/server/routes/rum_client.ts index 5b125803653f6..c2dc279fccecd 100644 --- a/x-pack/plugins/apm/server/routes/rum_client.ts +++ b/x-pack/plugins/apm/server/routes/rum_client.ts @@ -5,12 +5,7 @@ */ import * as t from 'io-ts'; -import Boom from 'boom'; import { createRoute } from './create_route'; -import { - invalidLicenseMessage, - isValidPlatinumLicense, -} from '../../common/service_map'; import { setupRequest } from '../lib/helpers/setup_request'; import { getClientMetrics } from '../lib/rum_client/get_client_metrics'; import { rangeRt, uiFiltersRt } from './default_api_types'; @@ -23,10 +18,6 @@ export const rumClientMetricsRoute = createRoute(() => ({ query: t.intersection([uiFiltersRt, rangeRt]), }, handler: async ({ context, request }) => { - if (!isValidPlatinumLicense(context.licensing.license)) { - throw Boom.forbidden(invalidLicenseMessage); - } - const setup = await setupRequest(context, request); return getClientMetrics({ setup }); @@ -39,10 +30,6 @@ export const rumPageLoadDistributionRoute = createRoute(() => ({ query: t.intersection([uiFiltersRt, rangeRt]), }, handler: async ({ context, request }) => { - if (!isValidPlatinumLicense(context.licensing.license)) { - throw Boom.forbidden(invalidLicenseMessage); - } - const setup = await setupRequest(context, request); return getPageLoadDistribution({ setup }); @@ -55,10 +42,6 @@ export const rumImpressionTrendRoute = createRoute(() => ({ query: t.intersection([uiFiltersRt, rangeRt]), }, handler: async ({ context, request }) => { - if (!isValidPlatinumLicense(context.licensing.license)) { - throw Boom.forbidden(invalidLicenseMessage); - } - const setup = await setupRequest(context, request); return getImpressionTrends({ setup }); }, diff --git a/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts b/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts index 0739e8e6120bf..6ee26caa4ef7c 100644 --- a/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts +++ b/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts @@ -137,6 +137,15 @@ export interface AggregationOptionsByType { >; keyed?: boolean; }; + auto_date_histogram: { + field: string; + buckets: number; + }; + percentile_ranks: { + field: string; + values: string[]; + keyed?: boolean; + }; } type AggregationType = keyof AggregationOptionsByType; @@ -301,6 +310,23 @@ interface AggregationResponsePart< ? Record : { buckets: DateRangeBucket[] }; }; + auto_date_histogram: { + buckets: Array< + { + doc_count: number; + key: number; + key_as_string: string; + } & BucketSubAggregationResponse< + TAggregationOptionsMap['aggs'], + TDocument + > + >; + interval: string; + }; + + percentile_ranks: { + values: Record | Array<{ key: number; value: number }>; + }; } // Type for debugging purposes. If you see an error in AggregationResponseMap From fd6d22a0697e9371fb821f0d302c0da11a532f3e Mon Sep 17 00:00:00 2001 From: Shahzad Date: Wed, 10 Jun 2020 17:16:06 +0200 Subject: [PATCH 10/54] update --- .../app/RumDashboard/ClientMetrics/index.tsx | 39 ++++++--- .../RumDashboard/ImpressionTrend/index.tsx | 43 +++++---- .../PercentileAnnotations.tsx | 60 +++++++++++++ .../PageLoadDistribution/index.tsx | 87 +++++++------------ .../app/RumDashboard/RumDashboard.tsx | 9 +- .../app/RumDashboard/translations.ts | 74 ++++++++++++++++ .../app/ServiceDetails/ServiceDetailTabs.tsx | 16 ++++ .../components/shared/KueryBar/index.tsx | 2 +- .../lib/rum_client/get_impression_trends.ts | 2 +- .../rum_client/get_page_load_distribution.ts | 13 ++- .../server/lib/service_map/get_service_map.ts | 1 - 11 files changed, 247 insertions(+), 99 deletions(-) create mode 100644 x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx create mode 100644 x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx index 2e4047498d172..67de158208222 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx @@ -8,43 +8,56 @@ import * as React from 'react'; import { EuiSpacer, EuiStat } from '@elastic/eui'; import { useFetcher } from '../../../../hooks/useFetcher'; import { useUrlParams } from '../../../../hooks/useUrlParams'; +import { BackEndLabel, FrontEndLabel, PageViewsLabel } from '../translations'; export const ClientMetrics = () => { const { urlParams, uiFilters } = useUrlParams(); const { start, end } = urlParams; - const { data } = useFetcher( + const { data, status } = useFetcher( (callApmApi) => { - return callApmApi({ - pathname: '/api/apm/rum/client-metrics', - params: { - query: { start, end, uiFilters: JSON.stringify(uiFilters) }, - }, - }); + if (start && end) { + return callApmApi({ + pathname: '/api/apm/rum/client-metrics', + params: { + query: { start, end, uiFilters: JSON.stringify(uiFilters) }, + }, + }); + } }, [start, end, uiFilters] ); + const getPageValue = (val?: number | null) => { + if (val && val > 1000) { + return val / 1000 + 'k'; + } + return val; + }; + return ( <> ); diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx index 0a31de1b66d7e..4c7c82de9cda9 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx @@ -20,6 +20,11 @@ import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; import { useUrlParams } from '../../../../hooks/useUrlParams'; import { useFetcher } from '../../../../hooks/useFetcher'; import { ChartWrapper } from '../ChartWrapper'; +import { + DateTimeLabel, + ImpressionsTrendsLabel, + NoOfImpressionsLabels, +} from '../translations'; export const ImpressionTrend = () => { const { urlParams, uiFilters } = useUrlParams(); @@ -28,47 +33,49 @@ export const ImpressionTrend = () => { const { data, status } = useFetcher( (callApmApi) => { - return callApmApi({ - pathname: '/api/apm/rum-client/impression-trend', - params: { - query: { - start, - end, - uiFilters: JSON.stringify(uiFilters), + if (start && end) { + return callApmApi({ + pathname: '/api/apm/rum-client/impression-trend', + params: { + query: { + start, + end, + uiFilters: JSON.stringify(uiFilters), + }, }, - }, - }); + }); + } }, [end, start, uiFilters] ); const formatter = timeFormatter(niceTimeFormatByDay(2)); return ( -
+
-

Impressions trends

+

{ImpressionsTrendsLabel}

- - + + ; +} + +function generateAnnotationData( + values?: Record +): LineAnnotationDatum[] { + return Object.entries(values ?? {}).map((value, index) => ({ + dataValue: value[1], + details: `${(+value[0]).toFixed(0)}`, + })); +} + +export const PercentileAnnotations = ({ percentiles }: Props) => { + const dataValues = generateAnnotationData(percentiles) ?? []; + + const style = { + line: { + strokeWidth: 3, + stroke: euiLightVars.euiColorLightShade, + opacity: 1, + }, + details: { + fontSize: 12, + fontFamily: 'Arial', + fontStyle: 'bold', + fill: 'gray', + padding: 0, + }, + }; + + return ( + <> + {dataValues.map((annotation, index) => ( + {annotation.details}th} + /> + ))} + + ); +}; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx index b11171692d2d3..5ec3e6e5f0828 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx @@ -3,31 +3,20 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -// @flow + import * as React from 'react'; import { EuiSpacer, EuiTitle } from '@elastic/eui'; -import { - AnnotationDomainTypes, - Axis, - Chart, - LineAnnotation, - LineAnnotationDatum, - ScaleType, - LineSeries, - CurveType, -} from '@elastic/charts'; +import { Axis, Chart, ScaleType, LineSeries, CurveType } from '@elastic/charts'; import { Position } from '@elastic/charts/dist/utils/commons'; -import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; import { useUrlParams } from '../../../../hooks/useUrlParams'; import { useFetcher } from '../../../../hooks/useFetcher'; import { ChartWrapper } from '../ChartWrapper'; - -function generateAnnotationData(values: any[]): LineAnnotationDatum[] { - return Object.entries(values).map((value, index) => ({ - dataValue: value[1], - details: `detail-${value[0]}`, - })); -} +import { PercentileAnnotations } from './PercentileAnnotations'; +import { + PageLoadDistLabel, + PageLoadTimeLabel, + PercPageLoadedLabel, +} from '../translations'; export const PageLoadDistribution = () => { const { urlParams, uiFilters } = useUrlParams(); @@ -36,58 +25,44 @@ export const PageLoadDistribution = () => { const { data, status } = useFetcher( (callApmApi) => { - return callApmApi({ - pathname: '/api/apm/rum-client/page-load-distribution', - params: { - query: { - start, - end, - uiFilters: JSON.stringify(uiFilters), + if (start && end) { + return callApmApi({ + pathname: '/api/apm/rum-client/page-load-distribution', + params: { + query: { + start, + end, + uiFilters: JSON.stringify(uiFilters), + }, }, - }, - }); + }); + } }, [end, start, uiFilters] ); - const dataValues = generateAnnotationData(data?.percentiles ?? []); - const style = { - line: { - strokeWidth: 3, - stroke: euiLightVars.euiColorLightShade, - opacity: 1, - }, - details: { - fontSize: 12, - fontFamily: 'Arial', - fontStyle: 'bold', - fill: 'gray', - padding: 0, - }, - }; + return ( -
+
-

Page load distribution

+

{PageLoadDistLabel}

- + - %} + + - Number(d).toFixed(2) + '%'} + tickFormat={(d) => Number(d).toFixed(1) + ' %'} /> -

- {i18n.translate('xpack.apm.rum.dashboard.title', { - defaultMessage: 'End User Experience', - })} -

+

{EndUserExperienceLabel}

@@ -29,6 +25,7 @@ export function RumDashboard() { + diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts new file mode 100644 index 0000000000000..9547d22808ad0 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts @@ -0,0 +1,74 @@ +/* + * 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 { i18n } from '@kbn/i18n'; + +export const EndUserExperienceLabel = i18n.translate( + 'xpack.apm.rum.dashboard.title', + { + defaultMessage: 'End User Experience', + } +); + +export const BackEndLabel = i18n.translate('xpack.apm.rum.dashboard.backend', { + defaultMessage: 'Backend', +}); + +export const FrontEndLabel = i18n.translate( + 'xpack.apm.rum.dashboard.frontend', + { + defaultMessage: 'Frontend', + } +); + +export const PageViewsLabel = i18n.translate( + 'xpack.apm.rum.dashboard.pageViews', + { + defaultMessage: 'Page views', + } +); + +export const DateTimeLabel = i18n.translate( + 'xpack.apm.rum.dashboard.dateTime.label', + { + defaultMessage: 'Date / Time', + } +); + +export const NoOfImpressionsLabels = i18n.translate( + 'xpack.apm.rum.dashboard.noOfImpressions.label', + { + defaultMessage: 'Number of impressions', + } +); + +export const PercPageLoadedLabel = i18n.translate( + 'xpack.apm.rum.dashboard.percentagePageLoaded.label', + { + defaultMessage: 'Percentages of page loaded', + } +); + +export const PageLoadTimeLabel = i18n.translate( + 'xpack.apm.rum.dashboard.pageLoadTime.label', + { + defaultMessage: 'Page load time', + } +); + +export const PageLoadDistLabel = i18n.translate( + 'xpack.apm.rum.dashboard.pageLoadDistribution.label', + { + defaultMessage: 'Page load distribution', + } +); + +export const ImpressionsTrendsLabel = i18n.translate( + 'xpack.apm.rum.dashboard.impressionsTrends.label', + { + defaultMessage: 'Impressions trends', + } +); diff --git a/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceDetailTabs.tsx b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceDetailTabs.tsx index 2f35e329720de..81bdbdad805d6 100644 --- a/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceDetailTabs.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceDetailTabs.tsx @@ -22,6 +22,8 @@ import { ServiceMap } from '../ServiceMap'; import { ServiceMetrics } from '../ServiceMetrics'; import { ServiceNodeOverview } from '../ServiceNodeOverview'; import { TransactionOverview } from '../TransactionOverview'; +import { RumOverviewLink } from '../../shared/Links/apm/RumOverviewLink'; +import { RumOverview } from '../RumDashboard'; interface Props { tab: 'transactions' | 'errors' | 'metrics' | 'nodes' | 'service-map'; @@ -110,6 +112,20 @@ export function ServiceDetailTabs({ tab }: Props) { tabs.push(serviceMapTab); } + if (isRumAgentName(agentName)) { + tabs.push({ + link: ( + + {i18n.translate('xpack.apm.home.rumTabLabel', { + defaultMessage: 'Real User Monitoring', + })} + + ), + render: () => , + name: 'rum-overview', + }); + } + const selectedTab = tabs.find((serviceTab) => serviceTab.name === tab); return ( diff --git a/x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx b/x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx index d01deb8160858..70bce9afd6eeb 100644 --- a/x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx @@ -76,7 +76,7 @@ export function KueryBar() { }); // The bar should be disabled when viewing the service map - const disabled = /\/service-map$/.test(location.pathname); + const disabled = /\/(service-map|rum-overview)$/.test(location.pathname); const disabledPlaceholder = i18n.translate( 'xpack.apm.kueryBar.disabledPlaceholder', { defaultMessage: 'Search is not available for service map' } diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_impression_trends.ts b/x-pack/plugins/apm/server/lib/rum_client/get_impression_trends.ts index db26046c37582..5270949ee696f 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_impression_trends.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_impression_trends.ts @@ -49,7 +49,7 @@ export async function getImpressionTrends({ const response = await client.search(params); - const result = response.aggregations.impressions.buckets ?? []; + const result = response.aggregations?.impressions.buckets ?? []; return result.map(({ key, trans_count }) => ({ x: key, y: trans_count.value, diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts b/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts index d3bdaed66ff40..9a3522769903e 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts @@ -53,9 +53,16 @@ export async function getPageLoadDistribution({ const { client } = setup; - const { aggregations } = await client.search(params); + const { + aggregations, + hits: { total }, + } = await client.search(params); + + if (total.value === 0) { + return null; + } - const minDuration = aggregations?.durationMinMax.value ?? 0 / 1000; + const minDuration = (aggregations?.durationMinMax.value ?? 0) / 1000; const maxPercentile = aggregations?.durationPercentiles.values['99.0'] ?? 100; @@ -66,7 +73,7 @@ export async function getPageLoadDistribution({ ); return { pageLoadDistribution: pageDist, - percentiles: aggregations?.durationPercentiles, + percentiles: aggregations?.durationPercentiles.values, }; } diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts index 40e0c903c9032..9f3ded82d7cbd 100644 --- a/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts +++ b/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts @@ -12,7 +12,6 @@ import { import { getServicesProjection } from '../../../common/projections/services'; import { mergeProjection } from '../../../common/projections/util/merge_projection'; import { PromiseReturnType } from '../../../typings/common'; -import { rangeFilter } from '../../../common/utils/range_filter'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { transformServiceMapResponses, From 89a93ed5c4fb1ebad3b76216fb73e8d6d65ba8c5 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Wed, 10 Jun 2020 17:52:07 +0200 Subject: [PATCH 11/54] update --- .../apm/server/lib/rum_client/queries.test.ts | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 x-pack/plugins/apm/server/lib/rum_client/queries.test.ts diff --git a/x-pack/plugins/apm/server/lib/rum_client/queries.test.ts b/x-pack/plugins/apm/server/lib/rum_client/queries.test.ts new file mode 100644 index 0000000000000..a55a7a9f2d8b4 --- /dev/null +++ b/x-pack/plugins/apm/server/lib/rum_client/queries.test.ts @@ -0,0 +1,50 @@ +/* + * 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 { + SearchParamsMock, + inspectSearchParams, +} from '../../../public/utils/testHelpers'; +import { getClientMetrics } from './get_client_metrics'; +import { getImpressionTrends } from './get_impression_trends'; +import { getPageLoadDistribution } from './get_page_load_distribution'; + +describe('rum client dashboard queries', () => { + let mock: SearchParamsMock; + + afterEach(() => { + mock.teardown(); + }); + + it('fetches client metrics', async () => { + mock = await inspectSearchParams((setup) => + getClientMetrics({ + setup, + }) + ); + + expect(mock.params).toMatchSnapshot(); + }); + + it('fetches impression trends', async () => { + mock = await inspectSearchParams((setup) => + getImpressionTrends({ + setup, + }) + ); + + expect(mock.params).toMatchSnapshot(); + }); + + it('fetches page load distribution', async () => { + mock = await inspectSearchParams((setup) => + getPageLoadDistribution({ + setup, + }) + ); + expect(mock.params).toMatchSnapshot(); + }); +}); From c1a9ef25da2a251f16108faa3ee21f3011c18da1 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Wed, 10 Jun 2020 20:07:10 +0200 Subject: [PATCH 12/54] added filter --- .../RumDashboard/ImpressionTrend/index.tsx | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx index 4c7c82de9cda9..f57d9b6085690 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx @@ -9,12 +9,14 @@ import { EuiSpacer, EuiTitle } from '@elastic/eui'; import { Axis, BarSeries, + BrushEndListener, Chart, niceTimeFormatByDay, ScaleType, Settings, timeFormatter, } from '@elastic/charts'; +import moment from 'moment'; import { Position } from '@elastic/charts/dist/utils/commons'; import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; import { useUrlParams } from '../../../../hooks/useUrlParams'; @@ -25,6 +27,8 @@ import { ImpressionsTrendsLabel, NoOfImpressionsLabels, } from '../translations'; +import { history } from '../../../../utils/history'; +import { fromQuery, toQuery } from '../../../shared/Links/url_helpers'; export const ImpressionTrend = () => { const { urlParams, uiFilters } = useUrlParams(); @@ -50,6 +54,25 @@ export const ImpressionTrend = () => { ); const formatter = timeFormatter(niceTimeFormatByDay(2)); + const onBrushEnd: BrushEndListener = ({ x }) => { + if (!x) { + return; + } + const [minX, maxX] = x; + + const rangeFrom = moment(minX).toISOString(); + const rangeTo = moment(maxX).toISOString(); + + history.push({ + ...history.location, + search: fromQuery({ + ...toQuery(history.location.search), + rangeFrom, + rangeTo, + }), + }); + }; + return (
@@ -62,6 +85,7 @@ export const ImpressionTrend = () => { showLegend={false} showLegendExtra legendPosition={Position.Bottom} + onBrushEnd={onBrushEnd} /> Date: Thu, 11 Jun 2020 13:46:56 +0200 Subject: [PATCH 13/54] update --- .../app/RumDashboard/ClientMetrics/index.tsx | 16 ++++++------ .../RumDashboard/ImpressionTrend/index.tsx | 4 ++- .../PageLoadDistribution/index.tsx | 26 ++++++++++++++++--- .../plugins/apm/server/routes/rum_client.ts | 7 ++++- 4 files changed, 40 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx index 67de158208222..e374b3ea8cfd7 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx @@ -10,6 +10,13 @@ import { useFetcher } from '../../../../hooks/useFetcher'; import { useUrlParams } from '../../../../hooks/useUrlParams'; import { BackEndLabel, FrontEndLabel, PageViewsLabel } from '../translations'; +export const formatBigValue = (val?: number | null): string => { + if (val && val >= 1000) { + return val / 1000 + 'k'; + } + return val + ''; +}; + export const ClientMetrics = () => { const { urlParams, uiFilters } = useUrlParams(); @@ -29,13 +36,6 @@ export const ClientMetrics = () => { [start, end, uiFilters] ); - const getPageValue = (val?: number | null) => { - if (val && val > 1000) { - return val / 1000 + 'k'; - } - return val; - }; - return ( <> @@ -48,7 +48,7 @@ export const ClientMetrics = () => { diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx index f57d9b6085690..42d935d1a8389 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx @@ -29,6 +29,7 @@ import { } from '../translations'; import { history } from '../../../../utils/history'; import { fromQuery, toQuery } from '../../../shared/Links/url_helpers'; +import { formatBigValue } from '../ClientMetrics'; export const ImpressionTrend = () => { const { urlParams, uiFilters } = useUrlParams(); @@ -97,9 +98,10 @@ export const ImpressionTrend = () => { id="number_of_impressions" title={NoOfImpressionsLabels} position={Position.Left} + tickFormat={(d) => formatBigValue(Number(d))} /> { const { start, end } = urlParams; + const [percentileRange, setPercentileRange] = useState({ min: 0, max: 99 }); + const { data, status } = useFetcher( (callApmApi) => { if (start && end) { @@ -33,14 +43,23 @@ export const PageLoadDistribution = () => { start, end, uiFilters: JSON.stringify(uiFilters), + minPercentile: percentileRange.min, + maxPercentile: percentileRange.max, }, }, }); } }, - [end, start, uiFilters] + [end, start, uiFilters, percentileRange] ); + const onBrushEnd: BrushEndListener = ({ x }) => { + if (!x) { + return; + } + const [minX, maxX] = x; + }; + return (
@@ -49,6 +68,7 @@ export const PageLoadDistribution = () => { + ({ path: '/api/apm/rum/client-metrics', params: { @@ -27,7 +32,7 @@ export const rumClientMetricsRoute = createRoute(() => ({ export const rumPageLoadDistributionRoute = createRoute(() => ({ path: '/api/apm/rum-client/page-load-distribution', params: { - query: t.intersection([uiFiltersRt, rangeRt]), + query: t.intersection([uiFiltersRt, rangeRt, percentileRangeRt]), }, handler: async ({ context, request }) => { const setup = await setupRequest(context, request); From 1d0afcc5e42edc75b0bda4fd239b6bdfc7061825 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 11 Jun 2020 14:47:06 +0200 Subject: [PATCH 14/54] update --- .../RumDashboard/PageLoadDistribution/index.tsx | 17 ++++++++++++++--- .../rum_client/get_page_load_distribution.ts | 17 +++++++++++------ x-pack/plugins/apm/server/routes/rum_client.ts | 6 ++++-- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx index b79c2cc63c5da..f54efff7e0fd1 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx @@ -31,7 +31,13 @@ export const PageLoadDistribution = () => { const { start, end } = urlParams; - const [percentileRange, setPercentileRange] = useState({ min: 0, max: 99 }); + const [percentileRange, setPercentileRange] = useState<{ + min: string | null; + max: string | null; + }>({ + min: null, + max: null, + }); const { data, status } = useFetcher( (callApmApi) => { @@ -43,8 +49,12 @@ export const PageLoadDistribution = () => { start, end, uiFilters: JSON.stringify(uiFilters), - minPercentile: percentileRange.min, - maxPercentile: percentileRange.max, + ...(percentileRange.min && percentileRange.max + ? { + minPercentile: percentileRange.min, + maxPercentile: percentileRange.max, + } + : {}), }, }, }); @@ -58,6 +68,7 @@ export const PageLoadDistribution = () => { return; } const [minX, maxX] = x; + setPercentileRange({ min: String(minX), max: String(maxX) }); }; return ( diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts b/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts index 9a3522769903e..a384e842f5c91 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts @@ -14,8 +14,12 @@ import { export async function getPageLoadDistribution({ setup, + minPercentile, + maxPercentile, }: { setup: Setup & SetupTimeRange & SetupUIFilters; + minPercentile: string; + maxPercentile: string; }) { const projection = getRumOverviewProjection({ setup, @@ -64,13 +68,14 @@ export async function getPageLoadDistribution({ const minDuration = (aggregations?.durationMinMax.value ?? 0) / 1000; - const maxPercentile = aggregations?.durationPercentiles.values['99.0'] ?? 100; + const minPerc = +minPercentile || minDuration; - const pageDist = await getPercentilesDistribution( - setup, - minDuration, - maxPercentile - ); + const maxPercentileQuery = + aggregations?.durationPercentiles.values['99.0'] ?? 100; + + const maxPerc = +maxPercentile || maxPercentileQuery; + + const pageDist = await getPercentilesDistribution(setup, minPerc, maxPerc); return { pageLoadDistribution: pageDist, percentiles: aggregations?.durationPercentiles.values, diff --git a/x-pack/plugins/apm/server/routes/rum_client.ts b/x-pack/plugins/apm/server/routes/rum_client.ts index 2404c734f4665..0cc5831b69f7b 100644 --- a/x-pack/plugins/apm/server/routes/rum_client.ts +++ b/x-pack/plugins/apm/server/routes/rum_client.ts @@ -12,7 +12,7 @@ import { rangeRt, uiFiltersRt } from './default_api_types'; import { getImpressionTrends } from '../lib/rum_client/get_impression_trends'; import { getPageLoadDistribution } from '../lib/rum_client/get_page_load_distribution'; -export const percentileRangeRt = t.type({ +export const percentileRangeRt = t.partial({ minPercentile: t.string, maxPercentile: t.string, }); @@ -37,7 +37,9 @@ export const rumPageLoadDistributionRoute = createRoute(() => ({ handler: async ({ context, request }) => { const setup = await setupRequest(context, request); - return getPageLoadDistribution({ setup }); + const { minPercentile, maxPercentile } = request.query; + + return getPageLoadDistribution({ setup, minPercentile, maxPercentile }); }, })); From f1259a71e2504f94de931c0f4a4b987c516bf8e2 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 11 Jun 2020 14:52:49 +0200 Subject: [PATCH 15/54] fixed --- .../server/lib/rum_client/get_page_load_distribution.ts | 8 ++++---- x-pack/plugins/apm/server/lib/rum_client/queries.test.ts | 2 ++ x-pack/plugins/apm/server/routes/rum_client.ts | 4 +++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts b/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts index a384e842f5c91..c4607b56df8e0 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts @@ -18,8 +18,8 @@ export async function getPageLoadDistribution({ maxPercentile, }: { setup: Setup & SetupTimeRange & SetupUIFilters; - minPercentile: string; - maxPercentile: string; + minPercentile?: string; + maxPercentile?: string; }) { const projection = getRumOverviewProjection({ setup, @@ -68,12 +68,12 @@ export async function getPageLoadDistribution({ const minDuration = (aggregations?.durationMinMax.value ?? 0) / 1000; - const minPerc = +minPercentile || minDuration; + const minPerc = minPercentile ? +minPercentile : minDuration; const maxPercentileQuery = aggregations?.durationPercentiles.values['99.0'] ?? 100; - const maxPerc = +maxPercentile || maxPercentileQuery; + const maxPerc = maxPercentile ? +maxPercentile : maxPercentileQuery; const pageDist = await getPercentilesDistribution(setup, minPerc, maxPerc); return { diff --git a/x-pack/plugins/apm/server/lib/rum_client/queries.test.ts b/x-pack/plugins/apm/server/lib/rum_client/queries.test.ts index a55a7a9f2d8b4..b1c260faba63e 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/queries.test.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/queries.test.ts @@ -43,6 +43,8 @@ describe('rum client dashboard queries', () => { mock = await inspectSearchParams((setup) => getPageLoadDistribution({ setup, + minPercentile: '0', + maxPercentile: '99', }) ); expect(mock.params).toMatchSnapshot(); diff --git a/x-pack/plugins/apm/server/routes/rum_client.ts b/x-pack/plugins/apm/server/routes/rum_client.ts index 0cc5831b69f7b..99bcda016442d 100644 --- a/x-pack/plugins/apm/server/routes/rum_client.ts +++ b/x-pack/plugins/apm/server/routes/rum_client.ts @@ -37,7 +37,9 @@ export const rumPageLoadDistributionRoute = createRoute(() => ({ handler: async ({ context, request }) => { const setup = await setupRequest(context, request); - const { minPercentile, maxPercentile } = request.query; + const { + query: { minPercentile, maxPercentile }, + } = context.params; return getPageLoadDistribution({ setup, minPercentile, maxPercentile }); }, From 638920d2f8c36a066ea77160d3b37f83cd5eec75 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 11 Jun 2020 19:09:59 +0200 Subject: [PATCH 16/54] added rum tests --- .../apm/e2e/cypress/integration/helpers.ts | 5 ++- .../cypress/integration/rum_dashboard.feature | 7 ++++ .../apm/e2e/cypress/integration/snapshots.js | 18 ++++++-- .../support/step_definitions/rum_dashboard.ts | 41 +++++++++++++++++++ x-pack/plugins/apm/e2e/yarn.lock | 8 ++-- .../app/RumDashboard/RumDashboard.tsx | 2 +- 6 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature create mode 100644 x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum_dashboard.ts diff --git a/x-pack/plugins/apm/e2e/cypress/integration/helpers.ts b/x-pack/plugins/apm/e2e/cypress/integration/helpers.ts index 90d5c9eda632d..179c5829dc2dd 100644 --- a/x-pack/plugins/apm/e2e/cypress/integration/helpers.ts +++ b/x-pack/plugins/apm/e2e/cypress/integration/helpers.ts @@ -6,8 +6,9 @@ /* eslint-disable import/no-extraneous-dependencies */ -const RANGE_FROM = '2020-03-04T12:30:00.000Z'; -const RANGE_TO = '2020-03-04T13:00:00.000Z'; +const RANGE_FROM = '2020-06-11T14:59:32.686Z'; +const RANGE_TO = '2020-06-11T16:59:36.219Z'; + const BASE_URL = Cypress.config().baseUrl; /** The default time in ms to wait for a Cypress command to complete */ diff --git a/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature b/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature new file mode 100644 index 0000000000000..f0739c7056a80 --- /dev/null +++ b/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature @@ -0,0 +1,7 @@ +Feature: RUM Dashboard + + Scenario: Client metrics + Given a user browses the APM UI application + When the user inspects the real user monitoring tab + Then should redirect to rum dashboard + And should have correct client metrics diff --git a/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js index f1633799ea583..20fac876f718d 100644 --- a/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js +++ b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js @@ -1,10 +1,20 @@ module.exports = { + "__version": "4.5.0", + "RUM Dashboard": { + "Client metrics": { + "1": "77.52 seconds", + "2": "199", + "3": "4.14 seconds", + "4": "77.52 seconds", + "5": "199", + "6": "4.14 seconds" + } + }, "APM": { "Transaction duration charts": { - "1": "350 ms", - "2": "175 ms", + "1": "450 ms", + "2": "225 ms", "3": "0 ms" } - }, - "__version": "4.5.0" + } } diff --git a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum_dashboard.ts b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum_dashboard.ts new file mode 100644 index 0000000000000..9655b71848db9 --- /dev/null +++ b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum_dashboard.ts @@ -0,0 +1,41 @@ +/* + * 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 { Given, When, Then } from 'cypress-cucumber-preprocessor/steps'; +import { loginAndWaitForPage } from '../../integration/helpers'; + +/** The default time in ms to wait for a Cypress command to complete */ +export const DEFAULT_TIMEOUT = 60 * 1000; + +Given(`a user browses the APM UI application`, () => { + // open service overview page + loginAndWaitForPage(`/app/apm#/services`); +}); + +When(`the user inspects the real user monitoring tab`, () => { + // click rum tab + cy.get(':contains(Real User Monitoring)', { timeout: DEFAULT_TIMEOUT }) + .last() + .click({ force: true }); +}); + +Then(`should redirect to rum dashboard`, () => { + cy.url().should('contain', `/app/apm#/rum-overview`); +}); + +Then(`should have correct client metrics`, () => { + const clientMetrics = '[data-cy=client-metrics] .euiStat__title'; + + // wait for all loading to finish + cy.get('kbnLoadingIndicator').should('not.be.visible'); + cy.get('.euiStat__title-isLoading').should('not.be.visible'); + + cy.get(clientMetrics).eq(2).invoke('text').snapshot(); + + cy.get(clientMetrics).eq(1).invoke('text').snapshot(); + + cy.get(clientMetrics).eq(0).invoke('text').snapshot(); +}); diff --git a/x-pack/plugins/apm/e2e/yarn.lock b/x-pack/plugins/apm/e2e/yarn.lock index a6729c56ecb09..975154d71b85d 100644 --- a/x-pack/plugins/apm/e2e/yarn.lock +++ b/x-pack/plugins/apm/e2e/yarn.lock @@ -5561,10 +5561,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@3.9.2: - version "3.9.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.2.tgz#64e9c8e9be6ea583c54607677dd4680a1cf35db9" - integrity sha512-q2ktq4n/uLuNNShyayit+DTobV2ApPEo/6so68JaD5ojvc/6GClBipedB9zNWYxRSAlZXAe405Rlijzl6qDiSw== +typescript@3.9.5: + version "3.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36" + integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ== umd@^3.0.0: version "3.0.3" diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx index 47fe48f82e266..f800d70612813 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx @@ -18,7 +18,7 @@ export function RumDashboard() {

{EndUserExperienceLabel}

- + From 9dc10c5e475839b475a6d8d47da6610dc1027eda Mon Sep 17 00:00:00 2001 From: Shahzad Date: Fri, 12 Jun 2020 18:16:02 +0200 Subject: [PATCH 17/54] update and added reset zoom button --- .../apm/public/components/app/Home/index.tsx | 7 +++- .../PageLoadDistribution/index.tsx | 34 ++++++++++++++++--- .../app/RumDashboard/RumDashboard.tsx | 15 ++++++-- .../app/RumDashboard/translations.ts | 13 +++++++ .../components/shared/KueryBar/index.tsx | 2 +- .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 7 files changed, 62 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/Home/index.tsx b/x-pack/plugins/apm/public/components/app/Home/index.tsx index f612ac0d383ef..c325a72375359 100644 --- a/x-pack/plugins/apm/public/components/app/Home/index.tsx +++ b/x-pack/plugins/apm/public/components/app/Home/index.tsx @@ -27,6 +27,7 @@ import { ServiceOverview } from '../ServiceOverview'; import { TraceOverview } from '../TraceOverview'; import { RumOverview } from '../RumDashboard'; import { RumOverviewLink } from '../../shared/Links/apm/RumOverviewLink'; +import { EndUserExperienceLabel } from '../RumDashboard/translations'; function getHomeTabs({ serviceMapEnabled = true, @@ -108,7 +109,11 @@ export function Home({ tab }: Props) { -

APM

+

+ {selectedTab.name === 'rum-overview' + ? EndUserExperienceLabel + : 'APM'} +

diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx index f54efff7e0fd1..d898857da20df 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx @@ -5,7 +5,13 @@ */ import React, { useState } from 'react'; -import { EuiSpacer, EuiTitle } from '@elastic/eui'; +import { + EuiButton, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiTitle, +} from '@elastic/eui'; import { Axis, Chart, @@ -24,6 +30,7 @@ import { PageLoadDistLabel, PageLoadTimeLabel, PercPageLoadedLabel, + ResetZoomLabel, } from '../translations'; export const PageLoadDistribution = () => { @@ -60,7 +67,7 @@ export const PageLoadDistribution = () => { }); } }, - [end, start, uiFilters, percentileRange] + [end, start, uiFilters, percentileRange.min, percentileRange.max] ); const onBrushEnd: BrushEndListener = ({ x }) => { @@ -74,9 +81,26 @@ export const PageLoadDistribution = () => { return (
- -

{PageLoadDistLabel}

-
+ + + +

{PageLoadDistLabel}

+
+
+ + { + setPercentileRange({ min: null, max: null }); + }} + fill={percentileRange.min !== null && percentileRange.max !== null} + > + {ResetZoomLabel} + + +
+ diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx index f800d70612813..282ff45b159e3 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx @@ -9,13 +9,24 @@ import React from 'react'; import { ClientMetrics } from './ClientMetrics'; import { ImpressionTrend } from './ImpressionTrend'; import { PageLoadDistribution } from './PageLoadDistribution'; -import { EndUserExperienceLabel } from './translations'; +import { getWhatIsGoingOnLabel } from './translations'; +import { useUrlParams } from '../../../hooks/useUrlParams'; export function RumDashboard() { + const { urlParams } = useUrlParams(); + + const { environment } = urlParams; + + let environmentLabel = environment || 'all environments'; + + if (environment === 'ENVIRONMENT_NOT_DEFINED') { + environmentLabel = 'undefined environment'; + } + return ( <> -

{EndUserExperienceLabel}

+

{getWhatIsGoingOnLabel(environmentLabel)}

diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts index 9547d22808ad0..36dd1ca16ce5a 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts @@ -13,6 +13,12 @@ export const EndUserExperienceLabel = i18n.translate( } ); +export const getWhatIsGoingOnLabel = (environmentVal: string) => + i18n.translate('xpack.apm.rum.dashboard.title', { + defaultMessage: `What's going on in {environmentVal}?`, + values: { environmentVal }, + }); + export const BackEndLabel = i18n.translate('xpack.apm.rum.dashboard.backend', { defaultMessage: 'Backend', }); @@ -72,3 +78,10 @@ export const ImpressionsTrendsLabel = i18n.translate( defaultMessage: 'Impressions trends', } ); + +export const ResetZoomLabel = i18n.translate( + 'xpack.apm.rum.dashboard.resetZoom.label', + { + defaultMessage: 'Reset zoom', + } +); diff --git a/x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx b/x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx index 70bce9afd6eeb..eab685a4c1ab4 100644 --- a/x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx @@ -79,7 +79,7 @@ export function KueryBar() { const disabled = /\/(service-map|rum-overview)$/.test(location.pathname); const disabledPlaceholder = i18n.translate( 'xpack.apm.kueryBar.disabledPlaceholder', - { defaultMessage: 'Search is not available for service map' } + { defaultMessage: 'Search is not available here' } ); async function onChange(inputValue: string, selectionStart: number) { diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index c5492e6bddc75..b49b96dc162a6 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -4209,7 +4209,6 @@ "xpack.apm.jvmsTable.noJvmsLabel": "JVM が見つかりませんでした", "xpack.apm.jvmsTable.nonHeapMemoryColumnLabel": "非ヒープ領域の平均", "xpack.apm.jvmsTable.threadCountColumnLabel": "最大スレッド数", - "xpack.apm.kueryBar.disabledPlaceholder": "サービスマップの検索は利用できません", "xpack.apm.kueryBar.placeholder": "検索 {event, select,\n transaction {トランザクション}\n metric {メトリック}\n error {エラー}\n other {その他}\n } (E.g. {queryExample})", "xpack.apm.license.betaBadge": "ベータ", "xpack.apm.license.betaTooltipMessage": "現在、この機能はベータです。不具合を見つけた場合やご意見がある場合、サポートに問い合わせるか、またはディスカッションフォーラムにご報告ください。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index f59a2ef4eb871..2143e0b80c56a 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -4212,7 +4212,6 @@ "xpack.apm.jvmsTable.noJvmsLabel": "未找到任何 JVM", "xpack.apm.jvmsTable.nonHeapMemoryColumnLabel": "非堆内存平均值", "xpack.apm.jvmsTable.threadCountColumnLabel": "线程计数最大值", - "xpack.apm.kueryBar.disabledPlaceholder": "搜索不适用于服务地图", "xpack.apm.kueryBar.placeholder": "搜索{event, select,\n transaction {事务}\n metric {指标}\n error {错误}\n other {事务、错误和指标}\n }(例如 {queryExample})", "xpack.apm.license.betaBadge": "公测版", "xpack.apm.license.betaTooltipMessage": "此功能当前为公测版。如果遇到任何错误或有任何反馈,请报告问题或访问我们的论坛。", From b2b444a7a55f7a2f2b67363e562d4a0878ae1a17 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Fri, 12 Jun 2020 18:19:58 +0200 Subject: [PATCH 18/54] snapshot --- .../__snapshots__/queries.test.ts.snap | 179 ++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap diff --git a/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap new file mode 100644 index 0000000000000..f1007de0bfcae --- /dev/null +++ b/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap @@ -0,0 +1,179 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`rum client dashboard queries fetches client metrics 1`] = ` +Object { + "body": Object { + "aggs": Object { + "backEnd": Object { + "avg": Object { + "field": "transaction.marks.agent.timeToFirstByte", + "missing": 0, + }, + }, + "domInteractive": Object { + "avg": Object { + "field": "transaction.marks.agent.domInteractive", + "missing": 0, + }, + }, + "pageViews": Object { + "value_count": Object { + "field": "transaction.type", + }, + }, + }, + "query": Object { + "bool": Object { + "filter": Array [ + Object { + "range": Object { + "@timestamp": Object { + "format": "epoch_millis", + "gte": 1528113600000, + "lte": 1528977600000, + }, + }, + }, + Object { + "term": Object { + "processor.event": "transaction", + }, + }, + Object { + "term": Object { + "transaction.type": "page-load", + }, + }, + Object { + "term": Object { + "my.custom.ui.filter": "foo-bar", + }, + }, + ], + }, + }, + "size": 0, + }, + "index": "myIndex", +} +`; + +exports[`rum client dashboard queries fetches impression trends 1`] = ` +Object { + "body": Object { + "aggs": Object { + "impressions": Object { + "aggs": Object { + "trans_count": Object { + "value_count": Object { + "field": "transaction.type", + }, + }, + }, + "auto_date_histogram": Object { + "buckets": 50, + "field": "@timestamp", + }, + }, + }, + "query": Object { + "bool": Object { + "filter": Array [ + Object { + "range": Object { + "@timestamp": Object { + "format": "epoch_millis", + "gte": 1528113600000, + "lte": 1528977600000, + }, + }, + }, + Object { + "term": Object { + "processor.event": "transaction", + }, + }, + Object { + "term": Object { + "transaction.type": "page-load", + }, + }, + Object { + "term": Object { + "my.custom.ui.filter": "foo-bar", + }, + }, + ], + }, + }, + "size": 0, + }, + "index": "myIndex", +} +`; + +exports[`rum client dashboard queries fetches page load distribution 1`] = ` +Object { + "body": Object { + "aggs": Object { + "durationMinMax": Object { + "min": Object { + "field": "transaction.duration.us", + "missing": 0, + }, + }, + "durationPercentiles": Object { + "percentiles": Object { + "field": "transaction.duration.us", + "percents": Array [ + 50, + 80, + 90, + 95, + 99, + ], + "script": Object { + "lang": "painless", + "params": Object { + "timeUnit": 1000, + }, + "source": "doc['transaction.duration.us'].value / params.timeUnit", + }, + }, + }, + }, + "query": Object { + "bool": Object { + "filter": Array [ + Object { + "range": Object { + "@timestamp": Object { + "format": "epoch_millis", + "gte": 1528113600000, + "lte": 1528977600000, + }, + }, + }, + Object { + "term": Object { + "processor.event": "transaction", + }, + }, + Object { + "term": Object { + "transaction.type": "page-load", + }, + }, + Object { + "term": Object { + "my.custom.ui.filter": "foo-bar", + }, + }, + ], + }, + }, + "size": 0, + }, + "index": "myIndex", +} +`; From 3c8f802a53e4a87d08c1cff729b59e2a4980507a Mon Sep 17 00:00:00 2001 From: Shahzad Date: Mon, 15 Jun 2020 10:16:54 +0200 Subject: [PATCH 19/54] added breakdown filter button --- .../app/RumDashboard/BreakdownFilter.tsx | 72 +++++++++++++++++++ .../PercentileAnnotations.tsx | 10 ++- .../PageLoadDistribution/index.tsx | 4 ++ .../lib/rum_client/get_breakdown_filters.ts | 57 +++++++++++++++ .../apm/server/routes/create_apm_api.ts | 2 + .../plugins/apm/server/routes/rum_client.ts | 12 ++++ x-pack/plugins/uptime/public/index.ts | 2 + 7 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx create mode 100644 x-pack/plugins/apm/server/lib/rum_client/get_breakdown_filters.ts diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx new file mode 100644 index 0000000000000..5980539383b49 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx @@ -0,0 +1,72 @@ +/* + * 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 React, { useMemo, useState } from 'react'; +import { EuiFilterButton } from '@elastic/eui'; +import { FilterPopover } from '../../../../../uptime/public'; +import { useLocalUIFilters } from '../../../hooks/useLocalUIFilters'; +import { PROJECTION } from '../../../../common/projections/typings'; +import { LocalUIFilters } from '../../shared/LocalUIFilters'; + +interface Props { + fieldName: string; +} + +export const BreakdownFilter = ({ fieldName }: Props) => { + const [isOpen, setIsOpen] = useState(false); + + const [isOpen, setIsOpen] = useState(false); + + const localUIFiltersConfig = useMemo(() => { + const config: React.ComponentProps = { + filterNames: ['transactionUrl', 'location', 'device', 'os', 'browser'], + projection: PROJECTION.RUM_OVERVIEW, + }; + + return config; + }, []); + + const { filters } = useLocalUIFilters(localUIFiltersConfig); + + const items = []; + + filters.forEach(({ options }) => { + options.forEach(({ name }) => { + items.push(name); + }); + }); + + const button = ( + setIsOpen(!isOpen)} + isSelected={isOpen} + numFilters={items.length} + hasActiveFilters={true} + numActiveFilters={2} + withNext={false} + > + Breakdown + + ); + + return ( + {}} + selectedItems={[]} + title={''} + btnContent={button} + forceOpen={isOpen} + setForceOpen={() => { + setIsOpen(!isOpen); + }} + /> + ); +}; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx index 0dc5fcb12172c..2f1bffafd8e58 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx @@ -11,6 +11,7 @@ import { LineAnnotationDatum, } from '@elastic/charts'; import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import styled from 'styled-components'; interface Props { percentiles?: Record; @@ -25,13 +26,18 @@ function generateAnnotationData( })); } +const PercentileMarket = styled.span` + position: relative; + bottom: 240px; +`; + export const PercentileAnnotations = ({ percentiles }: Props) => { const dataValues = generateAnnotationData(percentiles) ?? []; const style = { line: { strokeWidth: 3, - stroke: euiLightVars.euiColorLightShade, + stroke: euiLightVars.euiColorMediumShade, opacity: 1, }, details: { @@ -52,7 +58,7 @@ export const PercentileAnnotations = ({ percentiles }: Props) => { domainType={AnnotationDomainTypes.XDomain} dataValues={[annotation]} style={style} - marker={{annotation.details}th} + marker={{annotation.details}th} /> ))} diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx index d898857da20df..c70af74b110c7 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx @@ -32,6 +32,7 @@ import { PercPageLoadedLabel, ResetZoomLabel, } from '../translations'; +import { BreakdownFilter } from '../BreakdownFilter'; export const PageLoadDistribution = () => { const { urlParams, uiFilters } = useUrlParams(); @@ -99,6 +100,9 @@ export const PageLoadDistribution = () => { {ResetZoomLabel} + + + diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_breakdown_filters.ts b/x-pack/plugins/apm/server/lib/rum_client/get_breakdown_filters.ts new file mode 100644 index 0000000000000..90e01b693216c --- /dev/null +++ b/x-pack/plugins/apm/server/lib/rum_client/get_breakdown_filters.ts @@ -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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { getRumOverviewProjection } from '../../../common/projections/rum_overview'; +import { mergeProjection } from '../../../common/projections/util/merge_projection'; +import { + Setup, + SetupTimeRange, + SetupUIFilters, +} from '../helpers/setup_request'; + +export async function getBreakdownFilters({ + setup, +}: { + setup: Setup & SetupTimeRange & SetupUIFilters; +}) { + const projection = getRumOverviewProjection({ + setup, + }); + + const params = mergeProjection(projection, { + body: { + size: 0, + query: { + bool: projection.body.query.bool, + }, + aggs: { + impressions: { + auto_date_histogram: { + field: '@timestamp', + buckets: 50, + }, + aggs: { + trans_count: { + value_count: { + field: 'transaction.type', + }, + }, + }, + }, + }, + }, + }); + + const { client } = setup; + + const response = await client.search(params); + + const result = response.aggregations?.impressions.buckets ?? []; + return result.map(({ key, trans_count }) => ({ + x: key, + y: trans_count.value, + })); +} diff --git a/x-pack/plugins/apm/server/routes/create_apm_api.ts b/x-pack/plugins/apm/server/routes/create_apm_api.ts index 6ecc5e6ae5d5d..5f5473e7a73f9 100644 --- a/x-pack/plugins/apm/server/routes/create_apm_api.ts +++ b/x-pack/plugins/apm/server/routes/create_apm_api.ts @@ -71,6 +71,7 @@ import { customLinkTransactionRoute, } from './settings/custom_link'; import { + breakdownFiltersRoute, rumClientMetricsRoute, rumImpressionTrendRoute, rumPageLoadDistributionRoute, @@ -158,6 +159,7 @@ const createApmApi = () => { .add(rumOverviewLocalFiltersRoute) .add(rumImpressionTrendRoute) .add(rumPageLoadDistributionRoute) + .add(breakdownFiltersRoute) .add(rumClientMetricsRoute); return api; diff --git a/x-pack/plugins/apm/server/routes/rum_client.ts b/x-pack/plugins/apm/server/routes/rum_client.ts index 99bcda016442d..2ac7242f9cf2e 100644 --- a/x-pack/plugins/apm/server/routes/rum_client.ts +++ b/x-pack/plugins/apm/server/routes/rum_client.ts @@ -11,6 +11,7 @@ import { getClientMetrics } from '../lib/rum_client/get_client_metrics'; import { rangeRt, uiFiltersRt } from './default_api_types'; import { getImpressionTrends } from '../lib/rum_client/get_impression_trends'; import { getPageLoadDistribution } from '../lib/rum_client/get_page_load_distribution'; +import { getBreakdownFilters } from '../lib/rum_client/get_breakdown_filters'; export const percentileRangeRt = t.partial({ minPercentile: t.string, @@ -45,6 +46,17 @@ export const rumPageLoadDistributionRoute = createRoute(() => ({ }, })); +export const breakdownFiltersRoute = createRoute(() => ({ + path: '/api/apm/rum-client/breakdown', + params: { + query: t.intersection([uiFiltersRt, rangeRt]), + }, + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + return getBreakdownFilters({ setup }); + }, +})); + export const rumImpressionTrendRoute = createRoute(() => ({ path: '/api/apm/rum-client/impression-trend', params: { diff --git a/x-pack/plugins/uptime/public/index.ts b/x-pack/plugins/uptime/public/index.ts index 48cf2c90ad07b..799e40dcf3356 100644 --- a/x-pack/plugins/uptime/public/index.ts +++ b/x-pack/plugins/uptime/public/index.ts @@ -9,3 +9,5 @@ import { UptimePlugin } from './apps'; export const plugin = (initializerContext: PluginInitializerContext) => new UptimePlugin(initializerContext); + +export { FilterPopover } from './components/overview/filter_group/filter_popover'; From e72de7bfdc97f8e3d6ae1082079a39e3e9c42360 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Mon, 15 Jun 2020 10:21:50 +0200 Subject: [PATCH 20/54] update --- x-pack/plugins/apm/e2e/run-e2e.sh | 2 +- .../apm/public/components/app/RumDashboard/translations.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/apm/e2e/run-e2e.sh b/x-pack/plugins/apm/e2e/run-e2e.sh index 4bebab8e0c6a8..a879083ab485c 100755 --- a/x-pack/plugins/apm/e2e/run-e2e.sh +++ b/x-pack/plugins/apm/e2e/run-e2e.sh @@ -109,7 +109,7 @@ echo "${bold}Static mock data (logs: ${E2E_DIR}${TMP_DIR}/ingest-data.log)${norm # Download static data if not already done if [ ! -e "${TMP_DIR}/events.json" ]; then echo 'Downloading events.json...' - curl --silent https://storage.googleapis.com/apm-ui-e2e-static-data/events.json --output ${TMP_DIR}/events.json + curl --silent https://storage.googleapis.com/apm-ui-e2e-static-data/2020-06-12.json --output ${TMP_DIR}/events.json fi # echo "Deleting existing indices (apm* and .apm*)" diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts index 36dd1ca16ce5a..421a9b22ba233 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts @@ -14,7 +14,7 @@ export const EndUserExperienceLabel = i18n.translate( ); export const getWhatIsGoingOnLabel = (environmentVal: string) => - i18n.translate('xpack.apm.rum.dashboard.title', { + i18n.translate('xpack.apm.rum.dashboard.environment.title', { defaultMessage: `What's going on in {environmentVal}?`, values: { environmentVal }, }); From a0176da4cf4193df6ed8a099fce27d6569a81faa Mon Sep 17 00:00:00 2001 From: Shahzad Date: Mon, 15 Jun 2020 15:17:13 +0200 Subject: [PATCH 21/54] improve responsiveness --- .../plugins/apm/public/application/index.tsx | 3 +- .../app/RumDashboard/ClientMetrics/index.tsx | 68 ++++++++++++------- .../RumDashboard/ImpressionTrend/index.tsx | 2 +- .../PercentileAnnotations.tsx | 12 +++- .../PageLoadDistribution/index.tsx | 8 +-- .../app/RumDashboard/RumDashboard.tsx | 5 +- .../app/RumDashboard/translations.ts | 4 +- .../rum_client/get_page_load_distribution.ts | 2 +- 8 files changed, 63 insertions(+), 41 deletions(-) diff --git a/x-pack/plugins/apm/public/application/index.tsx b/x-pack/plugins/apm/public/application/index.tsx index 56c427e67ad4c..8800b2fd492bf 100644 --- a/x-pack/plugins/apm/public/application/index.tsx +++ b/x-pack/plugins/apm/public/application/index.tsx @@ -23,7 +23,7 @@ import { KibanaContextProvider, useUiSetting$, } from '../../../../../src/plugins/kibana_react/public'; -import { px, unit, units } from '../style/variables'; +import { px, units } from '../style/variables'; import { UpdateBreadcrumbs } from '../components/app/Main/UpdateBreadcrumbs'; import { APMIndicesPermission } from '../components/app/APMIndicesPermission'; import { ScrollToTopOnPathChange } from '../components/app/Main/ScrollToTopOnPathChange'; @@ -33,7 +33,6 @@ import { ConfigSchema } from '..'; import 'react-vis/dist/style.css'; const MainContainer = styled.div` - min-width: ${px(unit * 50)}; padding: ${px(units.plus)}; height: 100%; `; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx index e374b3ea8cfd7..29d75067aa8fc 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx @@ -5,18 +5,31 @@ */ // @flow import * as React from 'react'; -import { EuiSpacer, EuiStat } from '@elastic/eui'; +import styled from 'styled-components'; +import { EuiFlexGroup, EuiFlexItem, EuiStat } from '@elastic/eui'; import { useFetcher } from '../../../../hooks/useFetcher'; import { useUrlParams } from '../../../../hooks/useUrlParams'; import { BackEndLabel, FrontEndLabel, PageViewsLabel } from '../translations'; -export const formatBigValue = (val?: number | null): string => { +export const formatBigValue = (val?: number | null, fixed?: number): string => { if (val && val >= 1000) { - return val / 1000 + 'k'; + const result = val / 1000; + if (fixed) { + return result.toFixed(fixed) + 'k'; + } + return result + 'k'; } return val + ''; }; +const ClFlexGroup = styled(EuiFlexGroup)` + flex-direction: column; + @media only screen and (max-width: 768px) { + flex-direction: row; + justify-content: space-between; + } +`; + export const ClientMetrics = () => { const { urlParams, uiFilters } = useUrlParams(); @@ -37,28 +50,31 @@ export const ClientMetrics = () => { ); return ( - <> - - - - - - - + + + + + + + + + + + ); }; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx index 42d935d1a8389..d082da180fdf4 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx @@ -80,7 +80,7 @@ export const ImpressionTrend = () => {

{ImpressionsTrendsLabel}

- + ; @@ -25,13 +26,18 @@ function generateAnnotationData( })); } +const PercentileMarker = styled.span` + position: relative; + bottom: 140px; +`; + export const PercentileAnnotations = ({ percentiles }: Props) => { const dataValues = generateAnnotationData(percentiles) ?? []; const style = { line: { - strokeWidth: 3, - stroke: euiLightVars.euiColorLightShade, + strokeWidth: 1, + stroke: euiLightVars.euiColorSecondary, opacity: 1, }, details: { @@ -52,7 +58,7 @@ export const PercentileAnnotations = ({ percentiles }: Props) => { domainType={AnnotationDomainTypes.XDomain} dataValues={[annotation]} style={style} - marker={{annotation.details}th} + marker={{annotation.details}th} /> ))} diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx index d898857da20df..5efe0018776b2 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx @@ -80,8 +80,8 @@ export const PageLoadDistribution = () => { return (
- - + +

{PageLoadDistLabel}

@@ -100,8 +100,8 @@ export const PageLoadDistribution = () => {
- - + + diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx index 282ff45b159e3..fd1da3b9f233b 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx @@ -28,11 +28,12 @@ export function RumDashboard() {

{getWhatIsGoingOnLabel(environmentLabel)}

- + + - + diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts index 421a9b22ba233..1af895f2c52bb 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts @@ -52,9 +52,9 @@ export const NoOfImpressionsLabels = i18n.translate( ); export const PercPageLoadedLabel = i18n.translate( - 'xpack.apm.rum.dashboard.percentagePageLoaded.label', + 'xpack.apm.rum.dashboard.pagesLoaded.label', { - defaultMessage: 'Percentages of page loaded', + defaultMessage: 'Pages loaded', } ); diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts b/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts index c4607b56df8e0..3c563946e4052 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts @@ -41,7 +41,7 @@ export async function getPageLoadDistribution({ durationPercentiles: { percentiles: { field: 'transaction.duration.us', - percents: [50, 80, 90, 95, 99], + percents: [50, 75, 90, 95, 99], script: { lang: 'painless', source: "doc['transaction.duration.us'].value / params.timeUnit", From 3c769a72ba0502a848934bcae6577d6d11653529 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Mon, 15 Jun 2020 17:58:12 +0200 Subject: [PATCH 22/54] update --- .../public/components/app/RumDashboard/ClientMetrics/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx index 29d75067aa8fc..c7ba97464e63f 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx @@ -54,7 +54,7 @@ export const ClientMetrics = () => { From 9e0b508bcfd902a51489e5f8c55fd4aede5e1c9d Mon Sep 17 00:00:00 2001 From: Shahzad Date: Mon, 15 Jun 2020 19:46:38 +0200 Subject: [PATCH 23/54] rename impression treds --- .../index.tsx | 20 +++--- .../app/RumDashboard/RumDashboard.tsx | 4 +- .../app/RumDashboard/translations.ts | 14 ---- .../__snapshots__/queries.test.ts.snap | 64 +++++++++---------- ...sion_trends.ts => get_page_view_trends.ts} | 6 +- .../apm/server/lib/rum_client/queries.test.ts | 6 +- .../apm/server/routes/create_apm_api.ts | 4 +- .../plugins/apm/server/routes/rum_client.ts | 8 +-- 8 files changed, 54 insertions(+), 72 deletions(-) rename x-pack/plugins/apm/public/components/app/RumDashboard/{ImpressionTrend => PageViewsTrend}/index.tsx (88%) rename x-pack/plugins/apm/server/lib/rum_client/{get_impression_trends.ts => get_page_view_trends.ts} (90%) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx similarity index 88% rename from x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx rename to x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx index d082da180fdf4..25de38755a785 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ImpressionTrend/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -// @flow + import * as React from 'react'; import { EuiSpacer, EuiTitle } from '@elastic/eui'; import { @@ -22,16 +22,12 @@ import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; import { useUrlParams } from '../../../../hooks/useUrlParams'; import { useFetcher } from '../../../../hooks/useFetcher'; import { ChartWrapper } from '../ChartWrapper'; -import { - DateTimeLabel, - ImpressionsTrendsLabel, - NoOfImpressionsLabels, -} from '../translations'; +import { DateTimeLabel, PageViewsLabel } from '../translations'; import { history } from '../../../../utils/history'; import { fromQuery, toQuery } from '../../../shared/Links/url_helpers'; import { formatBigValue } from '../ClientMetrics'; -export const ImpressionTrend = () => { +export const PageViewsTrend = () => { const { urlParams, uiFilters } = useUrlParams(); const { start, end } = urlParams; @@ -40,7 +36,7 @@ export const ImpressionTrend = () => { (callApmApi) => { if (start && end) { return callApmApi({ - pathname: '/api/apm/rum-client/impression-trend', + pathname: '/api/apm/rum-client/page-view-trends', params: { query: { start, @@ -78,7 +74,7 @@ export const ImpressionTrend = () => {
-

{ImpressionsTrendsLabel}

+

{PageViewsLabel}

@@ -95,13 +91,13 @@ export const ImpressionTrend = () => { tickFormat={formatter} /> formatBigValue(Number(d))} /> - + diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts index 1af895f2c52bb..668d9924ba868 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts @@ -44,13 +44,6 @@ export const DateTimeLabel = i18n.translate( } ); -export const NoOfImpressionsLabels = i18n.translate( - 'xpack.apm.rum.dashboard.noOfImpressions.label', - { - defaultMessage: 'Number of impressions', - } -); - export const PercPageLoadedLabel = i18n.translate( 'xpack.apm.rum.dashboard.pagesLoaded.label', { @@ -72,13 +65,6 @@ export const PageLoadDistLabel = i18n.translate( } ); -export const ImpressionsTrendsLabel = i18n.translate( - 'xpack.apm.rum.dashboard.impressionsTrends.label', - { - defaultMessage: 'Impressions trends', - } -); - export const ResetZoomLabel = i18n.translate( 'xpack.apm.rum.dashboard.resetZoom.label', { diff --git a/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap index f1007de0bfcae..298cef4328d88 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap @@ -58,22 +58,34 @@ Object { } `; -exports[`rum client dashboard queries fetches impression trends 1`] = ` +exports[`rum client dashboard queries fetches page load distribution 1`] = ` Object { "body": Object { "aggs": Object { - "impressions": Object { - "aggs": Object { - "trans_count": Object { - "value_count": Object { - "field": "transaction.type", + "durationMinMax": Object { + "min": Object { + "field": "transaction.duration.us", + "missing": 0, + }, + }, + "durationPercentiles": Object { + "percentiles": Object { + "field": "transaction.duration.us", + "percents": Array [ + 50, + 75, + 90, + 95, + 99, + ], + "script": Object { + "lang": "painless", + "params": Object { + "timeUnit": 1000, }, + "source": "doc['transaction.duration.us'].value / params.timeUnit", }, }, - "auto_date_histogram": Object { - "buckets": 50, - "field": "@timestamp", - }, }, }, "query": Object { @@ -112,34 +124,22 @@ Object { } `; -exports[`rum client dashboard queries fetches page load distribution 1`] = ` +exports[`rum client dashboard queries fetches page view trends 1`] = ` Object { "body": Object { "aggs": Object { - "durationMinMax": Object { - "min": Object { - "field": "transaction.duration.us", - "missing": 0, - }, - }, - "durationPercentiles": Object { - "percentiles": Object { - "field": "transaction.duration.us", - "percents": Array [ - 50, - 80, - 90, - 95, - 99, - ], - "script": Object { - "lang": "painless", - "params": Object { - "timeUnit": 1000, + "pageViews": Object { + "aggs": Object { + "trans_count": Object { + "value_count": Object { + "field": "transaction.type", }, - "source": "doc['transaction.duration.us'].value / params.timeUnit", }, }, + "auto_date_histogram": Object { + "buckets": 50, + "field": "@timestamp", + }, }, }, "query": Object { diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_impression_trends.ts b/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts similarity index 90% rename from x-pack/plugins/apm/server/lib/rum_client/get_impression_trends.ts rename to x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts index 5270949ee696f..126605206d299 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_impression_trends.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts @@ -12,7 +12,7 @@ import { SetupUIFilters, } from '../helpers/setup_request'; -export async function getImpressionTrends({ +export async function getPageViewTrends({ setup, }: { setup: Setup & SetupTimeRange & SetupUIFilters; @@ -28,7 +28,7 @@ export async function getImpressionTrends({ bool: projection.body.query.bool, }, aggs: { - impressions: { + pageViews: { auto_date_histogram: { field: '@timestamp', buckets: 50, @@ -49,7 +49,7 @@ export async function getImpressionTrends({ const response = await client.search(params); - const result = response.aggregations?.impressions.buckets ?? []; + const result = response.aggregations?.pageViews.buckets ?? []; return result.map(({ key, trans_count }) => ({ x: key, y: trans_count.value, diff --git a/x-pack/plugins/apm/server/lib/rum_client/queries.test.ts b/x-pack/plugins/apm/server/lib/rum_client/queries.test.ts index b1c260faba63e..5f5a48eced746 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/queries.test.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/queries.test.ts @@ -9,7 +9,7 @@ import { inspectSearchParams, } from '../../../public/utils/testHelpers'; import { getClientMetrics } from './get_client_metrics'; -import { getImpressionTrends } from './get_impression_trends'; +import { getPageViewTrends } from './get_page_view_trends'; import { getPageLoadDistribution } from './get_page_load_distribution'; describe('rum client dashboard queries', () => { @@ -29,9 +29,9 @@ describe('rum client dashboard queries', () => { expect(mock.params).toMatchSnapshot(); }); - it('fetches impression trends', async () => { + it('fetches page view trends', async () => { mock = await inspectSearchParams((setup) => - getImpressionTrends({ + getPageViewTrends({ setup, }) ); diff --git a/x-pack/plugins/apm/server/routes/create_apm_api.ts b/x-pack/plugins/apm/server/routes/create_apm_api.ts index 6ecc5e6ae5d5d..3088803c3b4b0 100644 --- a/x-pack/plugins/apm/server/routes/create_apm_api.ts +++ b/x-pack/plugins/apm/server/routes/create_apm_api.ts @@ -72,7 +72,7 @@ import { } from './settings/custom_link'; import { rumClientMetricsRoute, - rumImpressionTrendRoute, + rumPageViewsTrendRoute, rumPageLoadDistributionRoute, } from './rum_client'; @@ -156,7 +156,7 @@ const createApmApi = () => { // Rum Overview .add(rumOverviewLocalFiltersRoute) - .add(rumImpressionTrendRoute) + .add(rumPageViewsTrendRoute) .add(rumPageLoadDistributionRoute) .add(rumClientMetricsRoute); diff --git a/x-pack/plugins/apm/server/routes/rum_client.ts b/x-pack/plugins/apm/server/routes/rum_client.ts index 99bcda016442d..9b5f6529b1783 100644 --- a/x-pack/plugins/apm/server/routes/rum_client.ts +++ b/x-pack/plugins/apm/server/routes/rum_client.ts @@ -9,7 +9,7 @@ import { createRoute } from './create_route'; import { setupRequest } from '../lib/helpers/setup_request'; import { getClientMetrics } from '../lib/rum_client/get_client_metrics'; import { rangeRt, uiFiltersRt } from './default_api_types'; -import { getImpressionTrends } from '../lib/rum_client/get_impression_trends'; +import { getPageViewTrends } from '../lib/rum_client/get_page_view_trends'; import { getPageLoadDistribution } from '../lib/rum_client/get_page_load_distribution'; export const percentileRangeRt = t.partial({ @@ -45,13 +45,13 @@ export const rumPageLoadDistributionRoute = createRoute(() => ({ }, })); -export const rumImpressionTrendRoute = createRoute(() => ({ - path: '/api/apm/rum-client/impression-trend', +export const rumPageViewsTrendRoute = createRoute(() => ({ + path: '/api/apm/rum-client/page-view-trends', params: { query: t.intersection([uiFiltersRt, rangeRt]), }, handler: async ({ context, request }) => { const setup = await setupRequest(context, request); - return getImpressionTrends({ setup }); + return getPageViewTrends({ setup }); }, })); From c7d1521a5395128f3266e08808773798b3fd1d65 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Mon, 15 Jun 2020 20:10:06 +0200 Subject: [PATCH 24/54] update tooltip --- .../PageLoadDistribution/PercentileAnnotations.tsx | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx index 571fdc6083852..9c89b8bc161b7 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx @@ -9,6 +9,7 @@ import { AnnotationDomainTypes, LineAnnotation, LineAnnotationDatum, + LineAnnotationStyle, } from '@elastic/charts'; import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; import styled from 'styled-components'; @@ -34,19 +35,12 @@ const PercentileMarker = styled.span` export const PercentileAnnotations = ({ percentiles }: Props) => { const dataValues = generateAnnotationData(percentiles) ?? []; - const style = { + const style: Partial = { line: { strokeWidth: 1, stroke: euiLightVars.euiColorSecondary, opacity: 1, }, - details: { - fontSize: 12, - fontFamily: 'Arial', - fontStyle: 'bold', - fill: 'gray', - padding: 0, - }, }; return ( From 1d94b3fd2d6ed48394908831492923e218529555 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Mon, 15 Jun 2020 21:05:55 +0200 Subject: [PATCH 25/54] update --- .../RumDashboard/PageLoadDistribution/index.tsx | 17 ++++++++++++++++- .../components/app/RumDashboard/translations.ts | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx index 5efe0018776b2..fb4e84f2da8cd 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx @@ -20,6 +20,8 @@ import { CurveType, BrushEndListener, Settings, + TooltipValueFormatter, + TooltipValue, } from '@elastic/charts'; import { Position } from '@elastic/charts/dist/utils/commons'; import { useUrlParams } from '../../../../hooks/useUrlParams'; @@ -78,6 +80,18 @@ export const PageLoadDistribution = () => { setPercentileRange({ min: String(minX), max: String(maxX) }); }; + const headerFormatter: TooltipValueFormatter = (tooltip: TooltipValue) => { + return ( +
+

{tooltip.value} seconds

+
+ ); + }; + + const tooltipProps = { + headerFormatter, + }; + return (
@@ -103,7 +117,7 @@ export const PageLoadDistribution = () => { - + { /> Date: Tue, 16 Jun 2020 12:56:04 +0200 Subject: [PATCH 26/54] update test --- .../apm/e2e/cypress/integration/helpers.ts | 4 +-- .../apm/e2e/cypress/integration/snapshots.js | 25 ++++++++----------- x-pack/plugins/apm/e2e/ingest-data/replay.js | 6 ++++- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/x-pack/plugins/apm/e2e/cypress/integration/helpers.ts b/x-pack/plugins/apm/e2e/cypress/integration/helpers.ts index 179c5829dc2dd..213615cae5f75 100644 --- a/x-pack/plugins/apm/e2e/cypress/integration/helpers.ts +++ b/x-pack/plugins/apm/e2e/cypress/integration/helpers.ts @@ -6,8 +6,8 @@ /* eslint-disable import/no-extraneous-dependencies */ -const RANGE_FROM = '2020-06-11T14:59:32.686Z'; -const RANGE_TO = '2020-06-11T16:59:36.219Z'; +const RANGE_FROM = '2020-06-01T14:59:32.686Z'; +const RANGE_TO = '2020-06-16T16:59:36.219Z'; const BASE_URL = Cypress.config().baseUrl; diff --git a/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js index 43f98330830c2..6c06a84405ad0 100644 --- a/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js +++ b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js @@ -1,20 +1,17 @@ module.exports = { - __version: "4.5.0", - "RUM Dashboard": { - "Client metrics": { - "1": "77.52 seconds", - "2": "199", - "3": "4.14 seconds", - "4": "77.52 seconds", - "5": "199", - "6": "4.14 seconds" - } - }, + "__version": "4.5.0", "APM": { "Transaction duration charts": { - "1": "450 ms", - "2": "225 ms", - "3": "0 ms" + "1": "55.0 ms", + "2": "27.5 ms", + "3": "0.0 ms" + } + }, + "RUM Dashboard": { + "Client metrics": { + "1": "62", + "2": "74.68 sec", + "3": "5.42 sec" } } } diff --git a/x-pack/plugins/apm/e2e/ingest-data/replay.js b/x-pack/plugins/apm/e2e/ingest-data/replay.js index ae3f62894afc0..3478039f39b50 100644 --- a/x-pack/plugins/apm/e2e/ingest-data/replay.js +++ b/x-pack/plugins/apm/e2e/ingest-data/replay.js @@ -99,7 +99,11 @@ async function init() { .split('\n') .filter((item) => item) .map((item) => JSON.parse(item)) - .filter((item) => item.url === '/intake/v2/events'); + .filter((item) => { + return ( + item.url === '/intake/v2/events' || item.url === '/intake/v2/rum/events' + ); + }); spinner.start(); requestProgress.total = items.length; From 20c779eba32ca5ddcd11820401a643b23503bf64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Casper=20Hu=CC=88bertz?= Date: Tue, 16 Jun 2020 21:20:43 +0200 Subject: [PATCH 27/54] Suggested design improvements --- .../app/RumDashboard/ClientMetrics/index.tsx | 12 +++--- .../PageLoadDistribution/index.tsx | 3 +- .../app/RumDashboard/PageViewsTrend/index.tsx | 3 +- .../app/RumDashboard/RumDashboard.tsx | 42 ++++++++++++++----- .../components/app/RumDashboard/index.tsx | 6 +-- 5 files changed, 42 insertions(+), 24 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx index c7ba97464e63f..6d126bff60e79 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx @@ -6,7 +6,7 @@ // @flow import * as React from 'react'; import styled from 'styled-components'; -import { EuiFlexGroup, EuiFlexItem, EuiStat } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiStat, EuiTitle } from '@elastic/eui'; import { useFetcher } from '../../../../hooks/useFetcher'; import { useUrlParams } from '../../../../hooks/useUrlParams'; import { BackEndLabel, FrontEndLabel, PageViewsLabel } from '../translations'; @@ -23,7 +23,7 @@ export const formatBigValue = (val?: number | null, fixed?: number): string => { }; const ClFlexGroup = styled(EuiFlexGroup)` - flex-direction: column; + flex-direction: row; @media only screen and (max-width: 768px) { flex-direction: row; justify-content: space-between; @@ -49,9 +49,11 @@ export const ClientMetrics = () => { [start, end, uiFilters] ); + const STAT_STYLE = { width: '240px' }; + return ( - + { isLoading={status !== 'success'} /> - + { isLoading={status !== 'success'} /> - + { return (
- - +

{PageLoadDistLabel}

diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx index 25de38755a785..5aac13c985d37 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx @@ -72,8 +72,7 @@ export const PageViewsTrend = () => { return (
- - +

{PageViewsLabel}

diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx index 862482cd17e4e..e3fa7374afb38 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx @@ -4,7 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiFlexGroup, EuiFlexItem, EuiTitle, EuiSpacer } from '@elastic/eui'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiTitle, + EuiSpacer, + EuiPanel, +} from '@elastic/eui'; import React from 'react'; import { ClientMetrics } from './ClientMetrics'; import { PageViewsTrend } from './PageViewsTrend'; @@ -26,18 +32,32 @@ export function RumDashboard() { return ( <> -

{getWhatIsGoingOnLabel(environmentLabel)}

+

{getWhatIsGoingOnLabel(environmentLabel)}

- - - - + + + + + + + +

Page load times

+
+ + +
+
+
- - - - - + + + + + + + + +
diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/index.tsx index 3591c71c5abf0..8f21065b0dab0 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/index.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiPanel, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import React, { useMemo } from 'react'; import { useTrackPageview } from '../../../../../observability/public'; import { LocalUIFilters } from '../../shared/LocalUIFilters'; @@ -32,9 +32,7 @@ export function RumOverview() {
- - - +
From bcb8ff8a6b708fc25e881da01cee2ed0f07f3248 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Wed, 17 Jun 2020 17:46:31 +0200 Subject: [PATCH 28/54] update --- .../app/RumDashboard/BreakdownFilter.tsx | 58 ++++----- .../RumDashboard/Charts/PageLoadDistChart.tsx | 102 ++++++++++++++++ .../RumDashboard/Charts/PageViewsChart.tsx | 101 ++++++++++++++++ .../PageLoadDistribution/BreakdownSeries.tsx | 39 +++++++ .../PageLoadDistribution/index.tsx | 103 ++++++---------- .../PageLoadDistribution/use_breakdowns.ts | 54 +++++++++ .../app/RumDashboard/PageViewsTrend/index.tsx | 110 ++++++------------ .../app/RumDashboard/RumDashboard.tsx | 2 +- .../rum_client/get_page_load_distribution.ts | 2 +- .../lib/rum_client/get_page_view_trends.ts | 34 +++++- .../plugins/apm/server/routes/rum_client.ts | 13 ++- .../overview/filter_group/filter_popover.tsx | 3 + .../filter_group/uptime_filter_button.tsx | 3 + 13 files changed, 448 insertions(+), 176 deletions(-) create mode 100644 x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx create mode 100644 x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx create mode 100644 x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/BreakdownSeries.tsx create mode 100644 x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/use_breakdowns.ts diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx index 5980539383b49..df5ab4053ee45 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx @@ -5,7 +5,6 @@ */ import React, { useMemo, useState } from 'react'; -import { EuiFilterButton } from '@elastic/eui'; import { FilterPopover } from '../../../../../uptime/public'; import { useLocalUIFilters } from '../../../hooks/useLocalUIFilters'; import { PROJECTION } from '../../../../common/projections/typings'; @@ -13,17 +12,19 @@ import { LocalUIFilters } from '../../shared/LocalUIFilters'; interface Props { fieldName: string; + onBreakdownChange: (values: Map) => void; } -export const BreakdownFilter = ({ fieldName }: Props) => { - const [isOpen, setIsOpen] = useState(false); - - const [isOpen, setIsOpen] = useState(false); +export const BreakdownFilter = ({ fieldName, onBreakdownChange }: Props) => { + const [selectedFilters, setSelectedFilters] = useState>( + new Set([]) + ); const localUIFiltersConfig = useMemo(() => { const config: React.ComponentProps = { filterNames: ['transactionUrl', 'location', 'device', 'os', 'browser'], projection: PROJECTION.RUM_OVERVIEW, + params: { uiFilters: '{}' }, }; return config; @@ -31,7 +32,7 @@ export const BreakdownFilter = ({ fieldName }: Props) => { const { filters } = useLocalUIFilters(localUIFiltersConfig); - const items = []; + const items: string[] = []; filters.forEach(({ options }) => { options.forEach(({ name }) => { @@ -39,19 +40,28 @@ export const BreakdownFilter = ({ fieldName }: Props) => { }); }); - const button = ( - setIsOpen(!isOpen)} - isSelected={isOpen} - numFilters={items.length} - hasActiveFilters={true} - numActiveFilters={2} - withNext={false} - > - Breakdown - - ); + const onFilterFieldChange = (field: string, selValues: string[]) => { + setSelectedFilters((prevState) => { + return new Set(selValues); + }); + + const newValues: Map = new Map(); + + filters.forEach(({ options, fieldName: fieldLabel }) => { + const selItems: string[] = []; + + options.forEach(({ name }) => { + if (selValues.includes(name)) { + selItems.push(name); + } + }); + + if (selItems.length > 0) { + newValues.set(fieldLabel, selItems); + } + }); + onBreakdownChange(newValues); + }; return ( { id={fieldName} items={items} loading={false} - onFilterFieldChange={() => {}} + onFilterFieldChange={onFilterFieldChange} selectedItems={[]} - title={''} - btnContent={button} - forceOpen={isOpen} - setForceOpen={() => { - setIsOpen(!isOpen); - }} + title={'Breakdown'} + size={'s'} /> ); }; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx new file mode 100644 index 0000000000000..38984775482ef --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx @@ -0,0 +1,102 @@ +/* + * 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 React, { FC } from 'react'; +import { + Axis, + BrushEndListener, + Chart, + CurveType, + LineSeries, + ScaleType, + Settings, + TooltipValue, + TooltipValueFormatter, +} from '@elastic/charts'; +import { Position } from '@elastic/charts/dist/utils/commons'; +import { PercentileAnnotations } from '../PageLoadDistribution/PercentileAnnotations'; +import { PageLoadTimeLabel, PercPageLoadedLabel } from '../translations'; +import { ChartWrapper } from '../ChartWrapper'; +import { BreakdownSeries } from '../PageLoadDistribution/BreakdownSeries'; +import { PercentileR } from '../PageLoadDistribution'; + +interface Props { + onPercentileChange: (min: number, max: number) => void; + data: any; + breakdowns: Map; + percentileRange: PercentileR; + loading: boolean; +} + +export const PageLoadDistChart: FC = ({ + onPercentileChange, + data, + breakdowns, + loading, + percentileRange, +}) => { + const onBrushEnd: BrushEndListener = ({ x }) => { + if (!x) { + return; + } + const [minX, maxX] = x; + onPercentileChange(minX, maxX); + }; + + const headerFormatter: TooltipValueFormatter = (tooltip: TooltipValue) => { + return ( +
+

{tooltip.value} seconds

+
+ ); + }; + + const tooltipProps = { + headerFormatter, + }; + + return ( + + + + + + Number(d).toFixed(1) + ' %'} + /> + + {Array.from(breakdowns.keys()).map((field) => { + const values = breakdowns.get(field); + + return values?.map((value: string) => { + return ( + + ); + }); + })} + + + ); +}; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx new file mode 100644 index 0000000000000..ef820723a551b --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx @@ -0,0 +1,101 @@ +/* + * 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 React, { FC } from 'react'; +import { + Axis, + BarSeries, + BrushEndListener, + Chart, + niceTimeFormatByDay, + ScaleType, + SeriesNameFn, + Settings, + timeFormatter, +} from '@elastic/charts'; +import moment from 'moment'; +import { Position } from '@elastic/charts/dist/utils/commons'; +import { DateTimeLabel, PageViewsLabel } from '../translations'; +import { formatBigValue } from '../ClientMetrics'; +import { history } from '../../../../utils/history'; +import { fromQuery, toQuery } from '../../../shared/Links/url_helpers'; +import { ChartWrapper } from '../ChartWrapper'; + +interface Props { + data: any; + loading: boolean; + breakdowns: Map; +} + +export const PageViewsChart: FC = ({ + data, + loading, + breakdowns, +}: Props) => { + const formatter = timeFormatter(niceTimeFormatByDay(2)); + + const onBrushEnd: BrushEndListener = ({ x }) => { + if (!x) { + return; + } + const [minX, maxX] = x; + + const rangeFrom = moment(minX).toISOString(); + const rangeTo = moment(maxX).toISOString(); + + history.push({ + ...history.location, + search: fromQuery({ + ...toQuery(history.location.search), + rangeFrom, + rangeTo, + }), + }); + }; + + let breakdownAccessors = []; + if (data && data.length > 0) { + const allKeys = Object.keys(data[0]); + breakdownAccessors = allKeys.filter((key) => key !== 'x'); + } + + const customSeriesNaming: SeriesNameFn = ({ yAccessor }) => { + if (yAccessor === 'y') { + return 'Overall'; + } + + return yAccessor.split('__')[1]; + }; + + return ( + + + + + formatBigValue(Number(d))} + /> + + + + ); +}; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/BreakdownSeries.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/BreakdownSeries.tsx new file mode 100644 index 0000000000000..a42e58339c490 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/BreakdownSeries.tsx @@ -0,0 +1,39 @@ +/* + * 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 React, { FC } from 'react'; +import { CurveType, LineSeries, ScaleType } from '@elastic/charts'; +import { usePageLoadBreakdowns } from './use_breakdowns'; +import { PercentileR } from './index'; + +interface Props { + field: string; + value: string; + percentileRange: PercentileR; +} + +export const BreakdownSeries: FC = ({ + field, + value, + percentileRange, +}) => { + const { data } = usePageLoadBreakdowns({ + field, + value, + percentileRange, + }); + + return ( + + ); +}; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx index b8200d47daeac..5b39a950526c4 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx @@ -6,49 +6,37 @@ import React, { useState } from 'react'; import { - EuiButton, + EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiTitle, } from '@elastic/eui'; -import { - Axis, - Chart, - ScaleType, - LineSeries, - CurveType, - BrushEndListener, - Settings, - TooltipValueFormatter, - TooltipValue, -} from '@elastic/charts'; -import { Position } from '@elastic/charts/dist/utils/commons'; import { useUrlParams } from '../../../../hooks/useUrlParams'; import { useFetcher } from '../../../../hooks/useFetcher'; -import { ChartWrapper } from '../ChartWrapper'; -import { PercentileAnnotations } from './PercentileAnnotations'; -import { - PageLoadDistLabel, - PageLoadTimeLabel, - PercPageLoadedLabel, - ResetZoomLabel, -} from '../translations'; +import { PageLoadDistLabel, ResetZoomLabel } from '../translations'; import { BreakdownFilter } from '../BreakdownFilter'; +import { PageLoadDistChart } from '../Charts/PageLoadDistChart'; + +export interface PercentileR { + min: string | null; + max: string | null; +} export const PageLoadDistribution = () => { const { urlParams, uiFilters } = useUrlParams(); const { start, end } = urlParams; - const [percentileRange, setPercentileRange] = useState<{ - min: string | null; - max: string | null; - }>({ + const [percentileRange, setPercentileRange] = useState({ min: null, max: null, }); + const [breakdowns, setBreakdowns] = useState>( + new Map() + ); + const { data, status } = useFetcher( (callApmApi) => { if (start && end) { @@ -73,24 +61,12 @@ export const PageLoadDistribution = () => { [end, start, uiFilters, percentileRange.min, percentileRange.max] ); - const onBrushEnd: BrushEndListener = ({ x }) => { - if (!x) { - return; - } - const [minX, maxX] = x; - setPercentileRange({ min: String(minX), max: String(maxX) }); + const onPercentileChange = (min: number, max: number) => { + setPercentileRange({ min: String(min), max: String(max) }); }; - const headerFormatter: TooltipValueFormatter = (tooltip: TooltipValue) => { - return ( -
-

{tooltip.value} seconds

-
- ); - }; - - const tooltipProps = { - headerFormatter, + const onBreakdownChange = (values: Map) => { + setBreakdowns(values); }; return ( @@ -103,47 +79,34 @@ export const PageLoadDistribution = () => {
- { setPercentileRange({ min: null, max: null }); }} - fill={percentileRange.min !== null && percentileRange.max !== null} + disabled={ + percentileRange.min === null && percentileRange.max === null + } > {ResetZoomLabel} - + - + - - - - - - Number(d).toFixed(1) + ' %'} - /> - - - +
); }; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/use_breakdowns.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/use_breakdowns.ts new file mode 100644 index 0000000000000..60f3e62debbf2 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/use_breakdowns.ts @@ -0,0 +1,54 @@ +/* + * 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 { useFetcher } from '../../../../hooks/useFetcher'; +import { useUrlParams } from '../../../../hooks/useUrlParams'; +import { PercentileR } from './index'; + +interface Props { + percentileRange?: PercentileR; + field: string; + value: string; +} + +export const usePageLoadBreakdowns = ({ + percentileRange, + field, + value, +}: Props) => { + const { urlParams, uiFilters } = useUrlParams(); + + const { start, end } = urlParams; + + const { min: minP, max: maxP } = percentileRange ?? {}; + + const { data, status } = useFetcher( + (callApmApi) => { + if (start && end && field && value) { + uiFilters.kuery = `${field}: ${value}`; + + return callApmApi({ + pathname: '/api/apm/rum-client/page-load-distribution', + params: { + query: { + start, + end, + uiFilters: JSON.stringify(uiFilters), + ...(minP && maxP + ? { + minPercentile: minP, + maxPercentile: maxP, + } + : {}), + }, + }, + }); + } + }, + [end, start, uiFilters, field, value, minP, maxP] + ); + return { data, loading: status !== 'success' }; +}; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx index 25de38755a785..ac4347dfe076a 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx @@ -4,34 +4,23 @@ * you may not use this file except in compliance with the Elastic License. */ -import * as React from 'react'; -import { EuiSpacer, EuiTitle } from '@elastic/eui'; -import { - Axis, - BarSeries, - BrushEndListener, - Chart, - niceTimeFormatByDay, - ScaleType, - Settings, - timeFormatter, -} from '@elastic/charts'; -import moment from 'moment'; -import { Position } from '@elastic/charts/dist/utils/commons'; -import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import React, { useState } from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiTitle } from '@elastic/eui'; import { useUrlParams } from '../../../../hooks/useUrlParams'; import { useFetcher } from '../../../../hooks/useFetcher'; -import { ChartWrapper } from '../ChartWrapper'; -import { DateTimeLabel, PageViewsLabel } from '../translations'; -import { history } from '../../../../utils/history'; -import { fromQuery, toQuery } from '../../../shared/Links/url_helpers'; -import { formatBigValue } from '../ClientMetrics'; +import { PageViewsLabel } from '../translations'; +import { BreakdownFilter } from '../BreakdownFilter'; +import { PageViewsChart } from '../Charts/PageViewsChart'; export const PageViewsTrend = () => { const { urlParams, uiFilters } = useUrlParams(); const { start, end } = urlParams; + const [breakdowns, setBreakdowns] = useState>( + new Map() + ); + const { data, status } = useFetcher( (callApmApi) => { if (start && end) { @@ -42,71 +31,48 @@ export const PageViewsTrend = () => { start, end, uiFilters: JSON.stringify(uiFilters), + ...(breakdowns.size > 0 + ? { + breakdowns: JSON.stringify( + Array.from(breakdowns.entries()) + ), + } + : {}), }, }, }); } }, - [end, start, uiFilters] + [end, start, uiFilters, breakdowns] ); - const formatter = timeFormatter(niceTimeFormatByDay(2)); - - const onBrushEnd: BrushEndListener = ({ x }) => { - if (!x) { - return; - } - const [minX, maxX] = x; - const rangeFrom = moment(minX).toISOString(); - const rangeTo = moment(maxX).toISOString(); - - history.push({ - ...history.location, - search: fromQuery({ - ...toQuery(history.location.search), - rangeFrom, - rangeTo, - }), - }); + const onBreakdownChange = (values: Map) => { + setBreakdowns(values); }; return (
- -

{PageViewsLabel}

-
- - - - - formatBigValue(Number(d))} - /> - + + +

{PageViewsLabel}

+
+
+ + -
-
+ + + +
); }; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx index 862482cd17e4e..ea6d23cbd5b3c 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx @@ -33,7 +33,7 @@ export function RumDashboard() { - + diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts b/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts index 3c563946e4052..7c35d990366ca 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts @@ -89,7 +89,7 @@ const getPercentilesDistribution = async ( ) => { const stepValue = (maxPercentile - minPercentiles) / 50; const stepValues = []; - for (let i = 1; i < 50; i++) { + for (let i = 1; i < 51; i++) { stepValues.push((stepValue * i + minPercentiles).toFixed(2)); } diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts b/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts index 126605206d299..7d94873af74e1 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts @@ -14,12 +14,30 @@ import { export async function getPageViewTrends({ setup, + breakdowns, }: { setup: Setup & SetupTimeRange & SetupUIFilters; + breakdowns: string; }) { const projection = getRumOverviewProjection({ setup, }); + const breakdownAggs: any = {}; + if (breakdowns) { + const breakdownMap: Map = new Map(JSON.parse(breakdowns)); + Array.from(breakdownMap.keys()).map((field) => { + const values = breakdownMap.get(field); + values.forEach((value) => { + breakdownAggs[field + '__' + value] = { + filter: { + term: { + [field]: value, + }, + }, + }; + }); + }); + } const params = mergeProjection(projection, { body: { @@ -39,6 +57,7 @@ export async function getPageViewTrends({ field: 'transaction.type', }, }, + ...breakdownAggs, }, }, }, @@ -50,8 +69,15 @@ export async function getPageViewTrends({ const response = await client.search(params); const result = response.aggregations?.pageViews.buckets ?? []; - return result.map(({ key, trans_count }) => ({ - x: key, - y: trans_count.value, - })); + return result.map(({ key: xVal, trans_count, ...rest }) => { + const res = { + x: xVal, + y: trans_count.value, + }; + Object.keys(breakdownAggs).forEach((key) => { + res[key] = rest[key]?.doc_count; + }); + + return res; + }); } diff --git a/x-pack/plugins/apm/server/routes/rum_client.ts b/x-pack/plugins/apm/server/routes/rum_client.ts index dcd2fe2cf39ae..7116efa2e1817 100644 --- a/x-pack/plugins/apm/server/routes/rum_client.ts +++ b/x-pack/plugins/apm/server/routes/rum_client.ts @@ -60,10 +60,19 @@ export const breakdownFiltersRoute = createRoute(() => ({ export const rumPageViewsTrendRoute = createRoute(() => ({ path: '/api/apm/rum-client/page-view-trends', params: { - query: t.intersection([uiFiltersRt, rangeRt]), + query: t.intersection([ + uiFiltersRt, + rangeRt, + t.partial({ breakdowns: t.string }), + ]), }, handler: async ({ context, request }) => { const setup = await setupRequest(context, request); - return getPageViewTrends({ setup }); + + const { + query: { breakdowns }, + } = context.params; + + return getPageViewTrends({ setup, breakdowns }); }, })); diff --git a/x-pack/plugins/uptime/public/components/overview/filter_group/filter_popover.tsx b/x-pack/plugins/uptime/public/components/overview/filter_group/filter_popover.tsx index 064907a633df0..c54256b697b5e 100644 --- a/x-pack/plugins/uptime/public/components/overview/filter_group/filter_popover.tsx +++ b/x-pack/plugins/uptime/public/components/overview/filter_group/filter_popover.tsx @@ -23,6 +23,7 @@ export interface FilterPopoverProps { btnContent?: JSX.Element; forceOpen?: boolean; setForceOpen?: (val: boolean) => void; + size?: string; } const isItemSelected = (selectedItems: string[], item: string): 'on' | undefined => @@ -40,6 +41,7 @@ export const FilterPopover = ({ btnContent, forceOpen, setForceOpen, + size, }: FilterPopoverProps) => { const [isOpen, setIsOpen] = useState(false); const [itemsToDisplay, setItemsToDisplay] = useState([]); @@ -79,6 +81,7 @@ export const FilterPopover = ({ onFilterFieldChange(fieldName, tempSelectedItems); }} title={title} + size={size} /> ) } diff --git a/x-pack/plugins/uptime/public/components/overview/filter_group/uptime_filter_button.tsx b/x-pack/plugins/uptime/public/components/overview/filter_group/uptime_filter_button.tsx index 0e05c17d57353..6570e85038aea 100644 --- a/x-pack/plugins/uptime/public/components/overview/filter_group/uptime_filter_button.tsx +++ b/x-pack/plugins/uptime/public/components/overview/filter_group/uptime_filter_button.tsx @@ -14,6 +14,7 @@ interface UptimeFilterButtonProps { numActiveFilters: number; onClick: () => void; title: string; + size?: string; } export const UptimeFilterButton = ({ @@ -23,6 +24,7 @@ export const UptimeFilterButton = ({ numActiveFilters, onClick, title, + size = 'l', }: UptimeFilterButtonProps) => ( {title} From 352621a7b4524cc21c99abde3711b994f9a3ff50 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 18 Jun 2020 09:51:28 +0200 Subject: [PATCH 29/54] fix types --- .../app/RumDashboard/BreakdownFilter.tsx | 10 +----- .../RumDashboard/Charts/PageViewsChart.tsx | 6 ++-- .../PageLoadDistribution/index.tsx | 2 +- .../app/RumDashboard/PageViewsTrend/index.tsx | 2 +- .../lib/rum_client/get_page_view_trends.ts | 35 +++++++++++-------- .../overview/filter_group/filter_popover.tsx | 2 +- .../filter_group/uptime_filter_button.tsx | 4 +-- 7 files changed, 29 insertions(+), 32 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx index df5ab4053ee45..4e522df9850f7 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useMemo, useState } from 'react'; +import React, { useMemo } from 'react'; import { FilterPopover } from '../../../../../uptime/public'; import { useLocalUIFilters } from '../../../hooks/useLocalUIFilters'; import { PROJECTION } from '../../../../common/projections/typings'; @@ -16,10 +16,6 @@ interface Props { } export const BreakdownFilter = ({ fieldName, onBreakdownChange }: Props) => { - const [selectedFilters, setSelectedFilters] = useState>( - new Set([]) - ); - const localUIFiltersConfig = useMemo(() => { const config: React.ComponentProps = { filterNames: ['transactionUrl', 'location', 'device', 'os', 'browser'], @@ -41,10 +37,6 @@ export const BreakdownFilter = ({ fieldName, onBreakdownChange }: Props) => { }); const onFilterFieldChange = (field: string, selValues: string[]) => { - setSelectedFilters((prevState) => { - return new Set(selValues); - }); - const newValues: Map = new Map(); filters.forEach(({ options, fieldName: fieldLabel }) => { diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx index ef820723a551b..32646eae0b75b 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx @@ -56,7 +56,7 @@ export const PageViewsChart: FC = ({ }); }; - let breakdownAccessors = []; + let breakdownAccessors: string[] = []; if (data && data.length > 0) { const allKeys = Object.keys(data[0]); breakdownAccessors = allKeys.filter((key) => key !== 'x'); @@ -67,13 +67,13 @@ export const PageViewsChart: FC = ({ return 'Overall'; } - return yAccessor.split('__')[1]; + return yAccessor.toString().split?.('__')[1]; }; return ( - + { - +

{PageLoadDistLabel}

diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx index ac4347dfe076a..a9c30268c91fa 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx @@ -56,7 +56,7 @@ export const PageViewsTrend = () => { - +

{PageViewsLabel}

diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts b/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts index 7d94873af74e1..130e97b5f1df8 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts @@ -11,31 +11,34 @@ import { SetupTimeRange, SetupUIFilters, } from '../helpers/setup_request'; +import { AggregationInputMap } from '../../../typings/elasticsearch/aggregations'; export async function getPageViewTrends({ setup, breakdowns, }: { setup: Setup & SetupTimeRange & SetupUIFilters; - breakdowns: string; + breakdowns?: string; }) { const projection = getRumOverviewProjection({ setup, }); - const breakdownAggs: any = {}; + const breakdownAggs: AggregationInputMap = {}; if (breakdowns) { const breakdownMap: Map = new Map(JSON.parse(breakdowns)); Array.from(breakdownMap.keys()).map((field) => { const values = breakdownMap.get(field); - values.forEach((value) => { - breakdownAggs[field + '__' + value] = { - filter: { - term: { - [field]: value, + if (values) { + values.forEach((value) => { + breakdownAggs[field + '__' + value] = { + filter: { + term: { + [field]: value, + }, }, - }, - }; - }); + }; + }); + } }); } @@ -52,7 +55,7 @@ export async function getPageViewTrends({ buckets: 50, }, aggs: { - trans_count: { + transCount: { value_count: { field: 'transaction.type', }, @@ -69,13 +72,15 @@ export async function getPageViewTrends({ const response = await client.search(params); const result = response.aggregations?.pageViews.buckets ?? []; - return result.map(({ key: xVal, trans_count, ...rest }) => { - const res = { + return result.map((bucket) => { + const { key: xVal, transCount } = bucket; + const res: Record = { x: xVal, - y: trans_count.value, + y: transCount.value, }; Object.keys(breakdownAggs).forEach((key) => { - res[key] = rest[key]?.doc_count; + // @ts-ignore + res[key] = bucket[key]?.doc_count; }); return res; diff --git a/x-pack/plugins/uptime/public/components/overview/filter_group/filter_popover.tsx b/x-pack/plugins/uptime/public/components/overview/filter_group/filter_popover.tsx index c54256b697b5e..1c99b1c776632 100644 --- a/x-pack/plugins/uptime/public/components/overview/filter_group/filter_popover.tsx +++ b/x-pack/plugins/uptime/public/components/overview/filter_group/filter_popover.tsx @@ -23,7 +23,7 @@ export interface FilterPopoverProps { btnContent?: JSX.Element; forceOpen?: boolean; setForceOpen?: (val: boolean) => void; - size?: string; + size?: 's' | 'l' | 'xs'; } const isItemSelected = (selectedItems: string[], item: string): 'on' | undefined => diff --git a/x-pack/plugins/uptime/public/components/overview/filter_group/uptime_filter_button.tsx b/x-pack/plugins/uptime/public/components/overview/filter_group/uptime_filter_button.tsx index 6570e85038aea..46da89eab5936 100644 --- a/x-pack/plugins/uptime/public/components/overview/filter_group/uptime_filter_button.tsx +++ b/x-pack/plugins/uptime/public/components/overview/filter_group/uptime_filter_button.tsx @@ -14,7 +14,7 @@ interface UptimeFilterButtonProps { numActiveFilters: number; onClick: () => void; title: string; - size?: string; + size?: 's' | 'xs' | 'l'; } export const UptimeFilterButton = ({ @@ -34,7 +34,7 @@ export const UptimeFilterButton = ({ numActiveFilters={numActiveFilters} numFilters={numFilters} onClick={onClick} - size={size as const} + size={size} > {title} From 7056e40815219177c3c3e79188045b3c904cd06f Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 18 Jun 2020 10:57:37 +0200 Subject: [PATCH 30/54] fix e2e --- .../apm/e2e/cypress/integration/helpers.ts | 15 ++++++++++++--- .../e2e/cypress/integration/rum_dashboard.feature | 2 +- .../apm/e2e/cypress/integration/snapshots.js | 6 +++--- .../support/step_definitions/rum_dashboard.ts | 6 ++++-- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/apm/e2e/cypress/integration/helpers.ts b/x-pack/plugins/apm/e2e/cypress/integration/helpers.ts index 213615cae5f75..689b88390810f 100644 --- a/x-pack/plugins/apm/e2e/cypress/integration/helpers.ts +++ b/x-pack/plugins/apm/e2e/cypress/integration/helpers.ts @@ -14,13 +14,22 @@ const BASE_URL = Cypress.config().baseUrl; /** The default time in ms to wait for a Cypress command to complete */ export const DEFAULT_TIMEOUT = 60 * 1000; -export function loginAndWaitForPage(url: string) { +export function loginAndWaitForPage( + url: string, + dateRange?: { to: string; from: string } +) { const username = Cypress.env('elasticsearch_username'); const password = Cypress.env('elasticsearch_password'); cy.log(`Authenticating via ${username} / ${password}`); - - const fullUrl = `${BASE_URL}${url}?rangeFrom=${RANGE_FROM}&rangeTo=${RANGE_TO}`; + let rangeFrom = RANGE_FROM; + let rangeTo = RANGE_TO; + if (dateRange) { + rangeFrom = dateRange.from; + rangeTo = dateRange.to; + } + + const fullUrl = `${BASE_URL}${url}?rangeFrom=${rangeFrom}&rangeTo=${rangeTo}`; cy.visit(fullUrl, { auth: { username, password } }); cy.viewport('macbook-15'); diff --git a/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature b/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature index f0739c7056a80..eabfaf096731b 100644 --- a/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature +++ b/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature @@ -1,7 +1,7 @@ Feature: RUM Dashboard Scenario: Client metrics - Given a user browses the APM UI application + Given a user browses the APM UI application for RUM Data When the user inspects the real user monitoring tab Then should redirect to rum dashboard And should have correct client metrics diff --git a/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js index 6c06a84405ad0..14a396f7bbb23 100644 --- a/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js +++ b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js @@ -2,9 +2,9 @@ module.exports = { "__version": "4.5.0", "APM": { "Transaction duration charts": { - "1": "55.0 ms", - "2": "27.5 ms", - "3": "0.0 ms" + "1": "55 ms", + "2": "28 ms", + "3": "0 ms" } }, "RUM Dashboard": { diff --git a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum_dashboard.ts b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum_dashboard.ts index 9655b71848db9..38eadbf513032 100644 --- a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum_dashboard.ts +++ b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum_dashboard.ts @@ -10,9 +10,11 @@ import { loginAndWaitForPage } from '../../integration/helpers'; /** The default time in ms to wait for a Cypress command to complete */ export const DEFAULT_TIMEOUT = 60 * 1000; -Given(`a user browses the APM UI application`, () => { +Given(`a user browses the APM UI application for RUM Data`, () => { // open service overview page - loginAndWaitForPage(`/app/apm#/services`); + const RANGE_FROM = 'now-24h'; + const RANGE_TO = 'now'; + loginAndWaitForPage(`/app/apm#/services`, { from: RANGE_FROM, to: RANGE_TO }); }); When(`the user inspects the real user monitoring tab`, () => { From fc33078d282027bd28fdea9921e60f7fbcc5037f Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 18 Jun 2020 13:43:21 +0200 Subject: [PATCH 31/54] fix issue with rum timing --- x-pack/plugins/apm/common/projections/rum_overview.ts | 6 ++++++ .../apm/server/lib/rum_client/get_client_metrics.ts | 7 +++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/apm/common/projections/rum_overview.ts b/x-pack/plugins/apm/common/projections/rum_overview.ts index e6e674671f54b..b1218546d09ff 100644 --- a/x-pack/plugins/apm/common/projections/rum_overview.ts +++ b/x-pack/plugins/apm/common/projections/rum_overview.ts @@ -25,6 +25,12 @@ export function getRumOverviewProjection({ { range: rangeFilter(start, end) }, { term: { [PROCESSOR_EVENT]: 'transaction' } }, { term: { [TRANSACTION_TYPE]: 'page-load' } }, + { + // Adding this filter to cater for some inconsistent rum data + exists: { + field: 'transaction.marks.navigationTiming.fetchStart', + }, + }, ...uiFiltersES, ], }; diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts b/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts index 6d231e6f58430..8b3f733fc402a 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts @@ -50,9 +50,12 @@ export async function getClientMetrics({ const response = await client.search(params); const { backEnd, domInteractive, pageViews } = response.aggregations!; + // Divide by 1000 to convert ms into seconds return { pageViews, - backEnd, - frontEnd: { value: domInteractive.value! - backEnd.value! }, + backEnd: { value: (backEnd.value || 0) / 1000 }, + frontEnd: { + value: ((domInteractive.value || 0) - (backEnd.value || 0)) / 1000, + }, }; } From 9529d767852d5385b4e756833a51ede79e719c4e Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 18 Jun 2020 14:02:40 +0200 Subject: [PATCH 32/54] update snapshot --- x-pack/plugins/apm/e2e/cypress/integration/snapshots.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js index 14a396f7bbb23..dd96a57ef8c45 100644 --- a/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js +++ b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js @@ -10,8 +10,8 @@ module.exports = { "RUM Dashboard": { "Client metrics": { "1": "62", - "2": "74.68 sec", - "3": "5.42 sec" + "2": "0.07 sec", + "3": "0.01 sec" } } } From d3149ea3095724147f1d0fc0c1d11caa55c87a53 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 18 Jun 2020 14:43:22 +0200 Subject: [PATCH 33/54] update snapshot --- .../rum_client/__snapshots__/queries.test.ts.snap | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap index 298cef4328d88..7d8f31aaeca7f 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap @@ -44,6 +44,11 @@ Object { "transaction.type": "page-load", }, }, + Object { + "exists": Object { + "field": "transaction.marks.navigationTiming.fetchStart", + }, + }, Object { "term": Object { "my.custom.ui.filter": "foo-bar", @@ -110,6 +115,11 @@ Object { "transaction.type": "page-load", }, }, + Object { + "exists": Object { + "field": "transaction.marks.navigationTiming.fetchStart", + }, + }, Object { "term": Object { "my.custom.ui.filter": "foo-bar", @@ -164,6 +174,11 @@ Object { "transaction.type": "page-load", }, }, + Object { + "exists": Object { + "field": "transaction.marks.navigationTiming.fetchStart", + }, + }, Object { "term": Object { "my.custom.ui.filter": "foo-bar", From 14e88510e68e1f82ff2f2926c8ccda25a2b270db Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 18 Jun 2020 15:05:13 +0200 Subject: [PATCH 34/54] fix types --- .../public/components/app/RumDashboard/ClientMetrics/index.tsx | 2 +- .../public/components/app/RumDashboard/PageViewsTrend/index.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx index 6d126bff60e79..8c0a7c6a91f67 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx @@ -6,7 +6,7 @@ // @flow import * as React from 'react'; import styled from 'styled-components'; -import { EuiFlexGroup, EuiFlexItem, EuiStat, EuiTitle } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiStat } from '@elastic/eui'; import { useFetcher } from '../../../../hooks/useFetcher'; import { useUrlParams } from '../../../../hooks/useUrlParams'; import { BackEndLabel, FrontEndLabel, PageViewsLabel } from '../translations'; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx index 5aac13c985d37..cc41bd4352947 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx @@ -5,7 +5,7 @@ */ import * as React from 'react'; -import { EuiSpacer, EuiTitle } from '@elastic/eui'; +import { EuiTitle } from '@elastic/eui'; import { Axis, BarSeries, From b232189318221d3b82bd8e6fc667e04a6561034f Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 18 Jun 2020 18:14:01 +0200 Subject: [PATCH 35/54] update --- .../app/RumDashboard/BreakdownFilter.tsx | 2 +- .../RumDashboard/Charts/PageLoadDistChart.tsx | 89 +++++++++++-------- .../RumDashboard/Charts/PageViewsChart.tsx | 61 ++++++------- .../PageLoadDistribution/BreakdownSeries.tsx | 10 ++- .../PercentileAnnotations.tsx | 17 +++- .../app/RumDashboard/PageViewsTrend/index.tsx | 9 +- .../app/RumDashboard/translations.ts | 7 ++ 7 files changed, 114 insertions(+), 81 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx index 4e522df9850f7..80180a942aae7 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx @@ -18,7 +18,7 @@ interface Props { export const BreakdownFilter = ({ fieldName, onBreakdownChange }: Props) => { const localUIFiltersConfig = useMemo(() => { const config: React.ComponentProps = { - filterNames: ['transactionUrl', 'location', 'device', 'os', 'browser'], + filterNames: ['location', 'device', 'os', 'browser'], projection: PROJECTION.RUM_OVERVIEW, params: { uiFilters: '{}' }, }; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx index 38984775482ef..dab5cd837e186 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { FC } from 'react'; +import React, { FC, useState } from 'react'; import { Axis, BrushEndListener, @@ -17,6 +17,7 @@ import { TooltipValueFormatter, } from '@elastic/charts'; import { Position } from '@elastic/charts/dist/utils/commons'; +import styled from 'styled-components'; import { PercentileAnnotations } from '../PageLoadDistribution/PercentileAnnotations'; import { PageLoadTimeLabel, PercPageLoadedLabel } from '../translations'; import { ChartWrapper } from '../ChartWrapper'; @@ -31,6 +32,12 @@ interface Props { loading: boolean; } +const PageLoadChart = styled(Chart)` + .echAnnotation { + pointer-events: initial; + } +`; + export const PageLoadDistChart: FC = ({ onPercentileChange, data, @@ -38,6 +45,7 @@ export const PageLoadDistChart: FC = ({ loading, percentileRange, }) => { + const [breakdownLoading, setBreakdownLoading] = useState(false); const onBrushEnd: BrushEndListener = ({ x }) => { if (!x) { return; @@ -59,44 +67,49 @@ export const PageLoadDistChart: FC = ({ }; return ( - - - - - - Number(d).toFixed(1) + ' %'} - /> - - {Array.from(breakdowns.keys()).map((field) => { - const values = breakdowns.get(field); + + {(!loading || data) && ( + + + + + Number(d).toFixed(1) + ' %'} + /> + + {Array.from(breakdowns.keys()).map((field) => { + const values = breakdowns.get(field); - return values?.map((value: string) => { - return ( - - ); - }); - })} - + return values?.map((value: string) => { + return ( + { + setBreakdownLoading(bLoading); + }} + /> + ); + }); + })} + + )} ); }; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx index 32646eae0b75b..d41ab0026eef7 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx @@ -18,7 +18,7 @@ import { } from '@elastic/charts'; import moment from 'moment'; import { Position } from '@elastic/charts/dist/utils/commons'; -import { DateTimeLabel, PageViewsLabel } from '../translations'; +import { DateTimeLabel, OverallLabel, PageViewsLabel } from '../translations'; import { formatBigValue } from '../ClientMetrics'; import { history } from '../../../../utils/history'; import { fromQuery, toQuery } from '../../../shared/Links/url_helpers'; @@ -27,14 +27,9 @@ import { ChartWrapper } from '../ChartWrapper'; interface Props { data: any; loading: boolean; - breakdowns: Map; } -export const PageViewsChart: FC = ({ - data, - loading, - breakdowns, -}: Props) => { +export const PageViewsChart: FC = ({ data, loading }: Props) => { const formatter = timeFormatter(niceTimeFormatByDay(2)); const onBrushEnd: BrushEndListener = ({ x }) => { @@ -64,7 +59,7 @@ export const PageViewsChart: FC = ({ const customSeriesNaming: SeriesNameFn = ({ yAccessor }) => { if (yAccessor === 'y') { - return 'Overall'; + return OverallLabel; } return yAccessor.toString().split?.('__')[1]; @@ -72,30 +67,32 @@ export const PageViewsChart: FC = ({ return ( - - - - formatBigValue(Number(d))} - /> - - + {(!loading || data) && ( + + + + formatBigValue(Number(d))} + /> + + + )} ); }; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/BreakdownSeries.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/BreakdownSeries.tsx index a42e58339c490..345ece859213b 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/BreakdownSeries.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/BreakdownSeries.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { FC } from 'react'; +import React, { FC, useEffect } from 'react'; import { CurveType, LineSeries, ScaleType } from '@elastic/charts'; import { usePageLoadBreakdowns } from './use_breakdowns'; import { PercentileR } from './index'; @@ -13,19 +13,25 @@ interface Props { field: string; value: string; percentileRange: PercentileR; + onLoadingChange: (loading: boolean) => void; } export const BreakdownSeries: FC = ({ field, value, percentileRange, + onLoadingChange, }) => { - const { data } = usePageLoadBreakdowns({ + const { data, loading } = usePageLoadBreakdowns({ field, value, percentileRange, }); + useEffect(() => { + onLoadingChange(loading); + }, [loading, onLoadingChange]); + return ( ; @@ -43,6 +44,10 @@ export const PercentileAnnotations = ({ percentiles }: Props) => { }, }; + const PercentileTooltip = ({ details }) => { + return Percentile: {details}th; + }; + return ( <> {dataValues.map((annotation, index) => ( @@ -52,7 +57,17 @@ export const PercentileAnnotations = ({ percentiles }: Props) => { domainType={AnnotationDomainTypes.XDomain} dataValues={[annotation]} style={style} - marker={{annotation.details}th} + hideTooltips={true} + marker={ + + } + content={Pages loaded {annotation.dataValue}} + > + {annotation.details}th + + + } /> ))} diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx index 59ece5b4e175b..b956744985e03 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx @@ -5,7 +5,7 @@ */ import React, { useState } from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiTitle } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; import { useUrlParams } from '../../../../hooks/useUrlParams'; import { useFetcher } from '../../../../hooks/useFetcher'; import { PageViewsLabel } from '../translations'; @@ -65,12 +65,7 @@ export const PageViewsTrend = () => { />
- - +
); }; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts index c2aed41a55c7d..a221821b08b91 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts @@ -71,3 +71,10 @@ export const ResetZoomLabel = i18n.translate( defaultMessage: 'Reset zoom', } ); + +export const OverallLabel = i18n.translate( + 'xpack.apm.rum.dashboard.overall.label', + { + defaultMessage: 'Overall', + } +); From 4ba1889ce4ae00d0bb5606b633063d467403925c Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 18 Jun 2020 18:31:08 +0200 Subject: [PATCH 36/54] fix issue came out of bad merge --- x-pack/plugins/apm/server/lib/errors/get_error_rate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/apm/server/lib/errors/get_error_rate.ts b/x-pack/plugins/apm/server/lib/errors/get_error_rate.ts index d558e3942a42b..e91d3953942d9 100644 --- a/x-pack/plugins/apm/server/lib/errors/get_error_rate.ts +++ b/x-pack/plugins/apm/server/lib/errors/get_error_rate.ts @@ -10,12 +10,12 @@ import { } from '../../../common/elasticsearch_fieldnames'; import { ProcessorEvent } from '../../../common/processor_event'; import { getMetricsDateHistogramParams } from '../helpers/metrics'; -import { rangeFilter } from '../helpers/range_filter'; import { Setup, SetupTimeRange, SetupUIFilters, } from '../helpers/setup_request'; +import { rangeFilter } from '../../../common/utils/range_filter'; export async function getErrorRate({ serviceName, From 291c30c874d5dd3cc75e05de3b782ee89247ea04 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Fri, 19 Jun 2020 00:18:36 +0200 Subject: [PATCH 37/54] update --- .../app/RumDashboard/BreakdownFilter.tsx | 62 ++++----- .../app/RumDashboard/BreakdownGroup.tsx | 131 ++++++++++++++++++ .../RumDashboard/Charts/PageLoadDistChart.tsx | 31 ++--- .../PercentileAnnotations.tsx | 4 +- .../PageLoadDistribution/index.tsx | 9 +- .../app/RumDashboard/PageViewsTrend/index.tsx | 15 +- .../app/RumDashboard/translations.ts | 14 ++ .../lib/rum_client/get_page_view_trends.ts | 24 ++-- .../lib/ui_filters/local_ui_filters/config.ts | 3 +- x-pack/plugins/apm/typings/ui_filters.ts | 7 + .../overview/filter_group/filter_popover.tsx | 2 - .../filter_group/uptime_filter_button.tsx | 3 - x-pack/plugins/uptime/public/index.ts | 2 - 13 files changed, 222 insertions(+), 85 deletions(-) create mode 100644 x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownGroup.tsx diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx index 80180a942aae7..f38a7190e0568 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx @@ -5,66 +5,66 @@ */ import React, { useMemo } from 'react'; -import { FilterPopover } from '../../../../../uptime/public'; import { useLocalUIFilters } from '../../../hooks/useLocalUIFilters'; import { PROJECTION } from '../../../../common/projections/typings'; import { LocalUIFilters } from '../../shared/LocalUIFilters'; +import { BreakdownGroup } from './BreakdownGroup'; +import { useUrlParams } from '../../../hooks/useUrlParams'; +import { BreakdownItem } from '../../../../typings/ui_filters'; interface Props { - fieldName: string; - onBreakdownChange: (values: Map) => void; + selectedBreakdowns: BreakdownItem[]; + onBreakdownChange: (values: BreakdownItem[]) => void; } -export const BreakdownFilter = ({ fieldName, onBreakdownChange }: Props) => { +export const BreakdownFilter = ({ + selectedBreakdowns, + onBreakdownChange, +}: Props) => { + const { uiFilters, urlParams } = useUrlParams(); + + const { start, end } = urlParams; + const localUIFiltersConfig = useMemo(() => { const config: React.ComponentProps = { filterNames: ['location', 'device', 'os', 'browser'], projection: PROJECTION.RUM_OVERVIEW, - params: { uiFilters: '{}' }, + params: { uiFilters: JSON.stringify(uiFilters), start, end }, }; return config; - }, []); + }, [uiFilters, start, end]); const { filters } = useLocalUIFilters(localUIFiltersConfig); - const items: string[] = []; + const newItems: BreakdownItem[] = []; - filters.forEach(({ options }) => { - options.forEach(({ name }) => { - items.push(name); + filters.forEach(({ options, fieldName }) => { + options.forEach((item) => { + if ( + selectedBreakdowns?.find( + ({ name, type }) => item.name === name && fieldName === type + ) + ) + newItems.push({ ...item, type: fieldName, selected: true }); + else newItems.push({ ...item, type: fieldName, selected: false }); }); }); - const onFilterFieldChange = (field: string, selValues: string[]) => { - const newValues: Map = new Map(); - - filters.forEach(({ options, fieldName: fieldLabel }) => { - const selItems: string[] = []; + const sItems = newItems.sort((a, b) => b.count - a.count); - options.forEach(({ name }) => { - if (selValues.includes(name)) { - selItems.push(name); - } - }); - - if (selItems.length > 0) { - newValues.set(fieldLabel, selItems); - } - }); - onBreakdownChange(newValues); + const onChange = (selValues: BreakdownItem[]) => { + onBreakdownChange(selValues); }; return ( - ); }; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownGroup.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownGroup.tsx new file mode 100644 index 0000000000000..e3baa38869c92 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownGroup.tsx @@ -0,0 +1,131 @@ +/* + * 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. + */ + +/* + * 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 { + EuiFacetButton, + EuiFieldSearch, + EuiFilterButton, + EuiFilterGroup, + EuiFilterSelectItem, + EuiIcon, + EuiPopover, + EuiPopoverTitle, +} from '@elastic/eui'; +import React, { useEffect, useState } from 'react'; +import { LoadingLabel, SearchBreakdownLabel } from './translations'; +import { BreakdownItem } from '../../../../typings/ui_filters'; + +export interface FilterPopoverProps { + fieldName: string; + id: string; + loading: boolean; + disabled?: boolean; + items: BreakdownItem[]; + onChange: (values: BreakdownItem[]) => void; + title: string; +} + +export const BreakdownGroup = ({ + id, + disabled, + loading, + items: allItems, + onChange, + title, +}: FilterPopoverProps) => { + const [isOpen, setIsOpen] = useState(false); + const [query, setQuery] = useState(''); + + const [items, setItems] = useState(allItems || []); + + useEffect(() => { + setItems(allItems); + }, [allItems]); + + const getSelItems = () => items.filter((tItem) => !!tItem.selected); + + const getItemsToDisplay = () => + items.filter( + (tItem) => + tItem.name.toLowerCase().indexOf(query.toLocaleLowerCase()) >= 0 + ); + + return ( + + 0} + numFilters={items.length} + numActiveFilters={getSelItems().length} + hasActiveFilters={getSelItems().length !== 0} + iconType="arrowDown" + onClick={() => { + setIsOpen(!isOpen); + }} + size="s" + > + {title} + + } + closePopover={() => { + setIsOpen(false); + onChange(getSelItems()); + }} + data-test-subj={`filter-popover_${id}`} + id={id} + isOpen={isOpen} + ownFocus={true} + withTitle + zIndex={10000} + > + + setQuery(tQuery)} + placeholder={loading ? LoadingLabel : SearchBreakdownLabel} + /> + +
+ {!loading && + getItemsToDisplay().map(({ name, count, selected }) => ( + + setItems((prevItems) => + prevItems.map((tItem) => ({ + ...tItem, + selected: + name === tItem.name && count === tItem.count + ? !tItem.selected + : tItem.selected, + })) + ) + } + > + } + > + {name} + + + ))} +
+
+
+ ); +}; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx index dab5cd837e186..95fc3a018ac85 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx @@ -23,11 +23,12 @@ import { PageLoadTimeLabel, PercPageLoadedLabel } from '../translations'; import { ChartWrapper } from '../ChartWrapper'; import { BreakdownSeries } from '../PageLoadDistribution/BreakdownSeries'; import { PercentileR } from '../PageLoadDistribution'; +import { BreakdownItem } from '../../../../../typings/ui_filters'; interface Props { onPercentileChange: (min: number, max: number) => void; data: any; - breakdowns: Map; + breakdowns: BreakdownItem[]; percentileRange: PercentileR; loading: boolean; } @@ -91,22 +92,18 @@ export const PageLoadDistChart: FC = ({ data={data?.pageLoadDistribution ?? []} curve={CurveType.CURVE_NATURAL} /> - {Array.from(breakdowns.keys()).map((field) => { - const values = breakdowns.get(field); - - return values?.map((value: string) => { - return ( - { - setBreakdownLoading(bLoading); - }} - /> - ); - }); + {breakdowns.map(({ name, type }) => { + return ( + { + setBreakdownLoading(bLoading); + }} + /> + ); })} )} diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx index 4daf17d92369b..0cec1df08dce5 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx @@ -62,7 +62,9 @@ export const PercentileAnnotations = ({ percentiles }: Props) => { } - content={Pages loaded {annotation.dataValue}} + content={ + Pages loaded: {annotation.dataValue.toFixed(2)} + } > {annotation.details}th diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx index eb61bfc85317f..3c26841baf3da 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx @@ -17,6 +17,7 @@ import { useFetcher } from '../../../../hooks/useFetcher'; import { PageLoadDistLabel, ResetZoomLabel } from '../translations'; import { BreakdownFilter } from '../BreakdownFilter'; import { PageLoadDistChart } from '../Charts/PageLoadDistChart'; +import { BreakdownItem } from '../../../../../typings/ui_filters'; export interface PercentileR { min: string | null; @@ -33,9 +34,7 @@ export const PageLoadDistribution = () => { max: null, }); - const [breakdowns, setBreakdowns] = useState>( - new Map() - ); + const [breakdowns, setBreakdowns] = useState([]); const { data, status } = useFetcher( (callApmApi) => { @@ -65,7 +64,7 @@ export const PageLoadDistribution = () => { setPercentileRange({ min: String(min), max: String(max) }); }; - const onBreakdownChange = (values: Map) => { + const onBreakdownChange = (values: BreakdownItem[]) => { setBreakdowns(values); }; @@ -93,7 +92,7 @@ export const PageLoadDistribution = () => {
diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx index b956744985e03..ebc9284b8a18e 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx @@ -11,15 +11,14 @@ import { useFetcher } from '../../../../hooks/useFetcher'; import { PageViewsLabel } from '../translations'; import { BreakdownFilter } from '../BreakdownFilter'; import { PageViewsChart } from '../Charts/PageViewsChart'; +import { BreakdownItem } from '../../../../../typings/ui_filters'; export const PageViewsTrend = () => { const { urlParams, uiFilters } = useUrlParams(); const { start, end } = urlParams; - const [breakdowns, setBreakdowns] = useState>( - new Map() - ); + const [breakdowns, setBreakdowns] = useState([]); const { data, status } = useFetcher( (callApmApi) => { @@ -31,11 +30,9 @@ export const PageViewsTrend = () => { start, end, uiFilters: JSON.stringify(uiFilters), - ...(breakdowns.size > 0 + ...(breakdowns.length > 0 ? { - breakdowns: JSON.stringify( - Array.from(breakdowns.entries()) - ), + breakdowns: JSON.stringify(breakdowns), } : {}), }, @@ -46,7 +43,7 @@ export const PageViewsTrend = () => { [end, start, uiFilters, breakdowns] ); - const onBreakdownChange = (values: Map) => { + const onBreakdownChange = (values: BreakdownItem[]) => { setBreakdowns(values); }; @@ -60,7 +57,7 @@ export const PageViewsTrend = () => {
diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts index a221821b08b91..2dc6a6554f634 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts @@ -78,3 +78,17 @@ export const OverallLabel = i18n.translate( defaultMessage: 'Overall', } ); + +export const LoadingLabel = i18n.translate( + 'xpack.apm.filterGroup.loadingMessage', + { + defaultMessage: 'Loading...', + } +); + +export const SearchBreakdownLabel = i18n.translate( + 'xpack.uptime.filterGroup.searchMessage', + { + defaultMessage: 'Search breakdown', + } +); diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts b/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts index 130e97b5f1df8..2b529567cd300 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts @@ -12,6 +12,7 @@ import { SetupUIFilters, } from '../helpers/setup_request'; import { AggregationInputMap } from '../../../typings/elasticsearch/aggregations'; +import { BreakdownItem } from '../../../typings/ui_filters'; export async function getPageViewTrends({ setup, @@ -25,20 +26,15 @@ export async function getPageViewTrends({ }); const breakdownAggs: AggregationInputMap = {}; if (breakdowns) { - const breakdownMap: Map = new Map(JSON.parse(breakdowns)); - Array.from(breakdownMap.keys()).map((field) => { - const values = breakdownMap.get(field); - if (values) { - values.forEach((value) => { - breakdownAggs[field + '__' + value] = { - filter: { - term: { - [field]: value, - }, - }, - }; - }); - } + const breakdownList: BreakdownItem[] = JSON.parse(breakdowns); + breakdownList.forEach(({ name, type }) => { + breakdownAggs[type + '__' + name] = { + filter: { + term: { + [type]: name, + }, + }, + }; }); } diff --git a/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts b/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts index 25a559cb07a3d..458f448c383d2 100644 --- a/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts +++ b/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts @@ -16,6 +16,7 @@ import { USER_AGENT_DEVICE, CLIENT_GEO, USER_AGENT_OS, + CLIENT_GEO_COUNTRY_ISO_CODE, } from '../../../../common/elasticsearch_fieldnames'; const filtersByName = { @@ -77,7 +78,7 @@ const filtersByName = { title: i18n.translate('xpack.apm.localFilters.titles.location', { defaultMessage: 'Location', }), - fieldName: CLIENT_GEO, + fieldName: CLIENT_GEO_COUNTRY_ISO_CODE, }, os: { title: i18n.translate('xpack.apm.localFilters.titles.os', { diff --git a/x-pack/plugins/apm/typings/ui_filters.ts b/x-pack/plugins/apm/typings/ui_filters.ts index 3f03e80325b49..7a05f9ee6e79b 100644 --- a/x-pack/plugins/apm/typings/ui_filters.ts +++ b/x-pack/plugins/apm/typings/ui_filters.ts @@ -11,3 +11,10 @@ export type UIFilters = { kuery?: string; environment?: string; } & { [key in LocalUIFilterName]?: string[] }; + +export interface BreakdownItem { + name: string; + count: number; + type: string; + selected?: boolean; +} diff --git a/x-pack/plugins/uptime/public/components/overview/filter_group/filter_popover.tsx b/x-pack/plugins/uptime/public/components/overview/filter_group/filter_popover.tsx index 1c99b1c776632..dfd46de20814b 100644 --- a/x-pack/plugins/uptime/public/components/overview/filter_group/filter_popover.tsx +++ b/x-pack/plugins/uptime/public/components/overview/filter_group/filter_popover.tsx @@ -41,7 +41,6 @@ export const FilterPopover = ({ btnContent, forceOpen, setForceOpen, - size, }: FilterPopoverProps) => { const [isOpen, setIsOpen] = useState(false); const [itemsToDisplay, setItemsToDisplay] = useState([]); @@ -81,7 +80,6 @@ export const FilterPopover = ({ onFilterFieldChange(fieldName, tempSelectedItems); }} title={title} - size={size} /> ) } diff --git a/x-pack/plugins/uptime/public/components/overview/filter_group/uptime_filter_button.tsx b/x-pack/plugins/uptime/public/components/overview/filter_group/uptime_filter_button.tsx index 46da89eab5936..0e05c17d57353 100644 --- a/x-pack/plugins/uptime/public/components/overview/filter_group/uptime_filter_button.tsx +++ b/x-pack/plugins/uptime/public/components/overview/filter_group/uptime_filter_button.tsx @@ -14,7 +14,6 @@ interface UptimeFilterButtonProps { numActiveFilters: number; onClick: () => void; title: string; - size?: 's' | 'xs' | 'l'; } export const UptimeFilterButton = ({ @@ -24,7 +23,6 @@ export const UptimeFilterButton = ({ numActiveFilters, onClick, title, - size = 'l', }: UptimeFilterButtonProps) => ( {title} diff --git a/x-pack/plugins/uptime/public/index.ts b/x-pack/plugins/uptime/public/index.ts index 799e40dcf3356..48cf2c90ad07b 100644 --- a/x-pack/plugins/uptime/public/index.ts +++ b/x-pack/plugins/uptime/public/index.ts @@ -9,5 +9,3 @@ import { UptimePlugin } from './apps'; export const plugin = (initializerContext: PluginInitializerContext) => new UptimePlugin(initializerContext); - -export { FilterPopover } from './components/overview/filter_group/filter_popover'; From aaf36d701d53186ef6f1f57a8f7636ad11d2a766 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Sat, 20 Jun 2020 01:36:12 +0200 Subject: [PATCH 38/54] commit --- .../apm/public/components/app/RumDashboard/BreakdownFilter.tsx | 3 +-- .../apm/public/components/app/RumDashboard/BreakdownGroup.tsx | 1 - .../PageLoadDistribution/PercentileAnnotations.tsx | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx index f38a7190e0568..5e9f8df0948f4 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx @@ -59,8 +59,7 @@ export const BreakdownFilter = ({ return ( ): LineAnnotationDatum[] { - return Object.entries(values ?? {}).map((value, index) => ({ + return Object.entries(values ?? {}).map((value) => ({ dataValue: value[1], details: `${(+value[0]).toFixed(0)}`, })); From b5746f31c4ca9941dda1718c638ab17831ae8139 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Sun, 21 Jun 2020 22:15:17 +0200 Subject: [PATCH 39/54] test --- .../cypress/integration/rum_dashboard.feature | 16 ++++ .../apm/e2e/cypress/integration/snapshots.js | 10 +++ .../step_definitions/rum/page_load_dist.ts | 38 ++++++++ .../step_definitions/rum/rum_dashboard.ts | 86 +++++++++++++++++++ .../{rum_dashboard.ts => rum/rum_filters.ts} | 24 +++--- x-pack/plugins/apm/e2e/ingest-data/replay.js | 17 +++- x-pack/plugins/apm/e2e/ingest-data/rum_ips.js | 19 ++++ .../apm/e2e/ingest-data/user_agents.js | 23 +++++ .../app/RumDashboard/BreakdownFilter.tsx | 4 +- .../app/RumDashboard/BreakdownGroup.tsx | 4 +- .../PercentileAnnotations.tsx | 8 +- .../PageLoadDistribution/index.tsx | 3 +- .../app/RumDashboard/PageViewsTrend/index.tsx | 1 + .../shared/LocalUIFilters/Filter/index.tsx | 1 + 14 files changed, 231 insertions(+), 23 deletions(-) create mode 100644 x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/page_load_dist.ts create mode 100644 x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/rum_dashboard.ts rename x-pack/plugins/apm/e2e/cypress/support/step_definitions/{rum_dashboard.ts => rum/rum_filters.ts} (56%) create mode 100644 x-pack/plugins/apm/e2e/ingest-data/rum_ips.js create mode 100644 x-pack/plugins/apm/e2e/ingest-data/user_agents.js diff --git a/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature b/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature index eabfaf096731b..dd1856e87b06d 100644 --- a/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature +++ b/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature @@ -5,3 +5,19 @@ Feature: RUM Dashboard When the user inspects the real user monitoring tab Then should redirect to rum dashboard And should have correct client metrics + + Scenario: Page load distribution + Given a user browses the APM UI application for RUM Data + When the user inspects the real user monitoring tab + Then should redirect to rum dashboard + And should display percentile for page load chart + And should display tooltip on hover + And should display chart legend + Given a user click page load breakdown filter + When the user selected the breakdown + Then breakdown series should appear in chart + + Given a user click the filter + When the user select the filter + And user applies the selected filter + Then it should filters the client metrics diff --git a/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js index dd96a57ef8c45..757f7203c1eab 100644 --- a/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js +++ b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js @@ -12,6 +12,16 @@ module.exports = { "1": "62", "2": "0.07 sec", "3": "0.01 sec" + }, + "Page load distribution": { + "1": "50th", + "2": "75th", + "3": "90th", + "4": "95th", + "5": "Pages loaded", + "6": "15", + "7": "0.07 sec", + "8": "0.01 sec" } } } diff --git a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/page_load_dist.ts b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/page_load_dist.ts new file mode 100644 index 0000000000000..f62782252901a --- /dev/null +++ b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/page_load_dist.ts @@ -0,0 +1,38 @@ +/* + * 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 { Given, When, Then } from 'cypress-cucumber-preprocessor/steps'; + +/** The default time in ms to wait for a Cypress command to complete */ +export const DEFAULT_TIMEOUT = 60 * 1000; + +Given(`a user click page load breakdown filter`, () => { + // wait for all loading to finish + cy.get('kbnLoadingIndicator').should('not.be.visible'); + cy.get('.euiStat__title-isLoading').should('not.be.visible'); + const breakDownBtn = cy.get('[data-cy=breakdown-popover_pageLoad]'); + breakDownBtn.click(); +}); + +When(`the user selected the breakdown`, () => { + cy.get('[data-cy=filter-breakdown-item_DE]').click(); + // click outside popover to close it + cy.get('[data-cy=pageLoadDist]').click(); +}); + +Then(`breakdown series should appear in chart`, () => { + cy.get('.euiLoadingChart').should('not.be.visible'); + cy.get('div.echLegendItem__label[title=DE] ') + .invoke('text') + .should('eq', 'DE'); +}); + +Then(`breakdown series should appear in chart`, () => { + cy.get('.euiLoadingChart').should('not.be.visible'); + cy.get('div.echLegendItem__label[title=DE] ') + .invoke('text') + .should('eq', 'DE'); +}); diff --git a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/rum_dashboard.ts b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/rum_dashboard.ts new file mode 100644 index 0000000000000..24961ceb3b3c2 --- /dev/null +++ b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/rum_dashboard.ts @@ -0,0 +1,86 @@ +/* + * 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 { Given, When, Then } from 'cypress-cucumber-preprocessor/steps'; +import { loginAndWaitForPage } from '../../../integration/helpers'; + +/** The default time in ms to wait for a Cypress command to complete */ +export const DEFAULT_TIMEOUT = 60 * 1000; + +Given(`a user browses the APM UI application for RUM Data`, () => { + // open service overview page + const RANGE_FROM = 'now-24h'; + const RANGE_TO = 'now'; + loginAndWaitForPage(`/app/apm#/services`, { from: RANGE_FROM, to: RANGE_TO }); +}); + +When(`the user inspects the real user monitoring tab`, () => { + // click rum tab + cy.get(':contains(Real User Monitoring)', { timeout: DEFAULT_TIMEOUT }) + .last() + .click({ force: true }); +}); + +Then(`should redirect to rum dashboard`, () => { + cy.url().should('contain', `/app/apm#/rum-overview`); +}); + +Then(`should have correct client metrics`, () => { + const clientMetrics = '[data-cy=client-metrics] .euiStat__title'; + + // wait for all loading to finish + cy.get('kbnLoadingIndicator').should('not.be.visible'); + cy.get('.euiStat__title-isLoading').should('not.be.visible'); + + cy.get(clientMetrics).eq(2).invoke('text').snapshot(); + + cy.get(clientMetrics).eq(1).invoke('text').snapshot(); + + cy.get(clientMetrics).eq(0).invoke('text').snapshot(); +}); + +Then(`should display percentile for page load chart`, () => { + const pMarkers = '[data-cy=percentile-markers] span'; + + cy.get('.euiLoadingChart').should('be.visible'); + + // wait for all loading to finish + cy.get('kbnLoadingIndicator').should('not.be.visible'); + cy.get('.euiStat__title-isLoading').should('not.be.visible'); + + cy.get(pMarkers).eq(0).invoke('text').snapshot(); + + cy.get(pMarkers).eq(1).invoke('text').snapshot(); + + cy.get(pMarkers).eq(2).invoke('text').snapshot(); + + cy.get(pMarkers).eq(3).invoke('text').snapshot(); +}); + +Then(`should display chart legend`, () => { + const chartLegend = 'div.echLegendItem__label'; + + // wait for all loading to finish + cy.get('kbnLoadingIndicator').should('not.be.visible'); + cy.get('.euiLoadingChart').should('not.be.visible'); + + cy.get(chartLegend).eq(0).invoke('text').snapshot(); +}); + +Then(`should display tooltip on hover`, () => { + cy.get('.euiLoadingChart').should('not.be.visible'); + + const pMarkers = '[data-cy=percentile-markers] span.euiToolTipAnchor'; + + // wait for all loading to finish + cy.get('kbnLoadingIndicator').should('not.be.visible'); + cy.get('.euiLoadingChart').should('not.be.visible'); + + const marker = cy.get(pMarkers).eq(0); + marker.invoke('show'); + marker.trigger('mouseover', { force: true }); + cy.get('span[data-cy=percentileTooltipTitle]').should('be.visible'); +}); diff --git a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum_dashboard.ts b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/rum_filters.ts similarity index 56% rename from x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum_dashboard.ts rename to x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/rum_filters.ts index 38eadbf513032..445eaf3c752b7 100644 --- a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum_dashboard.ts +++ b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/rum_filters.ts @@ -5,30 +5,26 @@ */ import { Given, When, Then } from 'cypress-cucumber-preprocessor/steps'; -import { loginAndWaitForPage } from '../../integration/helpers'; /** The default time in ms to wait for a Cypress command to complete */ export const DEFAULT_TIMEOUT = 60 * 1000; -Given(`a user browses the APM UI application for RUM Data`, () => { - // open service overview page - const RANGE_FROM = 'now-24h'; - const RANGE_TO = 'now'; - loginAndWaitForPage(`/app/apm#/services`, { from: RANGE_FROM, to: RANGE_TO }); +Given(`a user click the filter`, () => { + // wait for all loading to finish + cy.get('kbnLoadingIndicator').should('not.be.visible'); + cy.get('.euiStat__title-isLoading').should('not.be.visible'); + cy.get('#local-filter-os').click(); }); -When(`the user inspects the real user monitoring tab`, () => { - // click rum tab - cy.get(':contains(Real User Monitoring)', { timeout: DEFAULT_TIMEOUT }) - .last() - .click({ force: true }); +When(`the user select the filter`, () => { + cy.get('button.euiSelectableListItem[title="Mac OS X"]').click(); }); -Then(`should redirect to rum dashboard`, () => { - cy.url().should('contain', `/app/apm#/rum-overview`); +Then(`user applies the selected filter`, () => { + cy.get('[data-cy=applyFilter]').click(); }); -Then(`should have correct client metrics`, () => { +Then(`it should filters the client metrics`, () => { const clientMetrics = '[data-cy=client-metrics] .euiStat__title'; // wait for all loading to finish diff --git a/x-pack/plugins/apm/e2e/ingest-data/replay.js b/x-pack/plugins/apm/e2e/ingest-data/replay.js index 3478039f39b50..483cc99df7470 100644 --- a/x-pack/plugins/apm/e2e/ingest-data/replay.js +++ b/x-pack/plugins/apm/e2e/ingest-data/replay.js @@ -35,6 +35,8 @@ const pLimit = require('p-limit'); const pRetry = require('p-retry'); const { argv } = require('yargs'); const ora = require('ora'); +const userAgents = require('./user_agents'); +const userIps = require('./rum_ips'); const APM_SERVER_URL = argv.serverUrl; const SECRET_TOKEN = argv.secretToken; @@ -66,7 +68,7 @@ function incrementSpinnerCount({ success }) { spinner.text = `Remaining: ${remaining}. Succeeded: ${requestProgress.succeeded}. Failed: ${requestProgress.failed}.`; } - +let iterIndex = 0; async function insertItem(item) { try { const url = `${APM_SERVER_URL}${item.url}`; @@ -74,6 +76,15 @@ async function insertItem(item) { 'content-type': 'application/x-ndjson', }; + if (item.url === '/intake/v2/rum/events') { + if (iterIndex === userAgents.length) { + iterIndex = 0; + } + headers['User-Agent'] = userAgents[iterIndex]; + headers['X-Forwarded-For'] = userIps[iterIndex]; + iterIndex++; + } + if (SECRET_TOKEN) { headers.Authorization = `Bearer ${SECRET_TOKEN}`; } @@ -113,7 +124,9 @@ async function init() { items.map(async (item) => { try { // retry 5 times with exponential backoff - await pRetry(() => limit(() => insertItem(item)), { retries: 5 }); + await pRetry(() => limit(() => insertItem(item)), { + retries: 5, + }); incrementSpinnerCount({ success: true }); } catch (e) { incrementSpinnerCount({ success: false }); diff --git a/x-pack/plugins/apm/e2e/ingest-data/rum_ips.js b/x-pack/plugins/apm/e2e/ingest-data/rum_ips.js new file mode 100644 index 0000000000000..59152cd90701b --- /dev/null +++ b/x-pack/plugins/apm/e2e/ingest-data/rum_ips.js @@ -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; + * you may not use this file except in compliance with the Elastic License. + */ + +const IPS = [ + '89.191.86.214', // check24.de + '167.40.79.24', // canada.ca + '151.101.130.217', // elastic.co + '185.143.68.17', + '151.101.130.217', + '185.143.68.17', + '185.143.68.17', + '151.101.130.217', + '185.143.68.17', +]; + +module.exports = IPS; diff --git a/x-pack/plugins/apm/e2e/ingest-data/user_agents.js b/x-pack/plugins/apm/e2e/ingest-data/user_agents.js new file mode 100644 index 0000000000000..923726c4736b6 --- /dev/null +++ b/x-pack/plugins/apm/e2e/ingest-data/user_agents.js @@ -0,0 +1,23 @@ +/* + * 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. + */ + +/* eslint-disable no-console */ + +/* eslint-disable import/no-extraneous-dependencies */ + +const UserAgents = [ + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36', + 'Mozilla/5.0 (Linux; Android 8.0.0; SM-G960F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/69.0.3497.105 Mobile/15E148 Safari/605.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (Linux; Android 7.0; Pixel C Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/52.0.2743.98 Safari/537.36', + 'Mozilla/5.0 (X11; CrOS x86_64 8172.45.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.64 Safari/537.36', + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/601.3.9 (KHTML, like Gecko) Version/9.0.2 Safari/601.3.9', + 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0.1', + 'Mozilla/5.0 (CrKey armv7l 1.5.16041) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.0 Safari/537.36', +]; + +module.exports = UserAgents; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx index 5e9f8df0948f4..ef34c13e5b892 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx @@ -13,11 +13,13 @@ import { useUrlParams } from '../../../hooks/useUrlParams'; import { BreakdownItem } from '../../../../typings/ui_filters'; interface Props { + id: string; selectedBreakdowns: BreakdownItem[]; onBreakdownChange: (values: BreakdownItem[]) => void; } export const BreakdownFilter = ({ + id, selectedBreakdowns, onBreakdownChange, }: Props) => { @@ -59,7 +61,7 @@ export const BreakdownFilter = ({ return ( ( setItems((prevItems) => diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx index d10bd5f70a673..ac1534219e5f9 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx @@ -45,7 +45,9 @@ export const PercentileAnnotations = ({ percentiles }: Props) => { }; const PercentileTooltip = ({ details }) => { - return Percentile: {details}th; + return ( + Percentile: {details}th + ); }; return ( @@ -59,14 +61,14 @@ export const PercentileAnnotations = ({ percentiles }: Props) => { style={style} hideTooltips={true} marker={ - + } content={ Pages loaded: {annotation.dataValue.toFixed(2)} } > - {annotation.details}th + <>{annotation.details}th } diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx index 3c26841baf3da..74f441be5a983 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx @@ -69,7 +69,7 @@ export const PageLoadDistribution = () => { }; return ( -
+
@@ -92,6 +92,7 @@ export const PageLoadDistribution = () => { diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx index ebc9284b8a18e..9778ac7692dc3 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx @@ -57,6 +57,7 @@ export const PageViewsTrend = () => { diff --git a/x-pack/plugins/apm/public/components/shared/LocalUIFilters/Filter/index.tsx b/x-pack/plugins/apm/public/components/shared/LocalUIFilters/Filter/index.tsx index 45b32a82c2f8b..a0b3bbd58c412 100644 --- a/x-pack/plugins/apm/public/components/shared/LocalUIFilters/Filter/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/LocalUIFilters/Filter/index.tsx @@ -141,6 +141,7 @@ const Filter = ({ { From f9fe8e3f9f45c65103622eb1f05e923c52a0f555 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Mon, 22 Jun 2020 16:49:52 +0200 Subject: [PATCH 40/54] up --- .../RumDashboard/Charts/PageLoadDistChart.tsx | 18 +++++++++++++++-- .../RumDashboard/Charts/PageViewsChart.tsx | 20 +++++++++++++++++-- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx index 95fc3a018ac85..8001032160921 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx @@ -15,7 +15,13 @@ import { Settings, TooltipValue, TooltipValueFormatter, + DARK_THEME, + LIGHT_THEME, } from '@elastic/charts'; +import { + EUI_CHARTS_THEME_DARK, + EUI_CHARTS_THEME_LIGHT, +} from '@elastic/eui/dist/eui_charts_theme'; import { Position } from '@elastic/charts/dist/utils/commons'; import styled from 'styled-components'; import { PercentileAnnotations } from '../PageLoadDistribution/PercentileAnnotations'; @@ -24,6 +30,7 @@ import { ChartWrapper } from '../ChartWrapper'; import { BreakdownSeries } from '../PageLoadDistribution/BreakdownSeries'; import { PercentileR } from '../PageLoadDistribution'; import { BreakdownItem } from '../../../../../typings/ui_filters'; +import { useUiSetting$ } from '../../../../../../../../src/plugins/kibana_react/public'; interface Props { onPercentileChange: (min: number, max: number) => void; @@ -67,11 +74,18 @@ export const PageLoadDistChart: FC = ({ headerFormatter, }; + const [darkMode] = useUiSetting$('theme:darkMode'); + return ( {(!loading || data) && ( - - + + = ({ data, loading }: Props) => { return yAccessor.toString().split?.('__')[1]; }; + const [darkMode] = useUiSetting$('theme:darkMode'); + return ( {(!loading || data) && ( - - + + = ({ data, loading }: Props) => { title={PageViewsLabel} position={Position.Left} tickFormat={(d) => formatBigValue(Number(d))} + showGridLines /> Date: Tue, 23 Jun 2020 20:25:39 +0200 Subject: [PATCH 41/54] fix theme --- .../app/RumDashboard/BreakdownFilter.tsx | 20 ++++++++++++++++++ .../app/RumDashboard/BreakdownGroup.tsx | 21 ++++++++++--------- .../RumDashboard/Charts/PageLoadDistChart.tsx | 5 +++++ .../RumDashboard/Charts/PageViewsChart.tsx | 4 +++- .../PageLoadDistribution/index.tsx | 2 +- .../app/RumDashboard/PageViewsTrend/index.tsx | 3 ++- 6 files changed, 42 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx index ef34c13e5b892..0fe9f6cd90def 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx @@ -59,10 +59,30 @@ export const BreakdownFilter = ({ onBreakdownChange(selValues); }; + const categories: BreakdownItem[] = [ + { + name: 'Browser', + type: 'category', + }, + { + name: 'OS', + type: 'category', + }, + { + name: 'Device', + type: 'category', + }, + { + name: 'Location', + type: 'category', + }, + ]; + return ( void; title: string; } @@ -40,7 +40,8 @@ export const BreakdownGroup = ({ items: allItems, onChange, title, -}: FilterPopoverProps) => { + categories, +}: BreakdownGroupProps) => { const [isOpen, setIsOpen] = useState(false); const [query, setQuery] = useState(''); @@ -115,12 +116,12 @@ export const BreakdownGroup = ({ ) } > - } - > - {name} - + + {name} + + {count} + + ))}
diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx index 8001032160921..4e034c5bc01ed 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx @@ -82,6 +82,11 @@ export const PageLoadDistChart: FC = ({ = ({ data, loading }: Props) => { {(!loading || data) && ( = ({ data, loading }: Props) => { title={PageViewsLabel} position={Position.Left} tickFormat={(d) => formatBigValue(Number(d))} - showGridLines /> { /> - + { /> +
); From 5d267fe8e891b6d9800bf934edd3f7e5ab4805a0 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 25 Jun 2020 18:26:28 +0200 Subject: [PATCH 42/54] update --- .../app/RumDashboard/BreakdownFilter.tsx | 91 ------------------ .../Breakdowns/BreakdownFilter.tsx | 64 +++++++++++++ .../{ => Breakdowns}/BreakdownGroup.tsx | 58 ++++------- .../RumDashboard/Charts/PageLoadDistChart.tsx | 36 +++---- .../RumDashboard/Charts/PageViewsChart.tsx | 6 +- .../app/RumDashboard/ClientMetrics/index.tsx | 10 +- .../PageLoadDistribution/BreakdownSeries.tsx | 25 +++-- .../PercentileAnnotations.tsx | 18 ++-- .../PageLoadDistribution/index.tsx | 17 ++-- .../PageLoadDistribution/use_breakdowns.ts | 15 +-- .../app/RumDashboard/PageViewsTrend/index.tsx | 2 +- .../app/RumDashboard/translations.ts | 11 +-- .../lib/rum_client/get_breakdown_filters.ts | 57 ----------- .../rum_client/get_page_load_distribution.ts | 44 +++------ .../lib/rum_client/get_page_view_trends.ts | 34 ++++--- .../lib/rum_client/get_pl_dist_breakdown.ts | 96 +++++++++++++++++++ .../lib/ui_filters/local_ui_filters/config.ts | 1 - .../apm/server/routes/create_apm_api.ts | 4 +- .../plugins/apm/server/routes/rum_client.ts | 25 ++++- .../apm/typings/elasticsearch/aggregations.ts | 31 +++--- x-pack/plugins/apm/typings/ui_filters.ts | 1 + 21 files changed, 314 insertions(+), 332 deletions(-) delete mode 100644 x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx create mode 100644 x-pack/plugins/apm/public/components/app/RumDashboard/Breakdowns/BreakdownFilter.tsx rename x-pack/plugins/apm/public/components/app/RumDashboard/{ => Breakdowns}/BreakdownGroup.tsx (65%) delete mode 100644 x-pack/plugins/apm/server/lib/rum_client/get_breakdown_filters.ts create mode 100644 x-pack/plugins/apm/server/lib/rum_client/get_pl_dist_breakdown.ts diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx deleted file mode 100644 index 0fe9f6cd90def..0000000000000 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownFilter.tsx +++ /dev/null @@ -1,91 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import React, { useMemo } from 'react'; -import { useLocalUIFilters } from '../../../hooks/useLocalUIFilters'; -import { PROJECTION } from '../../../../common/projections/typings'; -import { LocalUIFilters } from '../../shared/LocalUIFilters'; -import { BreakdownGroup } from './BreakdownGroup'; -import { useUrlParams } from '../../../hooks/useUrlParams'; -import { BreakdownItem } from '../../../../typings/ui_filters'; - -interface Props { - id: string; - selectedBreakdowns: BreakdownItem[]; - onBreakdownChange: (values: BreakdownItem[]) => void; -} - -export const BreakdownFilter = ({ - id, - selectedBreakdowns, - onBreakdownChange, -}: Props) => { - const { uiFilters, urlParams } = useUrlParams(); - - const { start, end } = urlParams; - - const localUIFiltersConfig = useMemo(() => { - const config: React.ComponentProps = { - filterNames: ['location', 'device', 'os', 'browser'], - projection: PROJECTION.RUM_OVERVIEW, - params: { uiFilters: JSON.stringify(uiFilters), start, end }, - }; - - return config; - }, [uiFilters, start, end]); - - const { filters } = useLocalUIFilters(localUIFiltersConfig); - - const newItems: BreakdownItem[] = []; - - filters.forEach(({ options, fieldName }) => { - options.forEach((item) => { - if ( - selectedBreakdowns?.find( - ({ name, type }) => item.name === name && fieldName === type - ) - ) - newItems.push({ ...item, type: fieldName, selected: true }); - else newItems.push({ ...item, type: fieldName, selected: false }); - }); - }); - - const sItems = newItems.sort((a, b) => b.count - a.count); - - const onChange = (selValues: BreakdownItem[]) => { - onBreakdownChange(selValues); - }; - - const categories: BreakdownItem[] = [ - { - name: 'Browser', - type: 'category', - }, - { - name: 'OS', - type: 'category', - }, - { - name: 'Device', - type: 'category', - }, - { - name: 'Location', - type: 'category', - }, - ]; - - return ( - - ); -}; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/Breakdowns/BreakdownFilter.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/Breakdowns/BreakdownFilter.tsx new file mode 100644 index 0000000000000..986543ee7bf93 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/Breakdowns/BreakdownFilter.tsx @@ -0,0 +1,64 @@ +/* + * 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 React from 'react'; +import { BreakdownGroup } from './BreakdownGroup'; +import { BreakdownItem } from '../../../../../typings/ui_filters'; +import { + CLIENT_GEO_COUNTRY_ISO_CODE, + USER_AGENT_DEVICE, + USER_AGENT_NAME, + USER_AGENT_OS, +} from '../../../../../common/elasticsearch_fieldnames'; + +interface Props { + id: string; + selectedBreakdowns: BreakdownItem[]; + onBreakdownChange: (values: BreakdownItem[]) => void; +} + +export const BreakdownFilter = ({ + id, + selectedBreakdowns, + onBreakdownChange, +}: Props) => { + const onChange = (selValues: BreakdownItem[]) => { + onBreakdownChange(selValues); + }; + + const categories: BreakdownItem[] = [ + { + name: 'Browser', + type: 'category', + count: 0, + selected: !!selectedBreakdowns.find(({ name }) => name === 'Browser'), + fieldName: USER_AGENT_NAME, + }, + { + name: 'OS', + type: 'category', + count: 0, + selected: !!selectedBreakdowns.find(({ name }) => name === 'OS'), + fieldName: USER_AGENT_OS, + }, + { + name: 'Device', + type: 'category', + count: 0, + selected: !!selectedBreakdowns.find(({ name }) => name === 'Device'), + fieldName: USER_AGENT_DEVICE, + }, + { + name: 'Location', + type: 'category', + count: 0, + selected: !!selectedBreakdowns.find(({ name }) => name === 'Location'), + fieldName: CLIENT_GEO_COUNTRY_ISO_CODE, + }, + ]; + + return ; +}; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownGroup.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/Breakdowns/BreakdownGroup.tsx similarity index 65% rename from x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownGroup.tsx rename to x-pack/plugins/apm/public/components/app/RumDashboard/Breakdowns/BreakdownGroup.tsx index 5d772832a62c6..295b3ca84089a 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/BreakdownGroup.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/Breakdowns/BreakdownGroup.tsx @@ -11,41 +11,32 @@ */ import { - EuiFieldSearch, + EuiPopover, EuiFilterButton, EuiFilterGroup, - EuiFilterSelectItem, - EuiNotificationBadge, - EuiPopover, EuiPopoverTitle, + EuiFilterSelectItem, } from '@elastic/eui'; import React, { useEffect, useState } from 'react'; -import { LoadingLabel, SearchBreakdownLabel } from './translations'; -import { BreakdownItem } from '../../../../typings/ui_filters'; +import { BreakdownItem } from '../../../../../typings/ui_filters'; +import { SelectBreakdownLabel } from '../translations'; export interface BreakdownGroupProps { id: string; - loading: boolean; disabled?: boolean; items: BreakdownItem[]; - categories: BreakdownItem[]; onChange: (values: BreakdownItem[]) => void; - title: string; } export const BreakdownGroup = ({ id, disabled, - loading, - items: allItems, onChange, - title, - categories, + items: allItems, }: BreakdownGroupProps) => { const [isOpen, setIsOpen] = useState(false); - const [query, setQuery] = useState(''); - const [items, setItems] = useState(allItems || []); + const [items, setItems] = useState(allItems); useEffect(() => { setItems(allItems); @@ -53,12 +44,6 @@ export const BreakdownGroup = ({ const getSelItems = () => items.filter((tItem) => !!tItem.selected); - const getItemsToDisplay = () => - items.filter( - (tItem) => - tItem.name.toLowerCase().indexOf(query.toLocaleLowerCase()) >= 0 - ); - return ( - {title} + Breakdown } closePopover={() => { @@ -89,22 +74,16 @@ export const BreakdownGroup = ({ withTitle zIndex={10000} > - - setQuery(tQuery)} - placeholder={loading ? LoadingLabel : SearchBreakdownLabel} - /> - -
- {!loading && - getItemsToDisplay().map(({ name, count, selected }) => ( + {SelectBreakdownLabel} +
+ {items + .filter(({ type }) => type === 'category') + .map(({ name, count, selected, type, fieldName }) => ( + onClick={() => { setItems((prevItems) => prevItems.map((tItem) => ({ ...tItem, @@ -113,15 +92,10 @@ export const BreakdownGroup = ({ ? !tItem.selected : tItem.selected, })) - ) - } + ); + }} > - - {name} - - {count} - - + {name} ))}
diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx index 4e034c5bc01ed..6205118dfcf5a 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx @@ -25,12 +25,16 @@ import { import { Position } from '@elastic/charts/dist/utils/commons'; import styled from 'styled-components'; import { PercentileAnnotations } from '../PageLoadDistribution/PercentileAnnotations'; -import { PageLoadTimeLabel, PercPageLoadedLabel } from '../translations'; +import { + OverallLabel, + PageLoadTimeLabel, + PercPageLoadedLabel, +} from '../translations'; import { ChartWrapper } from '../ChartWrapper'; -import { BreakdownSeries } from '../PageLoadDistribution/BreakdownSeries'; import { PercentileR } from '../PageLoadDistribution'; import { BreakdownItem } from '../../../../../typings/ui_filters'; import { useUiSetting$ } from '../../../../../../../../src/plugins/kibana_react/public'; +import { BreakdownSeries } from '../PageLoadDistribution/BreakdownSeries'; interface Props { onPercentileChange: (min: number, max: number) => void; @@ -77,7 +81,7 @@ export const PageLoadDistChart: FC = ({ const [darkMode] = useUiSetting$('theme:darkMode'); return ( - + {(!loading || data) && ( = ({ /> - {breakdowns.map(({ name, type }) => { - return ( - { - setBreakdownLoading(bLoading); - }} - /> - ); - })} + {breakdowns.map(({ name, type }) => ( + { + setBreakdownLoading(bLoading); + }} + /> + ))} )} diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx index 95b2c7ee4a137..169f3b688e578 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx @@ -16,7 +16,7 @@ import { Settings, timeFormatter, } from '@elastic/charts'; -import { DARK_THEME, LIGHT_THEME, PartialTheme, Theme } from '@elastic/charts'; +import { DARK_THEME, LIGHT_THEME } from '@elastic/charts'; import { EUI_CHARTS_THEME_DARK, @@ -75,9 +75,9 @@ export const PageViewsChart: FC = ({ data, loading }: Props) => { const [darkMode] = useUiSetting$('theme:darkMode'); return ( - + {(!loading || data) && ( - + { +export const formatBigValue = (val?: number | null): string => { if (val && val >= 1000) { const result = val / 1000; - if (fixed) { - return result.toFixed(fixed) + 'k'; - } - return result + 'k'; + + return Math.round(result) + 'k'; } return val + ''; }; @@ -72,7 +70,7 @@ export const ClientMetrics = () => { diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/BreakdownSeries.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/BreakdownSeries.tsx index 345ece859213b..e84302c0ae68f 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/BreakdownSeries.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/BreakdownSeries.tsx @@ -6,8 +6,8 @@ import React, { FC, useEffect } from 'react'; import { CurveType, LineSeries, ScaleType } from '@elastic/charts'; -import { usePageLoadBreakdowns } from './use_breakdowns'; import { PercentileR } from './index'; +import { useBreakdowns } from './use_breakdowns'; interface Props { field: string; @@ -22,7 +22,7 @@ export const BreakdownSeries: FC = ({ percentileRange, onLoadingChange, }) => { - const { data, loading } = usePageLoadBreakdowns({ + const { data, loading } = useBreakdowns({ field, value, percentileRange, @@ -33,13 +33,18 @@ export const BreakdownSeries: FC = ({ }, [loading, onLoadingChange]); return ( - + <> + {data?.map(({ data: seriesData, name }) => ( + + ))} + ); }; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx index ac1534219e5f9..38d53aebd1b7f 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx @@ -23,14 +23,14 @@ function generateAnnotationData( values?: Record ): LineAnnotationDatum[] { return Object.entries(values ?? {}).map((value) => ({ - dataValue: value[1], + dataValue: Math.round(value[1] / 1000), details: `${(+value[0]).toFixed(0)}`, })); } const PercentileMarker = styled.span` position: relative; - bottom: 140px; + bottom: 205px; `; export const PercentileAnnotations = ({ percentiles }: Props) => { @@ -44,9 +44,15 @@ export const PercentileAnnotations = ({ percentiles }: Props) => { }, }; - const PercentileTooltip = ({ details }) => { + const PercentileTooltip = ({ + annotation, + }: { + annotation: LineAnnotationDatum; + }) => { return ( - Percentile: {details}th + + {annotation.details}th Percentile + ); }; @@ -63,9 +69,9 @@ export const PercentileAnnotations = ({ percentiles }: Props) => { marker={ } + title={} content={ - Pages loaded: {annotation.dataValue.toFixed(2)} + Pages loaded: {Math.round(annotation.dataValue)} } > <>{annotation.details}th diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx index 11e776309480e..18228323b75fa 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx @@ -15,13 +15,13 @@ import { import { useUrlParams } from '../../../../hooks/useUrlParams'; import { useFetcher } from '../../../../hooks/useFetcher'; import { PageLoadDistLabel, ResetZoomLabel } from '../translations'; -import { BreakdownFilter } from '../BreakdownFilter'; +import { BreakdownFilter } from '../Breakdowns/BreakdownFilter'; import { PageLoadDistChart } from '../Charts/PageLoadDistChart'; import { BreakdownItem } from '../../../../../typings/ui_filters'; export interface PercentileR { - min: string | null; - max: string | null; + min?: number | null; + max?: number | null; } export const PageLoadDistribution = () => { @@ -48,8 +48,8 @@ export const PageLoadDistribution = () => { uiFilters: JSON.stringify(uiFilters), ...(percentileRange.min && percentileRange.max ? { - minPercentile: percentileRange.min, - maxPercentile: percentileRange.max, + minPercentile: String(percentileRange.min), + maxPercentile: String(percentileRange.max), } : {}), }, @@ -61,7 +61,7 @@ export const PageLoadDistribution = () => { ); const onPercentileChange = (min: number, max: number) => { - setPercentileRange({ min: String(min), max: String(max) }); + setPercentileRange({ min, max }); }; const onBreakdownChange = (values: BreakdownItem[]) => { @@ -104,7 +104,10 @@ export const PageLoadDistribution = () => { onPercentileChange={onPercentileChange} loading={status !== 'success'} breakdowns={breakdowns} - percentileRange={percentileRange} + percentileRange={{ + max: percentileRange.max || data?.maxDuration, + min: percentileRange.min || data?.minDuration, + }} />
); diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/use_breakdowns.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/use_breakdowns.ts index 60f3e62debbf2..570b222177ad6 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/use_breakdowns.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/use_breakdowns.ts @@ -14,11 +14,7 @@ interface Props { value: string; } -export const usePageLoadBreakdowns = ({ - percentileRange, - field, - value, -}: Props) => { +export const useBreakdowns = ({ percentileRange, field, value }: Props) => { const { urlParams, uiFilters } = useUrlParams(); const { start, end } = urlParams; @@ -28,19 +24,18 @@ export const usePageLoadBreakdowns = ({ const { data, status } = useFetcher( (callApmApi) => { if (start && end && field && value) { - uiFilters.kuery = `${field}: ${value}`; - return callApmApi({ - pathname: '/api/apm/rum-client/page-load-distribution', + pathname: '/api/apm/rum-client/page-load-distribution/breakdown', params: { query: { start, end, + breakdown: value, uiFilters: JSON.stringify(uiFilters), ...(minP && maxP ? { - minPercentile: minP, - maxPercentile: maxP, + minPercentile: String(minP), + maxPercentile: String(maxP), } : {}), }, diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx index f8f78dce82ae4..b371d9d31ac36 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx @@ -9,7 +9,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiTitle } from '@elastic/eui'; import { useUrlParams } from '../../../../hooks/useUrlParams'; import { useFetcher } from '../../../../hooks/useFetcher'; import { PageViewsLabel } from '../translations'; -import { BreakdownFilter } from '../BreakdownFilter'; +import { BreakdownFilter } from '../Breakdowns/BreakdownFilter'; import { PageViewsChart } from '../Charts/PageViewsChart'; import { BreakdownItem } from '../../../../../typings/ui_filters'; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts index 2dc6a6554f634..1d792f0b8c1c6 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts @@ -79,15 +79,8 @@ export const OverallLabel = i18n.translate( } ); -export const LoadingLabel = i18n.translate( - 'xpack.apm.filterGroup.loadingMessage', - { - defaultMessage: 'Loading...', - } -); - -export const SearchBreakdownLabel = i18n.translate( - 'xpack.uptime.filterGroup.searchMessage', +export const SelectBreakdownLabel = i18n.translate( + 'xpack.uptime.filterGroup.selectBreakdown', { defaultMessage: 'Search breakdown', } diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_breakdown_filters.ts b/x-pack/plugins/apm/server/lib/rum_client/get_breakdown_filters.ts deleted file mode 100644 index 90e01b693216c..0000000000000 --- a/x-pack/plugins/apm/server/lib/rum_client/get_breakdown_filters.ts +++ /dev/null @@ -1,57 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { getRumOverviewProjection } from '../../../common/projections/rum_overview'; -import { mergeProjection } from '../../../common/projections/util/merge_projection'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../helpers/setup_request'; - -export async function getBreakdownFilters({ - setup, -}: { - setup: Setup & SetupTimeRange & SetupUIFilters; -}) { - const projection = getRumOverviewProjection({ - setup, - }); - - const params = mergeProjection(projection, { - body: { - size: 0, - query: { - bool: projection.body.query.bool, - }, - aggs: { - impressions: { - auto_date_histogram: { - field: '@timestamp', - buckets: 50, - }, - aggs: { - trans_count: { - value_count: { - field: 'transaction.type', - }, - }, - }, - }, - }, - }, - }); - - const { client } = setup; - - const response = await client.search(params); - - const result = response.aggregations?.impressions.buckets ?? []; - return result.map(({ key, trans_count }) => ({ - x: key, - y: trans_count.value, - })); -} diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts b/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts index 7c35d990366ca..43af18999547d 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts @@ -32,23 +32,16 @@ export async function getPageLoadDistribution({ bool: projection.body.query.bool, }, aggs: { - durationMinMax: { + minDuration: { min: { field: 'transaction.duration.us', missing: 0, }, }, - durationPercentiles: { + durPercentiles: { percentiles: { field: 'transaction.duration.us', percents: [50, 75, 90, 95, 99], - script: { - lang: 'painless', - source: "doc['transaction.duration.us'].value / params.timeUnit", - params: { - timeUnit: 1000, - }, - }, }, }, }, @@ -66,31 +59,32 @@ export async function getPageLoadDistribution({ return null; } - const minDuration = (aggregations?.durationMinMax.value ?? 0) / 1000; + const minDuration = aggregations?.minDuration.value ?? 0; const minPerc = minPercentile ? +minPercentile : minDuration; - const maxPercentileQuery = - aggregations?.durationPercentiles.values['99.0'] ?? 100; + const maxPercQuery = aggregations?.durPercentiles.values['99.0'] ?? 10000; - const maxPerc = maxPercentile ? +maxPercentile : maxPercentileQuery; + const maxPerc = maxPercentile ? +maxPercentile : maxPercQuery; const pageDist = await getPercentilesDistribution(setup, minPerc, maxPerc); return { pageLoadDistribution: pageDist, - percentiles: aggregations?.durationPercentiles.values, + percentiles: aggregations?.durPercentiles.values, + minDuration: minPerc, + maxDuration: maxPerc, }; } const getPercentilesDistribution = async ( setup: Setup & SetupTimeRange & SetupUIFilters, - minPercentiles: number, - maxPercentile: number + minDuration: number, + maxDuration: number ) => { - const stepValue = (maxPercentile - minPercentiles) / 50; + const stepValue = (maxDuration - minDuration) / 50; const stepValues = []; for (let i = 1; i < 51; i++) { - stepValues.push((stepValue * i + minPercentiles).toFixed(2)); + stepValues.push((stepValue * i + minDuration).toFixed(2)); } const projection = getRumOverviewProjection({ @@ -109,13 +103,6 @@ const getPercentilesDistribution = async ( field: 'transaction.duration.us', values: stepValues, keyed: false, - script: { - lang: 'painless', - source: "doc['transaction.duration.us'].value / params.timeUnit", - params: { - timeUnit: 1000, - }, - }, }, }, }, @@ -126,14 +113,11 @@ const getPercentilesDistribution = async ( const { aggregations } = await client.search(params); - const pageDist = (aggregations?.loadDistribution.values ?? []) as Array<{ - key: number; - value: number; - }>; + const pageDist = aggregations?.loadDistribution.values ?? []; return pageDist.map(({ key, value }, index: number, arr) => { return { - x: key, + x: Math.round(key / 1000), y: index === 0 ? value : value - arr[index - 1].value, }; }); diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts b/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts index 2b529567cd300..99ff17ba2a044 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts @@ -27,12 +27,11 @@ export async function getPageViewTrends({ const breakdownAggs: AggregationInputMap = {}; if (breakdowns) { const breakdownList: BreakdownItem[] = JSON.parse(breakdowns); - breakdownList.forEach(({ name, type }) => { + breakdownList.forEach(({ name, type, fieldName }) => { breakdownAggs[type + '__' + name] = { - filter: { - term: { - [type]: name, - }, + terms: { + field: fieldName, + size: 9, }, }; }); @@ -50,14 +49,7 @@ export async function getPageViewTrends({ field: '@timestamp', buckets: 50, }, - aggs: { - transCount: { - value_count: { - field: 'transaction.type', - }, - }, - ...breakdownAggs, - }, + aggs: breakdownAggs, }, }, }, @@ -68,15 +60,21 @@ export async function getPageViewTrends({ const response = await client.search(params); const result = response.aggregations?.pageViews.buckets ?? []; + return result.map((bucket) => { - const { key: xVal, transCount } = bucket; + const { key: xVal, doc_count: bCount } = bucket; const res: Record = { x: xVal, - y: transCount.value, + y: bCount, }; - Object.keys(breakdownAggs).forEach((key) => { - // @ts-ignore - res[key] = bucket[key]?.doc_count; + + Object.keys(breakdownAggs).forEach((bKey) => { + const categoryBuckets = (bucket[bKey] as any).buckets; + categoryBuckets.forEach( + ({ key, doc_count: docCount }: { key: string; doc_count: number }) => { + res['category__' + key] = docCount; + } + ); }); return res; diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_pl_dist_breakdown.ts b/x-pack/plugins/apm/server/lib/rum_client/get_pl_dist_breakdown.ts new file mode 100644 index 0000000000000..add0ece78967d --- /dev/null +++ b/x-pack/plugins/apm/server/lib/rum_client/get_pl_dist_breakdown.ts @@ -0,0 +1,96 @@ +/* + * 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 { getRumOverviewProjection } from '../../../common/projections/rum_overview'; +import { mergeProjection } from '../../../common/projections/util/merge_projection'; +import { + Setup, + SetupTimeRange, + SetupUIFilters, +} from '../helpers/setup_request'; +import { + CLIENT_GEO_COUNTRY_ISO_CODE, + USER_AGENT_DEVICE, + USER_AGENT_NAME, + USER_AGENT_OS, +} from '../../../common/elasticsearch_fieldnames'; + +export const getBreakdownField = (breakdown: string) => { + switch (breakdown) { + case 'Location': + return CLIENT_GEO_COUNTRY_ISO_CODE; + case 'Device': + return USER_AGENT_DEVICE; + case 'Browser': + return USER_AGENT_NAME; + case 'OS': + return USER_AGENT_OS; + default: + return USER_AGENT_NAME; + } +}; + +export const getPageLoadDistBreakdown = async ( + setup: Setup & SetupTimeRange & SetupUIFilters, + minDuration: number, + maxDuration: number, + breakdown: string +) => { + const stepValue = (maxDuration - minDuration) / 50; + const stepValues = []; + + for (let i = 1; i < 51; i++) { + stepValues.push((stepValue * i + minDuration).toFixed(2)); + } + + const projection = getRumOverviewProjection({ + setup, + }); + + const params = mergeProjection(projection, { + body: { + size: 0, + query: { + bool: projection.body.query.bool, + }, + aggs: { + breakdowns: { + terms: { + field: getBreakdownField(breakdown), + size: 9, + }, + aggs: { + page_dist: { + percentile_ranks: { + field: 'transaction.duration.us', + values: stepValues, + keyed: false, + }, + }, + }, + }, + }, + }, + }); + + const { client } = setup; + + const { aggregations } = await client.search(params); + + const pageDistBreakdowns = aggregations?.breakdowns.buckets; + + return pageDistBreakdowns?.map(({ key, page_dist: pageDist }) => { + return { + name: String(key), + data: pageDist.values?.map(({ key: pKey, value }, index: number, arr) => { + return { + x: Math.round(pKey / 1000), + y: index === 0 ? value : value - arr[index - 1].value, + }; + }), + }; + }); +}; diff --git a/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts b/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts index 458f448c383d2..7a3d9d94dec8e 100644 --- a/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts +++ b/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts @@ -14,7 +14,6 @@ import { TRANSACTION_URL, USER_AGENT_NAME, USER_AGENT_DEVICE, - CLIENT_GEO, USER_AGENT_OS, CLIENT_GEO_COUNTRY_ISO_CODE, } from '../../../../common/elasticsearch_fieldnames'; diff --git a/x-pack/plugins/apm/server/routes/create_apm_api.ts b/x-pack/plugins/apm/server/routes/create_apm_api.ts index d73fb6ef2d9ec..2fa92cf198c34 100644 --- a/x-pack/plugins/apm/server/routes/create_apm_api.ts +++ b/x-pack/plugins/apm/server/routes/create_apm_api.ts @@ -72,10 +72,10 @@ import { customLinkTransactionRoute, } from './settings/custom_link'; import { - breakdownFiltersRoute, rumClientMetricsRoute, rumPageViewsTrendRoute, rumPageLoadDistributionRoute, + rumPageLoadDistBreakdownRoute, } from './rum_client'; const createApmApi = () => { @@ -161,7 +161,7 @@ const createApmApi = () => { .add(rumOverviewLocalFiltersRoute) .add(rumPageViewsTrendRoute) .add(rumPageLoadDistributionRoute) - .add(breakdownFiltersRoute) + .add(rumPageLoadDistBreakdownRoute) .add(rumClientMetricsRoute); return api; diff --git a/x-pack/plugins/apm/server/routes/rum_client.ts b/x-pack/plugins/apm/server/routes/rum_client.ts index 7116efa2e1817..75651f646a50d 100644 --- a/x-pack/plugins/apm/server/routes/rum_client.ts +++ b/x-pack/plugins/apm/server/routes/rum_client.ts @@ -11,7 +11,7 @@ import { getClientMetrics } from '../lib/rum_client/get_client_metrics'; import { rangeRt, uiFiltersRt } from './default_api_types'; import { getPageViewTrends } from '../lib/rum_client/get_page_view_trends'; import { getPageLoadDistribution } from '../lib/rum_client/get_page_load_distribution'; -import { getBreakdownFilters } from '../lib/rum_client/get_breakdown_filters'; +import { getPageLoadDistBreakdown } from '../lib/rum_client/get_pl_dist_breakdown'; export const percentileRangeRt = t.partial({ minPercentile: t.string, @@ -46,14 +46,29 @@ export const rumPageLoadDistributionRoute = createRoute(() => ({ }, })); -export const breakdownFiltersRoute = createRoute(() => ({ - path: '/api/apm/rum-client/breakdown', +export const rumPageLoadDistBreakdownRoute = createRoute(() => ({ + path: '/api/apm/rum-client/page-load-distribution/breakdown', params: { - query: t.intersection([uiFiltersRt, rangeRt]), + query: t.intersection([ + uiFiltersRt, + rangeRt, + percentileRangeRt, + t.type({ breakdown: t.string }), + ]), }, handler: async ({ context, request }) => { const setup = await setupRequest(context, request); - return getBreakdownFilters({ setup }); + + const { + query: { minPercentile, maxPercentile, breakdown }, + } = context.params; + + return getPageLoadDistBreakdown( + setup, + Number(minPercentile), + Number(maxPercentile), + breakdown + ); }, })); diff --git a/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts b/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts index 6ee26caa4ef7c..a340aa24aebfb 100644 --- a/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts +++ b/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts @@ -35,6 +35,11 @@ type MetricsAggregationOptions = interface MetricsAggregationResponsePart { value: number | null; } +interface DateHistogramBucket { + doc_count: number; + key: number; + key_as_string: string; +} type GetCompositeKeys< TAggregationOptionsMap extends AggregationOptionsMap @@ -204,14 +209,8 @@ interface AggregationResponsePart< }; date_histogram: { buckets: Array< - { - doc_count: number; - key: number; - key_as_string: string; - } & BucketSubAggregationResponse< - TAggregationOptionsMap['aggs'], - TDocument - > + DateHistogramBucket & + BucketSubAggregationResponse >; }; avg: MetricsAggregationResponsePart; @@ -312,20 +311,18 @@ interface AggregationResponsePart< }; auto_date_histogram: { buckets: Array< - { - doc_count: number; - key: number; - key_as_string: string; - } & BucketSubAggregationResponse< - TAggregationOptionsMap['aggs'], - TDocument - > + DateHistogramBucket & + AggregationResponseMap >; interval: string; }; percentile_ranks: { - values: Record | Array<{ key: number; value: number }>; + values: TAggregationOptionsMap extends { + percentile_ranks: { keyed: false }; + } + ? Array<{ key: number; value: number }> + : Record; }; } diff --git a/x-pack/plugins/apm/typings/ui_filters.ts b/x-pack/plugins/apm/typings/ui_filters.ts index 7a05f9ee6e79b..2a727dda7241d 100644 --- a/x-pack/plugins/apm/typings/ui_filters.ts +++ b/x-pack/plugins/apm/typings/ui_filters.ts @@ -16,5 +16,6 @@ export interface BreakdownItem { name: string; count: number; type: string; + fieldName: string; selected?: boolean; } From 986e9a51124dd351a0ed9dfbfd0178bb510ff278 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 25 Jun 2020 18:50:47 +0200 Subject: [PATCH 43/54] upate --- .../components/app/RumDashboard/PageLoadDistribution/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx index 18228323b75fa..a0460f208a648 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx @@ -61,7 +61,7 @@ export const PageLoadDistribution = () => { ); const onPercentileChange = (min: number, max: number) => { - setPercentileRange({ min, max }); + setPercentileRange({ min: min * 1000, max: max * 1000 }); }; const onBreakdownChange = (values: BreakdownItem[]) => { From 37973885ca291b0f413ecf3dfa1b628377159299 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 25 Jun 2020 18:54:25 +0200 Subject: [PATCH 44/54] update --- .../__snapshots__/queries.test.ts.snap | 29 +++++-------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap index 7d8f31aaeca7f..c006d01637483 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap @@ -67,13 +67,7 @@ exports[`rum client dashboard queries fetches page load distribution 1`] = ` Object { "body": Object { "aggs": Object { - "durationMinMax": Object { - "min": Object { - "field": "transaction.duration.us", - "missing": 0, - }, - }, - "durationPercentiles": Object { + "durPercentiles": Object { "percentiles": Object { "field": "transaction.duration.us", "percents": Array [ @@ -83,13 +77,12 @@ Object { 95, 99, ], - "script": Object { - "lang": "painless", - "params": Object { - "timeUnit": 1000, - }, - "source": "doc['transaction.duration.us'].value / params.timeUnit", - }, + }, + }, + "minDuration": Object { + "min": Object { + "field": "transaction.duration.us", + "missing": 0, }, }, }, @@ -139,13 +132,7 @@ Object { "body": Object { "aggs": Object { "pageViews": Object { - "aggs": Object { - "trans_count": Object { - "value_count": Object { - "field": "transaction.type", - }, - }, - }, + "aggs": Object {}, "auto_date_histogram": Object { "buckets": 50, "field": "@timestamp", From 1690d155aad009f034c0ad8ed8d5c63e54776dc7 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 25 Jun 2020 19:24:31 +0200 Subject: [PATCH 45/54] update --- .../apm/e2e/cypress/integration/snapshots.js | 2 +- .../support/step_definitions/rum/page_load_dist.ts | 13 +++---------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js index 757f7203c1eab..4aef5d08f77e1 100644 --- a/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js +++ b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js @@ -18,7 +18,7 @@ module.exports = { "2": "75th", "3": "90th", "4": "95th", - "5": "Pages loaded", + "5": "Overall", "6": "15", "7": "0.07 sec", "8": "0.01 sec" diff --git a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/page_load_dist.ts b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/page_load_dist.ts index f62782252901a..809b22490abd6 100644 --- a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/page_load_dist.ts +++ b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/page_load_dist.ts @@ -18,21 +18,14 @@ Given(`a user click page load breakdown filter`, () => { }); When(`the user selected the breakdown`, () => { - cy.get('[data-cy=filter-breakdown-item_DE]').click(); + cy.get('[data-cy=filter-breakdown-item_Browser]').click(); // click outside popover to close it cy.get('[data-cy=pageLoadDist]').click(); }); Then(`breakdown series should appear in chart`, () => { cy.get('.euiLoadingChart').should('not.be.visible'); - cy.get('div.echLegendItem__label[title=DE] ') + cy.get('div.echLegendItem__label[title=Chrome] ') .invoke('text') - .should('eq', 'DE'); -}); - -Then(`breakdown series should appear in chart`, () => { - cy.get('.euiLoadingChart').should('not.be.visible'); - cy.get('div.echLegendItem__label[title=DE] ') - .invoke('text') - .should('eq', 'DE'); + .should('eq', 'Chrome'); }); From a11f183e61161cdbaf09373c8b6877aeaa34a84c Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 25 Jun 2020 19:38:40 +0200 Subject: [PATCH 46/54] update --- .../Breakdowns/BreakdownGroup.tsx | 42 +++++++++---------- .../app/RumDashboard/translations.ts | 2 +- .../overview/filter_group/filter_popover.tsx | 1 - 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/Breakdowns/BreakdownGroup.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/Breakdowns/BreakdownGroup.tsx index 295b3ca84089a..6bc1b864e93b1 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/Breakdowns/BreakdownGroup.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/Breakdowns/BreakdownGroup.tsx @@ -76,28 +76,26 @@ export const BreakdownGroup = ({ > {SelectBreakdownLabel}
- {items - .filter(({ type }) => type === 'category') - .map(({ name, count, selected, type, fieldName }) => ( - { - setItems((prevItems) => - prevItems.map((tItem) => ({ - ...tItem, - selected: - name === tItem.name && count === tItem.count - ? !tItem.selected - : tItem.selected, - })) - ); - }} - > - {name} - - ))} + {items.map(({ name, count, selected }) => ( + { + setItems((prevItems) => + prevItems.map((tItem) => ({ + ...tItem, + selected: + name === tItem.name && count === tItem.count + ? !tItem.selected + : tItem.selected, + })) + ); + }} + > + {name} + + ))}
diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts index 1d792f0b8c1c6..fc2fb3301fda1 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts @@ -82,6 +82,6 @@ export const OverallLabel = i18n.translate( export const SelectBreakdownLabel = i18n.translate( 'xpack.uptime.filterGroup.selectBreakdown', { - defaultMessage: 'Search breakdown', + defaultMessage: 'Select breakdown', } ); diff --git a/x-pack/plugins/uptime/public/components/overview/filter_group/filter_popover.tsx b/x-pack/plugins/uptime/public/components/overview/filter_group/filter_popover.tsx index dfd46de20814b..064907a633df0 100644 --- a/x-pack/plugins/uptime/public/components/overview/filter_group/filter_popover.tsx +++ b/x-pack/plugins/uptime/public/components/overview/filter_group/filter_popover.tsx @@ -23,7 +23,6 @@ export interface FilterPopoverProps { btnContent?: JSX.Element; forceOpen?: boolean; setForceOpen?: (val: boolean) => void; - size?: 's' | 'l' | 'xs'; } const isItemSelected = (selectedItems: string[], item: string): 'on' | undefined => From 9df90e9ba32a5a91bc475de3161013a2258223b4 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 25 Jun 2020 20:47:39 +0200 Subject: [PATCH 47/54] added types --- .../app/RumDashboard/Charts/PageLoadDistChart.tsx | 9 ++++++++- .../app/RumDashboard/Charts/PageViewsChart.tsx | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx index 6205118dfcf5a..b90bcba1ae2be 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx @@ -36,9 +36,16 @@ import { BreakdownItem } from '../../../../../typings/ui_filters'; import { useUiSetting$ } from '../../../../../../../../src/plugins/kibana_react/public'; import { BreakdownSeries } from '../PageLoadDistribution/BreakdownSeries'; +interface PageLoadData { + pageLoadDistribution: Array<{ x: number; y: number }>; + percentiles: Record | undefined; + minDuration: number; + maxDuration: number; +} + interface Props { onPercentileChange: (min: number, max: number) => void; - data: any; + data?: PageLoadData | null; breakdowns: BreakdownItem[]; percentileRange: PercentileR; loading: boolean; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx index 169f3b688e578..c3528ede569fd 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx @@ -32,7 +32,7 @@ import { ChartWrapper } from '../ChartWrapper'; import { useUiSetting$ } from '../../../../../../../../src/plugins/kibana_react/public'; interface Props { - data: any; + data?: Array>; loading: boolean; } From 059ac73a5b41e351a117d4141edd38bff936f098 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Fri, 26 Jun 2020 15:12:30 +0200 Subject: [PATCH 48/54] Fix PR feedback --- .../cypress/integration/rum_dashboard.feature | 2 +- .../step_definitions/rum/rum_filters.ts | 2 +- .../apm/public/components/app/Home/index.tsx | 4 +- .../Breakdowns/BreakdownFilter.tsx | 22 ++-- .../Breakdowns/BreakdownGroup.tsx | 52 ++++---- .../RumDashboard/Charts/PageLoadDistChart.tsx | 28 ++--- .../RumDashboard/Charts/PageViewsChart.tsx | 30 +++-- .../app/RumDashboard/ClientMetrics/index.tsx | 13 +- .../PageLoadDistribution/BreakdownSeries.tsx | 4 +- .../PageLoadDistribution/index.tsx | 10 +- .../PageLoadDistribution/use_breakdowns.ts | 4 +- .../app/RumDashboard/PageViewsTrend/index.tsx | 4 +- .../app/RumDashboard/RumDashboard.tsx | 6 +- .../app/RumDashboard/translations.ts | 113 +++++++----------- .../lib/rum_client/get_page_view_trends.ts | 9 +- .../lib/rum_client/get_pl_dist_breakdown.ts | 3 +- .../apm/server/routes/create_apm_api.ts | 1 - 17 files changed, 142 insertions(+), 165 deletions(-) diff --git a/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature b/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature index dd1856e87b06d..d7423b52ac05b 100644 --- a/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature +++ b/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature @@ -20,4 +20,4 @@ Feature: RUM Dashboard Given a user click the filter When the user select the filter And user applies the selected filter - Then it should filters the client metrics + Then it filters the client metrics diff --git a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/rum_filters.ts b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/rum_filters.ts index 445eaf3c752b7..9a7456c8bcc29 100644 --- a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/rum_filters.ts +++ b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/rum_filters.ts @@ -24,7 +24,7 @@ Then(`user applies the selected filter`, () => { cy.get('[data-cy=applyFilter]').click(); }); -Then(`it should filters the client metrics`, () => { +Then(`it filters the client metrics`, () => { const clientMetrics = '[data-cy=client-metrics] .euiStat__title'; // wait for all loading to finish diff --git a/x-pack/plugins/apm/public/components/app/Home/index.tsx b/x-pack/plugins/apm/public/components/app/Home/index.tsx index c325a72375359..69699b72a96df 100644 --- a/x-pack/plugins/apm/public/components/app/Home/index.tsx +++ b/x-pack/plugins/apm/public/components/app/Home/index.tsx @@ -27,7 +27,7 @@ import { ServiceOverview } from '../ServiceOverview'; import { TraceOverview } from '../TraceOverview'; import { RumOverview } from '../RumDashboard'; import { RumOverviewLink } from '../../shared/Links/apm/RumOverviewLink'; -import { EndUserExperienceLabel } from '../RumDashboard/translations'; +import { I18LABELS } from '../RumDashboard/translations'; function getHomeTabs({ serviceMapEnabled = true, @@ -111,7 +111,7 @@ export function Home({ tab }: Props) {

{selectedTab.name === 'rum-overview' - ? EndUserExperienceLabel + ? I18LABELS.endUserExperience : 'APM'}

diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/Breakdowns/BreakdownFilter.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/Breakdowns/BreakdownFilter.tsx index 986543ee7bf93..332cf40a465f9 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/Breakdowns/BreakdownFilter.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/Breakdowns/BreakdownFilter.tsx @@ -25,40 +25,44 @@ export const BreakdownFilter = ({ selectedBreakdowns, onBreakdownChange, }: Props) => { - const onChange = (selValues: BreakdownItem[]) => { - onBreakdownChange(selValues); - }; - const categories: BreakdownItem[] = [ { name: 'Browser', type: 'category', count: 0, - selected: !!selectedBreakdowns.find(({ name }) => name === 'Browser'), + selected: selectedBreakdowns.some(({ name }) => name === 'Browser'), fieldName: USER_AGENT_NAME, }, { name: 'OS', type: 'category', count: 0, - selected: !!selectedBreakdowns.find(({ name }) => name === 'OS'), + selected: selectedBreakdowns.some(({ name }) => name === 'OS'), fieldName: USER_AGENT_OS, }, { name: 'Device', type: 'category', count: 0, - selected: !!selectedBreakdowns.find(({ name }) => name === 'Device'), + selected: selectedBreakdowns.some(({ name }) => name === 'Device'), fieldName: USER_AGENT_DEVICE, }, { name: 'Location', type: 'category', count: 0, - selected: !!selectedBreakdowns.find(({ name }) => name === 'Location'), + selected: selectedBreakdowns.some(({ name }) => name === 'Location'), fieldName: CLIENT_GEO_COUNTRY_ISO_CODE, }, ]; - return ; + return ( + { + onBreakdownChange(selValues); + }} + /> + ); }; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/Breakdowns/BreakdownGroup.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/Breakdowns/BreakdownGroup.tsx index 6bc1b864e93b1..007cdab0d2078 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/Breakdowns/BreakdownGroup.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/Breakdowns/BreakdownGroup.tsx @@ -4,12 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -/* - * 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 { EuiPopover, EuiFilterButton, @@ -17,9 +11,9 @@ import { EuiPopoverTitle, EuiFilterSelectItem, } from '@elastic/eui'; -import React, { useEffect, useState } from 'react'; +import React, { MouseEvent, useCallback, useEffect, useState } from 'react'; import { BreakdownItem } from '../../../../../typings/ui_filters'; -import { SelectBreakdownLabel } from '../translations'; +import { I18LABELS } from '../translations'; export interface BreakdownGroupProps { id: string; @@ -32,17 +26,29 @@ export const BreakdownGroup = ({ id, disabled, onChange, - items: allItems, + items, }: BreakdownGroupProps) => { const [isOpen, setIsOpen] = useState(false); - const [items, setItems] = useState(allItems); + const [activeItems, setActiveItems] = useState(items); useEffect(() => { - setItems(allItems); - }, [allItems]); + setActiveItems(items); + }, [items]); - const getSelItems = () => items.filter((tItem) => !!tItem.selected); + const getSelItems = () => activeItems.filter((item) => item.selected); + + const onFilterItemClick = useCallback( + (name: string) => (_event: MouseEvent) => { + setActiveItems((prevItems) => + prevItems.map((item) => ({ + ...item, + selected: name === item.name ? !item.selected : item.selected, + })) + ); + }, + [] + ); return ( @@ -51,7 +57,7 @@ export const BreakdownGroup = ({ 0} - numFilters={items.length} + numFilters={activeItems.length} numActiveFilters={getSelItems().length} hasActiveFilters={getSelItems().length !== 0} iconType="arrowDown" @@ -60,7 +66,7 @@ export const BreakdownGroup = ({ }} size="s" > - Breakdown + {I18LABELS.breakdown} } closePopover={() => { @@ -74,24 +80,14 @@ export const BreakdownGroup = ({ withTitle zIndex={10000} > - {SelectBreakdownLabel} + {I18LABELS.selectBreakdown}
- {items.map(({ name, count, selected }) => ( + {activeItems.map(({ name, count, selected }) => ( { - setItems((prevItems) => - prevItems.map((tItem) => ({ - ...tItem, - selected: - name === tItem.name && count === tItem.count - ? !tItem.selected - : tItem.selected, - })) - ); - }} + onClick={onFilterItemClick(name)} > {name} diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx index b90bcba1ae2be..af8a055c10294 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { FC, useState } from 'react'; +import React, { useState } from 'react'; import { Axis, BrushEndListener, @@ -25,13 +25,9 @@ import { import { Position } from '@elastic/charts/dist/utils/commons'; import styled from 'styled-components'; import { PercentileAnnotations } from '../PageLoadDistribution/PercentileAnnotations'; -import { - OverallLabel, - PageLoadTimeLabel, - PercPageLoadedLabel, -} from '../translations'; +import { I18LABELS } from '../translations'; import { ChartWrapper } from '../ChartWrapper'; -import { PercentileR } from '../PageLoadDistribution'; +import { PercentileRange } from '../PageLoadDistribution'; import { BreakdownItem } from '../../../../../typings/ui_filters'; import { useUiSetting$ } from '../../../../../../../../src/plugins/kibana_react/public'; import { BreakdownSeries } from '../PageLoadDistribution/BreakdownSeries'; @@ -47,7 +43,7 @@ interface Props { onPercentileChange: (min: number, max: number) => void; data?: PageLoadData | null; breakdowns: BreakdownItem[]; - percentileRange: PercentileR; + percentileRange: PercentileRange; loading: boolean; } @@ -57,13 +53,13 @@ const PageLoadChart = styled(Chart)` } `; -export const PageLoadDistChart: FC = ({ +export function PageLoadDistChart({ onPercentileChange, data, breakdowns, loading, percentileRange, -}) => { +}: Props) { const [breakdownLoading, setBreakdownLoading] = useState(false); const onBrushEnd: BrushEndListener = ({ x }) => { if (!x) { @@ -76,7 +72,9 @@ export const PageLoadDistChart: FC = ({ const headerFormatter: TooltipValueFormatter = (tooltip: TooltipValue) => { return (
-

{tooltip.value} seconds

+

+ {tooltip.value} {I18LABELS.seconds} +

); }; @@ -105,18 +103,18 @@ export const PageLoadDistChart: FC = ({ Number(d).toFixed(1) + ' %'} /> = ({ )} ); -}; +} diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx index c3528ede569fd..1d4f37ceb2df9 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { FC } from 'react'; +import React from 'react'; import { Axis, BarSeries, @@ -24,7 +24,7 @@ import { } from '@elastic/eui/dist/eui_charts_theme'; import moment from 'moment'; import { Position } from '@elastic/charts/dist/utils/commons'; -import { DateTimeLabel, OverallLabel, PageViewsLabel } from '../translations'; +import { I18LABELS } from '../translations'; import { formatBigValue } from '../ClientMetrics'; import { history } from '../../../../utils/history'; import { fromQuery, toQuery } from '../../../shared/Links/url_helpers'; @@ -36,7 +36,7 @@ interface Props { loading: boolean; } -export const PageViewsChart: FC = ({ data, loading }: Props) => { +export function PageViewsChart({ data, loading }: Props) { const formatter = timeFormatter(niceTimeFormatByDay(2)); const onBrushEnd: BrushEndListener = ({ x }) => { @@ -58,18 +58,22 @@ export const PageViewsChart: FC = ({ data, loading }: Props) => { }); }; - let breakdownAccessors: string[] = []; + let breakdownAccessors: Set = new Set(); if (data && data.length > 0) { - const allKeys = Object.keys(data[0]); - breakdownAccessors = allKeys.filter((key) => key !== 'x'); + data.forEach((item) => { + breakdownAccessors = new Set([ + ...Array.from(breakdownAccessors), + ...Object.keys(item).filter((key) => key !== 'x'), + ]); + }); } const customSeriesNaming: SeriesNameFn = ({ yAccessor }) => { if (yAccessor === 'y') { - return OverallLabel; + return I18LABELS.overall; } - return yAccessor.toString().split?.('__')[1]; + return yAccessor; }; const [darkMode] = useUiSetting$('theme:darkMode'); @@ -91,21 +95,21 @@ export const PageViewsChart: FC = ({ data, loading }: Props) => { formatBigValue(Number(d))} /> @@ -113,4 +117,4 @@ export const PageViewsChart: FC = ({ data, loading }: Props) => { )} ); -}; +} diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx index 50442b6e1ddee..8b6b39049a40a 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx @@ -3,13 +3,12 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -// @flow import * as React from 'react'; import styled from 'styled-components'; import { EuiFlexGroup, EuiFlexItem, EuiStat } from '@elastic/eui'; import { useFetcher } from '../../../../hooks/useFetcher'; import { useUrlParams } from '../../../../hooks/useUrlParams'; -import { BackEndLabel, FrontEndLabel, PageViewsLabel } from '../translations'; +import { I18LABELS } from '../translations'; export const formatBigValue = (val?: number | null): string => { if (val && val >= 1000) { @@ -28,7 +27,7 @@ const ClFlexGroup = styled(EuiFlexGroup)` } `; -export const ClientMetrics = () => { +export function ClientMetrics() { const { urlParams, uiFilters } = useUrlParams(); const { start, end } = urlParams; @@ -55,7 +54,7 @@ export const ClientMetrics = () => { @@ -63,7 +62,7 @@ export const ClientMetrics = () => { @@ -71,10 +70,10 @@ export const ClientMetrics = () => { ); -}; +} diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/BreakdownSeries.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/BreakdownSeries.tsx index e84302c0ae68f..7f8837f9a3a89 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/BreakdownSeries.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/BreakdownSeries.tsx @@ -6,13 +6,13 @@ import React, { FC, useEffect } from 'react'; import { CurveType, LineSeries, ScaleType } from '@elastic/charts'; -import { PercentileR } from './index'; +import { PercentileRange } from './index'; import { useBreakdowns } from './use_breakdowns'; interface Props { field: string; value: string; - percentileRange: PercentileR; + percentileRange: PercentileRange; onLoadingChange: (loading: boolean) => void; } diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx index a0460f208a648..5ed307c606143 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx @@ -14,12 +14,12 @@ import { } from '@elastic/eui'; import { useUrlParams } from '../../../../hooks/useUrlParams'; import { useFetcher } from '../../../../hooks/useFetcher'; -import { PageLoadDistLabel, ResetZoomLabel } from '../translations'; +import { I18LABELS } from '../translations'; import { BreakdownFilter } from '../Breakdowns/BreakdownFilter'; import { PageLoadDistChart } from '../Charts/PageLoadDistChart'; import { BreakdownItem } from '../../../../../typings/ui_filters'; -export interface PercentileR { +export interface PercentileRange { min?: number | null; max?: number | null; } @@ -29,7 +29,7 @@ export const PageLoadDistribution = () => { const { start, end } = urlParams; - const [percentileRange, setPercentileRange] = useState({ + const [percentileRange, setPercentileRange] = useState({ min: null, max: null, }); @@ -73,7 +73,7 @@ export const PageLoadDistribution = () => { -

{PageLoadDistLabel}

+

{I18LABELS.pageLoadDistribution}

@@ -87,7 +87,7 @@ export const PageLoadDistribution = () => { percentileRange.min === null && percentileRange.max === null } > - {ResetZoomLabel} + {I18LABELS.resetZoom} diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/use_breakdowns.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/use_breakdowns.ts index 570b222177ad6..41fe491637dbd 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/use_breakdowns.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/use_breakdowns.ts @@ -6,10 +6,10 @@ import { useFetcher } from '../../../../hooks/useFetcher'; import { useUrlParams } from '../../../../hooks/useUrlParams'; -import { PercentileR } from './index'; +import { PercentileRange } from './index'; interface Props { - percentileRange?: PercentileR; + percentileRange?: PercentileRange; field: string; value: string; } diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx index b371d9d31ac36..34347f3f95947 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx @@ -8,7 +8,7 @@ import React, { useState } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiTitle } from '@elastic/eui'; import { useUrlParams } from '../../../../hooks/useUrlParams'; import { useFetcher } from '../../../../hooks/useFetcher'; -import { PageViewsLabel } from '../translations'; +import { I18LABELS } from '../translations'; import { BreakdownFilter } from '../Breakdowns/BreakdownFilter'; import { PageViewsChart } from '../Charts/PageViewsChart'; import { BreakdownItem } from '../../../../../typings/ui_filters'; @@ -52,7 +52,7 @@ export const PageViewsTrend = () => { -

{PageViewsLabel}

+

{I18LABELS.pageViews}

diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx index e3fa7374afb38..cd50f3b575113 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx @@ -15,7 +15,7 @@ import React from 'react'; import { ClientMetrics } from './ClientMetrics'; import { PageViewsTrend } from './PageViewsTrend'; import { PageLoadDistribution } from './PageLoadDistribution'; -import { getWhatIsGoingOnLabel } from './translations'; +import { I18LABELS } from './translations'; import { useUrlParams } from '../../../hooks/useUrlParams'; export function RumDashboard() { @@ -32,7 +32,7 @@ export function RumDashboard() { return ( <> -

{getWhatIsGoingOnLabel(environmentLabel)}

+

{I18LABELS.getWhatIsGoingOn(environmentLabel)}

@@ -41,7 +41,7 @@ export function RumDashboard() { -

Page load times

+

{I18LABELS.pageLoadTimes}

diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts index fc2fb3301fda1..e253993bb3f26 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts @@ -6,82 +6,55 @@ import { i18n } from '@kbn/i18n'; -export const EndUserExperienceLabel = i18n.translate( - 'xpack.apm.rum.dashboard.title', - { +export const I18LABELS = { + endUserExperience: i18n.translate('xpack.apm.rum.dashboard.title', { defaultMessage: 'End User Experience', - } -); - -export const getWhatIsGoingOnLabel = (environmentVal: string) => - i18n.translate('xpack.apm.rum.dashboard.environment.title', { - defaultMessage: `What's going on in {environmentVal}?`, - values: { environmentVal }, - }); - -export const BackEndLabel = i18n.translate('xpack.apm.rum.dashboard.backend', { - defaultMessage: 'Backend', -}); - -export const FrontEndLabel = i18n.translate( - 'xpack.apm.rum.dashboard.frontend', - { + }), + getWhatIsGoingOn: (environmentVal: string) => + i18n.translate('xpack.apm.rum.dashboard.environment.title', { + defaultMessage: `What's going on in {environmentVal}?`, + values: { environmentVal }, + }), + backEnd: i18n.translate('xpack.apm.rum.dashboard.backend', { + defaultMessage: 'Backend', + }), + frontEnd: i18n.translate('xpack.apm.rum.dashboard.frontend', { defaultMessage: 'Frontend', - } -); - -export const PageViewsLabel = i18n.translate( - 'xpack.apm.rum.dashboard.pageViews', - { + }), + pageViews: i18n.translate('xpack.apm.rum.dashboard.pageViews', { defaultMessage: 'Page views', - } -); - -export const DateTimeLabel = i18n.translate( - 'xpack.apm.rum.dashboard.dateTime.label', - { + }), + dateTime: i18n.translate('xpack.apm.rum.dashboard.dateTime.label', { defaultMessage: 'Date / Time', - } -); - -export const PercPageLoadedLabel = i18n.translate( - 'xpack.apm.rum.dashboard.pagesLoaded.label', - { + }), + percPageLoaded: i18n.translate('xpack.apm.rum.dashboard.pagesLoaded.label', { defaultMessage: 'Pages loaded', - } -); - -export const PageLoadTimeLabel = i18n.translate( - 'xpack.apm.rum.dashboard.pageLoadTime.label', - { + }), + pageLoadTime: i18n.translate('xpack.apm.rum.dashboard.pageLoadTime.label', { defaultMessage: 'Page load time (seconds)', - } -); - -export const PageLoadDistLabel = i18n.translate( - 'xpack.apm.rum.dashboard.pageLoadDistribution.label', - { - defaultMessage: 'Page load distribution', - } -); - -export const ResetZoomLabel = i18n.translate( - 'xpack.apm.rum.dashboard.resetZoom.label', - { + }), + pageLoadTimes: i18n.translate('xpack.apm.rum.dashboard.pageLoadTimes.label', { + defaultMessage: 'Page load times', + }), + pageLoadDistribution: i18n.translate( + 'xpack.apm.rum.dashboard.pageLoadDistribution.label', + { + defaultMessage: 'Page load distribution', + } + ), + resetZoom: i18n.translate('xpack.apm.rum.dashboard.resetZoom.label', { defaultMessage: 'Reset zoom', - } -); - -export const OverallLabel = i18n.translate( - 'xpack.apm.rum.dashboard.overall.label', - { + }), + overall: i18n.translate('xpack.apm.rum.dashboard.overall.label', { defaultMessage: 'Overall', - } -); - -export const SelectBreakdownLabel = i18n.translate( - 'xpack.uptime.filterGroup.selectBreakdown', - { + }), + selectBreakdown: i18n.translate('xpack.rum.filterGroup.selectBreakdown', { defaultMessage: 'Select breakdown', - } -); + }), + breakdown: i18n.translate('xpack.rum.filterGroup.breakdown', { + defaultMessage: 'Breakdown', + }), + seconds: i18n.translate('xpack.rum.filterGroup.seconds', { + defaultMessage: 'seconds', + }), +}; diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts b/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts index 99ff17ba2a044..30b2677d3c217 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts @@ -28,10 +28,11 @@ export async function getPageViewTrends({ if (breakdowns) { const breakdownList: BreakdownItem[] = JSON.parse(breakdowns); breakdownList.forEach(({ name, type, fieldName }) => { - breakdownAggs[type + '__' + name] = { + breakdownAggs[name] = { terms: { field: fieldName, size: 9, + missing: 'Other', }, }; }); @@ -72,7 +73,11 @@ export async function getPageViewTrends({ const categoryBuckets = (bucket[bKey] as any).buckets; categoryBuckets.forEach( ({ key, doc_count: docCount }: { key: string; doc_count: number }) => { - res['category__' + key] = docCount; + if (key === 'Other') { + res[key + `(${bKey})`] = docCount; + } else { + res[key] = docCount; + } } ); }); diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_pl_dist_breakdown.ts b/x-pack/plugins/apm/server/lib/rum_client/get_pl_dist_breakdown.ts index add0ece78967d..5ae6bd1540f7c 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_pl_dist_breakdown.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_pl_dist_breakdown.ts @@ -24,10 +24,9 @@ export const getBreakdownField = (breakdown: string) => { return CLIENT_GEO_COUNTRY_ISO_CODE; case 'Device': return USER_AGENT_DEVICE; - case 'Browser': - return USER_AGENT_NAME; case 'OS': return USER_AGENT_OS; + case 'Browser': default: return USER_AGENT_NAME; } diff --git a/x-pack/plugins/apm/server/routes/create_apm_api.ts b/x-pack/plugins/apm/server/routes/create_apm_api.ts index f6de34a18724e..ed1c045616a27 100644 --- a/x-pack/plugins/apm/server/routes/create_apm_api.ts +++ b/x-pack/plugins/apm/server/routes/create_apm_api.ts @@ -167,7 +167,6 @@ const createApmApi = () => { .add(rumPageLoadDistributionRoute) .add(rumPageLoadDistBreakdownRoute) .add(rumClientMetricsRoute) - .add(rumClientMetricsRoute) // Observability dashboard .add(observabilityDashboardHasDataRoute) From 2d686b03285c79d5f3a7ca7b79254c7bb7dfa9a0 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Fri, 26 Jun 2020 15:59:09 +0200 Subject: [PATCH 49/54] PR feedbck --- .../RumDashboard/Charts/PageLoadDistChart.tsx | 3 ++- .../app/RumDashboard/Charts/PageViewsChart.tsx | 4 ++-- .../app/RumDashboard/ClientMetrics/index.tsx | 18 +++++++----------- .../PageLoadDistribution/index.tsx | 6 +----- 4 files changed, 12 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx index af8a055c10294..e17a8046b5c6a 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageLoadDistChart.tsx @@ -5,6 +5,7 @@ */ import React, { useState } from 'react'; +import numeral from '@elastic/numeral'; import { Axis, BrushEndListener, @@ -110,7 +111,7 @@ export function PageLoadDistChart({ id="left" title={I18LABELS.percPageLoaded} position={Position.Left} - tickFormat={(d) => Number(d).toFixed(1) + ' %'} + tickFormat={(d) => numeral(d).format('0.0') + '%'} /> formatBigValue(Number(d))} + tickFormat={(d) => numeral(d).format('0.0 a')} /> { - if (val && val >= 1000) { - const result = val / 1000; - - return Math.round(result) + 'k'; - } - return val + ''; -}; - const ClFlexGroup = styled(EuiFlexGroup)` flex-direction: row; @media only screen and (max-width: 768px) { @@ -69,7 +61,11 @@ export function ClientMetrics() { + <> {numeral(data?.pageViews?.value).format('0 a') ?? '-'} + + } description={I18LABELS.pageViews} isLoading={status !== 'success'} /> diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx index 5ed307c606143..c6b34c8b76698 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx @@ -64,10 +64,6 @@ export const PageLoadDistribution = () => { setPercentileRange({ min: min * 1000, max: max * 1000 }); }; - const onBreakdownChange = (values: BreakdownItem[]) => { - setBreakdowns(values); - }; - return (
@@ -94,7 +90,7 @@ export const PageLoadDistribution = () => { From e45f12fa8bf53d537e9a17bd3cc9e63acf87a5ad Mon Sep 17 00:00:00 2001 From: Shahzad Date: Fri, 26 Jun 2020 16:15:59 +0200 Subject: [PATCH 50/54] update i18c --- x-pack/plugins/apm/e2e/cypress/integration/snapshots.js | 4 ++-- .../components/app/RumDashboard/ClientMetrics/index.tsx | 2 +- .../apm/public/components/app/RumDashboard/translations.ts | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js index 4aef5d08f77e1..c83c73b8965f6 100644 --- a/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js +++ b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js @@ -9,7 +9,7 @@ module.exports = { }, "RUM Dashboard": { "Client metrics": { - "1": "62", + "1": "62 ", "2": "0.07 sec", "3": "0.01 sec" }, @@ -19,7 +19,7 @@ module.exports = { "3": "90th", "4": "95th", "5": "Overall", - "6": "15", + "6": "15 ", "7": "0.07 sec", "8": "0.01 sec" } diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx index 331e6e6bb6c23..776f74a169966 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx @@ -63,7 +63,7 @@ export function ClientMetrics() { titleSize="s" title={ - <> {numeral(data?.pageViews?.value).format('0 a') ?? '-'} + <>{numeral(data?.pageViews?.value).format('0 a') ?? '-'} } description={I18LABELS.pageViews} diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts index e253993bb3f26..4da7b59ec7fa5 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts @@ -48,13 +48,13 @@ export const I18LABELS = { overall: i18n.translate('xpack.apm.rum.dashboard.overall.label', { defaultMessage: 'Overall', }), - selectBreakdown: i18n.translate('xpack.rum.filterGroup.selectBreakdown', { + selectBreakdown: i18n.translate('xpack.apm.rum.filterGroup.selectBreakdown', { defaultMessage: 'Select breakdown', }), - breakdown: i18n.translate('xpack.rum.filterGroup.breakdown', { + breakdown: i18n.translate('xpack.apm.rum.filterGroup.breakdown', { defaultMessage: 'Breakdown', }), - seconds: i18n.translate('xpack.rum.filterGroup.seconds', { + seconds: i18n.translate('xpack.apm.rum.filterGroup.seconds', { defaultMessage: 'seconds', }), }; From f12173b5f495b559e5364cb6a2c677d4b5395f1c Mon Sep 17 00:00:00 2001 From: Shahzad Date: Fri, 26 Jun 2020 18:04:04 +0200 Subject: [PATCH 51/54] update scenerios --- .../cypress/integration/rum_dashboard.feature | 28 ++++++++++++++----- .../apm/e2e/cypress/integration/snapshots.js | 16 +++++++---- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature b/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature index d7423b52ac05b..cfcf05c496aab 100644 --- a/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature +++ b/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature @@ -6,18 +6,32 @@ Feature: RUM Dashboard Then should redirect to rum dashboard And should have correct client metrics - Scenario: Page load distribution + Scenario: Rum page filters + Given a user click the filter + When the user select the filter + And user applies the selected filter + Then it filters the client metrics + + Scenario: Page load distribution percentiles Given a user browses the APM UI application for RUM Data When the user inspects the real user monitoring tab Then should redirect to rum dashboard And should display percentile for page load chart - And should display tooltip on hover - And should display chart legend + + Scenario: Page load distribution chart tooltip + Given a user browses the APM UI application for RUM Data + When the user inspects the real user monitoring tab + Then should redirect to rum dashboard + And should display tooltip on hover + + Scenario: Page load distribution chart legends + Given a user browses the APM UI application for RUM Data + When the user inspects the real user monitoring tab + Then should redirect to rum dashboard + And should display chart legend + + Scenario: Breakdown filter Given a user click page load breakdown filter When the user selected the breakdown Then breakdown series should appear in chart - Given a user click the filter - When the user select the filter - And user applies the selected filter - Then it filters the client metrics diff --git a/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js index c83c73b8965f6..9b1c3a1bfdc4c 100644 --- a/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js +++ b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js @@ -13,15 +13,19 @@ module.exports = { "2": "0.07 sec", "3": "0.01 sec" }, - "Page load distribution": { + "Page load distribution percentiles": { "1": "50th", "2": "75th", "3": "90th", - "4": "95th", - "5": "Overall", - "6": "15 ", - "7": "0.07 sec", - "8": "0.01 sec" + "4": "95th" + }, + "Rum page filters": { + "1": "15 ", + "2": "0.07 sec", + "3": "0.01 sec" + }, + "Page load distribution chart legends": { + "1": "Overall" } } } From b1573bdf828c32e30ca537588b59325f97891d2c Mon Sep 17 00:00:00 2001 From: Shahzad Date: Fri, 26 Jun 2020 18:09:26 +0200 Subject: [PATCH 52/54] remove unnecessary changes --- .../RumDashboard/PageLoadDistribution/BreakdownSeries.tsx | 6 +++--- .../app/RumDashboard/PageLoadDistribution/use_breakdowns.ts | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/BreakdownSeries.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/BreakdownSeries.tsx index 7f8837f9a3a89..0c47ad24128ef 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/BreakdownSeries.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/BreakdownSeries.tsx @@ -22,15 +22,15 @@ export const BreakdownSeries: FC = ({ percentileRange, onLoadingChange, }) => { - const { data, loading } = useBreakdowns({ + const { data, status } = useBreakdowns({ field, value, percentileRange, }); useEffect(() => { - onLoadingChange(loading); - }, [loading, onLoadingChange]); + onLoadingChange(status !== 'success'); + }, [status, onLoadingChange]); return ( <> diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/use_breakdowns.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/use_breakdowns.ts index 41fe491637dbd..814cf977c9569 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/use_breakdowns.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/use_breakdowns.ts @@ -21,7 +21,7 @@ export const useBreakdowns = ({ percentileRange, field, value }: Props) => { const { min: minP, max: maxP } = percentileRange ?? {}; - const { data, status } = useFetcher( + return useFetcher( (callApmApi) => { if (start && end && field && value) { return callApmApi({ @@ -45,5 +45,4 @@ export const useBreakdowns = ({ percentileRange, field, value }: Props) => { }, [end, start, uiFilters, field, value, minP, maxP] ); - return { data, loading: status !== 'success' }; }; From 12937e167de6b5acce404aed029ad3406e25078a Mon Sep 17 00:00:00 2001 From: Shahzad Date: Mon, 29 Jun 2020 11:06:01 +0200 Subject: [PATCH 53/54] update bdd spec --- .../apm/e2e/cypress/integration/rum_dashboard.feature | 5 ++--- .../e2e/cypress/support/step_definitions/rum/rum_filters.ts | 6 ++---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature b/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature index cfcf05c496aab..8baa17f9e1a84 100644 --- a/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature +++ b/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature @@ -7,9 +7,8 @@ Feature: RUM Dashboard And should have correct client metrics Scenario: Rum page filters - Given a user click the filter - When the user select the filter - And user applies the selected filter + Given the user filters by os + When user applies the selected filter Then it filters the client metrics Scenario: Page load distribution percentiles diff --git a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/rum_filters.ts b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/rum_filters.ts index 9a7456c8bcc29..bc82057091925 100644 --- a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/rum_filters.ts +++ b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/rum_filters.ts @@ -9,18 +9,16 @@ import { Given, When, Then } from 'cypress-cucumber-preprocessor/steps'; /** The default time in ms to wait for a Cypress command to complete */ export const DEFAULT_TIMEOUT = 60 * 1000; -Given(`a user click the filter`, () => { +Given(`the user filters by os`, () => { // wait for all loading to finish cy.get('kbnLoadingIndicator').should('not.be.visible'); cy.get('.euiStat__title-isLoading').should('not.be.visible'); cy.get('#local-filter-os').click(); -}); -When(`the user select the filter`, () => { cy.get('button.euiSelectableListItem[title="Mac OS X"]').click(); }); -Then(`user applies the selected filter`, () => { +When(`user applies the selected filter`, () => { cy.get('[data-cy=applyFilter]').click(); }); From fe89c69ebf3330fd1fe2da243eba776552a25efc Mon Sep 17 00:00:00 2001 From: Shahzad Date: Mon, 29 Jun 2020 18:37:21 +0200 Subject: [PATCH 54/54] update scenerios --- .../cypress/integration/rum_dashboard.feature | 9 ++++++--- .../apm/e2e/cypress/integration/snapshots.js | 15 +++++++++----- .../step_definitions/rum/rum_filters.ts | 20 +++++++++---------- .../shared/LocalUIFilters/index.tsx | 1 + 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature b/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature index 8baa17f9e1a84..bc807d596a272 100644 --- a/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature +++ b/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature @@ -6,10 +6,13 @@ Feature: RUM Dashboard Then should redirect to rum dashboard And should have correct client metrics - Scenario: Rum page filters - Given the user filters by os - When user applies the selected filter + Scenario Outline: Rum page filters + When the user filters by "" Then it filters the client metrics + Examples: + | filterName | + | os | + | location | Scenario: Page load distribution percentiles Given a user browses the APM UI application for RUM Data diff --git a/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js index 9b1c3a1bfdc4c..acccd86f3e4d7 100644 --- a/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js +++ b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js @@ -13,17 +13,22 @@ module.exports = { "2": "0.07 sec", "3": "0.01 sec" }, + "Rum page filters (example #1)": { + "1": "15 ", + "2": "0.07 sec", + "3": "0.01 sec" + }, + "Rum page filters (example #2)": { + "1": "35 ", + "2": "0.07 sec", + "3": "0.01 sec" + }, "Page load distribution percentiles": { "1": "50th", "2": "75th", "3": "90th", "4": "95th" }, - "Rum page filters": { - "1": "15 ", - "2": "0.07 sec", - "3": "0.01 sec" - }, "Page load distribution chart legends": { "1": "Overall" } diff --git a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/rum_filters.ts b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/rum_filters.ts index bc82057091925..439003351aedb 100644 --- a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/rum_filters.ts +++ b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum/rum_filters.ts @@ -4,21 +4,19 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Given, When, Then } from 'cypress-cucumber-preprocessor/steps'; +import { When, Then } from 'cypress-cucumber-preprocessor/steps'; -/** The default time in ms to wait for a Cypress command to complete */ -export const DEFAULT_TIMEOUT = 60 * 1000; - -Given(`the user filters by os`, () => { +When(/^the user filters by "([^"]*)"$/, (filterName) => { // wait for all loading to finish cy.get('kbnLoadingIndicator').should('not.be.visible'); cy.get('.euiStat__title-isLoading').should('not.be.visible'); - cy.get('#local-filter-os').click(); - - cy.get('button.euiSelectableListItem[title="Mac OS X"]').click(); -}); + cy.get(`#local-filter-${filterName}`).click(); -When(`user applies the selected filter`, () => { + if (filterName === 'os') { + cy.get('button.euiSelectableListItem[title="Mac OS X"]').click(); + } else { + cy.get('button.euiSelectableListItem[title="DE"]').click(); + } cy.get('[data-cy=applyFilter]').click(); }); @@ -34,4 +32,6 @@ Then(`it filters the client metrics`, () => { cy.get(clientMetrics).eq(1).invoke('text').snapshot(); cy.get(clientMetrics).eq(0).invoke('text').snapshot(); + + cy.get('[data-cy=clearFilters]').click(); }); diff --git a/x-pack/plugins/apm/public/components/shared/LocalUIFilters/index.tsx b/x-pack/plugins/apm/public/components/shared/LocalUIFilters/index.tsx index 4aae82518ab3c..020b7481c68ea 100644 --- a/x-pack/plugins/apm/public/components/shared/LocalUIFilters/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/LocalUIFilters/index.tsx @@ -80,6 +80,7 @@ const LocalUIFilters = ({ iconType="cross" flush="left" onClick={clearValues} + data-cy="clearFilters" > {i18n.translate('xpack.apm.clearFilters', { defaultMessage: 'Clear filters',