From f9c20a1702683ebe8e6affa15ab540cd2f48517e Mon Sep 17 00:00:00 2001 From: Shahzad Date: Wed, 3 Jun 2020 15:57:50 +0200 Subject: [PATCH 01/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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 e72de7bfdc97f8e3d6ae1082079a39e3e9c42360 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Mon, 15 Jun 2020 10:21:50 +0200 Subject: [PATCH 19/32] 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 20/32] 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 21/32] 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 22/32] 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 23/32] 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 24/32] 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 25/32] 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 26/32] 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 7056e40815219177c3c3e79188045b3c904cd06f Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 18 Jun 2020 10:57:37 +0200 Subject: [PATCH 27/32] 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 28/32] 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 29/32] 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 30/32] 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 31/32] 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 4ba1889ce4ae00d0bb5606b633063d467403925c Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 18 Jun 2020 18:31:08 +0200 Subject: [PATCH 32/32] 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,