diff --git a/src/plugins/embeddable/docs/README.md b/src/plugins/embeddable/docs/README.md index 1b6c7be13b1d4..ce5e76d54a046 100644 --- a/src/plugins/embeddable/docs/README.md +++ b/src/plugins/embeddable/docs/README.md @@ -2,4 +2,5 @@ ## Reference -- [Embeddable containers and inherited input state](./containers_and_inherited_state.md) +- [Input and output state](./input_and_output_state.md) +- [Common mistakes with embeddable containers and inherited input state](./containers_and_inherited_state.md) diff --git a/src/plugins/embeddable/docs/containers_and_inherited_state.md b/src/plugins/embeddable/docs/containers_and_inherited_state.md index c950bef96002a..35e399f89c131 100644 --- a/src/plugins/embeddable/docs/containers_and_inherited_state.md +++ b/src/plugins/embeddable/docs/containers_and_inherited_state.md @@ -1,4 +1,4 @@ -## Embeddable containers and inherited input state +## Common mistakes with embeddable containers and inherited input state `updateInput` is typed as `updateInput(input: Partial)`. Notice it's _partial_. This is to support the use case of inherited state when an embeddable is inside a container. diff --git a/src/plugins/embeddable/docs/input_and_output_state.md b/src/plugins/embeddable/docs/input_and_output_state.md new file mode 100644 index 0000000000000..810dc72664f96 --- /dev/null +++ b/src/plugins/embeddable/docs/input_and_output_state.md @@ -0,0 +1,282 @@ +## Input and output state + +### What's the difference? + +Input vs Output State + +| Input | Output | +| ----------- | ----------- | +| Public, on the IEmbeddable interface. `embeddable.updateInput(changedInput)` | Protected inside the Embeddable class. `this.updateOutput(changedOutput)` | +| Serializable representation of the embeddable | Does not need to be serializable | +| Can be updated throughout the lifecycle of an Embeddable | Often derived from input state | + +Non-real examples to showcase the difference: + +| Input | Output | +| ----------- | ----------- | +| savedObjectId | savedObjectAttributes | +| esQueryRequest | esQueryResponse | +| props | renderComplete | + +### Types of input state + +#### Inherited input state + +The only reason we have different types of input state is to support embeddable containers, and children embeddables _inheriting_ state from the container. +For example, when the dashboard time range changes, so does +the time range of all children embeddables. Dashboard passes down time range as _inherited_ input state. From the viewpoint of the child Embeddable, +time range is just input state. It doesn't care where it gets this data from. + + +For example, imagine a container with this input: + +```js +{ + gridData: {...}, + timeRange: 'now-15m to now', + + // Every embeddable container has a panels mapping. It's how the base container class manages common changes like children being + // added, removed or edited. + panels: { + ['1']: { + // `type` is used to grab the right embeddable factory. Every PanelState must specify one. + type: 'clock', + + // `explicitInput` is combined with `inheritedInput` to create `childInput`, and is use like: + // `embeddableFactories.get(type).create(childInput)`. + explicitInput: { + + // All explicitInput is required to have an id. This is used as a way for the + // embeddable to know where it exists in the panels array if it's living in a container. + // Note, this is NOT THE SAVED OBJECT ID! Even though it's sometimes used to store the saved object id. + id: '1', + } + } + } +} +``` + +That could result in the following input being passed to a child: + +```js +{ + timeRange: 'now-15m to now', + id: '1', +} +``` + +Notice that `gridData` is not passed down, but `timeRange` is. What ends up as _inherited_ state, that is passed down to a child, is up to the specific +implementation of a container and +determined by the abstract function `Container.getInheritedInput()` + +#### Overridding inherited input + +We wanted to support _overriding_ this inherited state, to support the "Per panel time range" feature. The _inherited_ `timeRange` input can be +overridden by the _explicit_ `timeRange` input. + +Take this example dashboard container input: + +```js +{ + gridData: {...}, + timeRange: 'now-15m to now', + panels: { + ['1']: { + type: 'clock', + explicitInput: { + timeRange: 'now-30m to now', + id: '1', + } + }, + ['2']: { + type: 'clock', + explicitInput: { + id: '2', + } + }, +} +``` + +The first child embeddable will get passed input state: + +```js +{ + timeRange: 'now-30m to now', + id: '1', +} +``` + +This override wouldn't affect other children, so the second child would receive: + +```js +{ + timeRange: 'now-15m to now', + id: '2', +} +``` + +#### EmbeddableInput.id and some technical debt + +Above I said: + +> From the viewpoint of the child Embeddable, +> time range is just input state. It doesn't care where it gets this data from. + +and this is mostly true, however, the primary reason EmbeddableInput.id exists is to support the +case where the custom time range badge action needs to look up a child's explicit input on the +parent. It does this to determine whether or not to show the badge. The logic is something like: + +```ts + // If there is no explicit input defined on the parent then this embeddable inherits the + // time range from whatever the time range of the parent is. + return parent.getInput().panels[embeddable.id].explicitInput.timeRange === undefined; +``` + +It doesn't just compare the timeRange input on the parent (`embeddable.parent?.getInput().timeRange` )because even if they happen to match, +we still want the badge showing to indicate the time range is "locked" on this particular panel. + +Note that `parent` can be retrieved from either `embeddabble.parent` or `embeddable.getRoot()`. The +`getRoot` variety will walk up to find the root parent, even though we have no tested or used +nested containers, it is theoretically possible. + +This EmbeddableInput.id parameter is marked as required on the `EmbeddableInput` interface, even though it's only used +when an embeddable is inside a parent. There is also no +typescript safety to ensure the id matches the panel id in the parents json: + +```js + ['2']: { + type: 'clock', + explicitInput: { + id: '3', // No! Should be 2! + } + }, +``` + +It should probably be something that the parent passes down to the child specifically, based on the panel mapping key, +and renamed to something like `panelKeyInParent`. + +Note that this has nothing to do with a saved object id, even though in dashboard app, the saved object happens to be +used as the dashboard container id. Another reason this should probably not be required for embeddables not +inside containers. + +#### A container can pass down any information to the children + +It doesn't have to be part of it's own input. It's possible for a container input like: + + +```js +{ + timeRange: 'now-15m to now', + panels: { + ['1']: { + type: 'clock', + explicitInput: { + timeRange: 'now-30m to now', + id: '1', + } + } +} +``` + +to pass down this input: + +```js +{ + timeRange: 'now-30m to now', + id: '1', + zed: 'bar', // <-- Where did this come from?? +} +``` + +I don't have a realistic use case for this, just noting it's possible in any containers implementation of `getInheritedInput`. Note this is still considered +inherited input because it's coming from the container. + +#### Explicit input stored on behalf of the container + +It's possible for a container to store explicit input state on behalf of an embeddable, without knowing what that state is. For example, a container could +have input state like: + +```js +{ + timeRange: 'now-15m to now', + panels: { + ['1']: { + type: 'clock', + explicitInput: { + display: 'analog', + id: '1', + } + } +} +``` + +And what gets passed to the child is: + +```js +{ + timeRange: 'now-15m to now', + id: '1', + display: 'analog' +} +``` + +even if a container has no idea about this `clock` embeddable implementation, nor this `explicitInput.display` field. + +There are two ways for this kind of state to end up in `panels[id].explicitInput`. + +1. `ClockEmbeddableFactory.getExplicitInput` returns it. +2. `ClockEmbeddableFactory.getDefaultInput` returns it. (This function is largely unused. We may be able to get rid of it.) +3. Someone called `embeddable.updateInput({ display: 'analog' })`, when the embeddable is a child in a container. + +#### Containers can pass down too much information + +Lets say our container state is: + +```js +{ + timeRange: 'now-15m to now', + panels: { + ['1']: { + type: 'helloWorld', + explicitInput: { + id: '1', + } + } +} +``` + +What gets passed to the child is: + +```js +{ + timeRange: 'now-15m to now', + id: '1', +} +``` + +It doesn't matter if the embeddable does not require, nor use, `timeRange`. The container passes down inherited input state to every child. +This could present problems with trying to figure out which embeddables support +different types of actions. For example, it'd be great if "Customize time range" action only showed up on embeddables that actually did something +with the `timeRange`. You can't check at runtime whether `input.timeRange === undefined` to do so though, because it will be passed in by the container +regardless. + + +#### Tech debt warnings + +`EmbeddableFactory.getExplicitInput` was intended as a way for an embeddable to retrieve input state it needs, that will not +be provided by a container. However, an embeddable won't know where it will be rendered, so how will the factory know which +required data to ask from the user and which will be inherited from the container? I believe `getDefaultInput` was meant to solve this. +`getDefaultInput` would provide default values, only if the container didn't supply them through inheritance. Explicit input would +always provide these values, and would always be stored in a containers `panel[id].explicitInput`, even if the container _did_ provide +them. + +There are no real life examples showcasing this, it may not even be really needed by current use cases. Containers were built as an abstraction, with +the thinking being that it would support any type of rendering of child embeddables - whether in a "snap to grid" style like dashboard, +or in a free form layout like canvas. + +The only real implementation of a container in production code at the time this is written is Dashboard however, with no plans to migrate +Canvas over to use it (this was the original impetus for an abstraction). The container code is quite complicated with child management, +so it makes creating a new container very easy, as you can see in the developer examples of containers. But, it's possible this layer was + an over abstraction without a real prod use case (I can say that because I wrote it, I'm only insulting myself!) :). + +Be sure to read [Common mistakes with embeddable containers and inherited input state](./containers_and_inherited_state.md) next! \ No newline at end of file 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 f3dc7abcf8239..54dd4704edfc0 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,8 +4,6 @@ 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`; @@ -124,26 +122,18 @@ 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`; @@ -262,26 +252,18 @@ 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"`; @@ -400,16 +382,10 @@ 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 7537dba7f8411..d5c3f91eb9247 100644 --- a/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts +++ b/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts @@ -87,9 +87,3 @@ 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/errors.ts b/x-pack/plugins/apm/common/projections/errors.ts index 390a8a0968102..bd397afae2243 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 '../utils/range_filter'; +import { rangeFilter } from '../../server/lib/helpers/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 45998bfe82e96..b05ec5f2ba876 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 '../utils/range_filter'; +import { rangeFilter } from '../../server/lib/helpers/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 deleted file mode 100644 index b1218546d09ff..0000000000000 --- a/x-pack/plugins/apm/common/projections/rum_overview.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { - Setup, - SetupTimeRange, - SetupUIFilters, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../server/lib/helpers/setup_request'; -import { PROCESSOR_EVENT, TRANSACTION_TYPE } from '../elasticsearch_fieldnames'; -import { rangeFilter } from '../utils/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' } }, - { term: { [TRANSACTION_TYPE]: 'page-load' } }, - { - // Adding this filter to cater for some inconsistent rum data - exists: { - field: 'transaction.marks.navigationTiming.fetchStart', - }, - }, - ...uiFiltersES, - ], - }; - - return { - index: indices['apm_oss.transactionIndices'], - body: { - query: { - bool, - }, - }, - }; -} diff --git a/x-pack/plugins/apm/common/projections/services.ts b/x-pack/plugins/apm/common/projections/services.ts index 80a3471e9c30d..bcfc27d720ba9 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 '../utils/range_filter'; +import { rangeFilter } from '../../server/lib/helpers/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 b6cd73ca9aaad..99d5a04c1e722 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 '../utils/range_filter'; +import { rangeFilter } from '../../server/lib/helpers/range_filter'; export function getTransactionsProjection({ setup, diff --git a/x-pack/plugins/apm/common/projections/typings.ts b/x-pack/plugins/apm/common/projections/typings.ts index 693795b09e1d0..3361770336dde 100644 --- a/x-pack/plugins/apm/common/projections/typings.ts +++ b/x-pack/plugins/apm/common/projections/typings.ts @@ -29,5 +29,4 @@ export enum PROJECTION { METRICS = 'metrics', ERROR_GROUPS = 'errorGroups', SERVICE_NODES = 'serviceNodes', - RUM_OVERVIEW = 'rumOverview', } diff --git a/x-pack/plugins/apm/e2e/cypress/integration/helpers.ts b/x-pack/plugins/apm/e2e/cypress/integration/helpers.ts index 689b88390810f..90d5c9eda632d 100644 --- a/x-pack/plugins/apm/e2e/cypress/integration/helpers.ts +++ b/x-pack/plugins/apm/e2e/cypress/integration/helpers.ts @@ -6,30 +6,20 @@ /* eslint-disable import/no-extraneous-dependencies */ -const RANGE_FROM = '2020-06-01T14:59:32.686Z'; -const RANGE_TO = '2020-06-16T16:59:36.219Z'; - +const RANGE_FROM = '2020-03-04T12:30:00.000Z'; +const RANGE_TO = '2020-03-04T13:00:00.000Z'; 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, - dateRange?: { to: string; from: string } -) { +export function loginAndWaitForPage(url: string) { const username = Cypress.env('elasticsearch_username'); const password = Cypress.env('elasticsearch_password'); cy.log(`Authenticating via ${username} / ${password}`); - 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}`; + + const fullUrl = `${BASE_URL}${url}?rangeFrom=${RANGE_FROM}&rangeTo=${RANGE_TO}`; 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 deleted file mode 100644 index eabfaf096731b..0000000000000 --- a/x-pack/plugins/apm/e2e/cypress/integration/rum_dashboard.feature +++ /dev/null @@ -1,7 +0,0 @@ -Feature: RUM Dashboard - - Scenario: Client metrics - 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 dd96a57ef8c45..d4c8ba4910850 100644 --- a/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js +++ b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js @@ -1,17 +1,10 @@ module.exports = { - "__version": "4.5.0", - "APM": { - "Transaction duration charts": { - "1": "55 ms", - "2": "28 ms", - "3": "0 ms" - } + APM: { + 'Transaction duration charts': { + '1': '350 ms', + '2': '175 ms', + '3': '0 ms', + }, }, - "RUM Dashboard": { - "Client metrics": { - "1": "62", - "2": "0.07 sec", - "3": "0.01 sec" - } - } -} + __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 deleted file mode 100644 index 38eadbf513032..0000000000000 --- a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/rum_dashboard.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { Given, When, Then } from 'cypress-cucumber-preprocessor/steps'; -import { loginAndWaitForPage } from '../../integration/helpers'; - -/** The default time in ms to wait for a Cypress command to complete */ -export const DEFAULT_TIMEOUT = 60 * 1000; - -Given(`a user browses the APM UI application for RUM Data`, () => { - // open service overview page - const RANGE_FROM = 'now-24h'; - const RANGE_TO = 'now'; - loginAndWaitForPage(`/app/apm#/services`, { from: RANGE_FROM, to: RANGE_TO }); -}); - -When(`the user inspects the real user monitoring tab`, () => { - // click rum tab - cy.get(':contains(Real User Monitoring)', { timeout: DEFAULT_TIMEOUT }) - .last() - .click({ force: true }); -}); - -Then(`should redirect to rum dashboard`, () => { - cy.url().should('contain', `/app/apm#/rum-overview`); -}); - -Then(`should have correct client metrics`, () => { - const clientMetrics = '[data-cy=client-metrics] .euiStat__title'; - - // wait for all loading to finish - cy.get('kbnLoadingIndicator').should('not.be.visible'); - cy.get('.euiStat__title-isLoading').should('not.be.visible'); - - cy.get(clientMetrics).eq(2).invoke('text').snapshot(); - - cy.get(clientMetrics).eq(1).invoke('text').snapshot(); - - cy.get(clientMetrics).eq(0).invoke('text').snapshot(); -}); diff --git a/x-pack/plugins/apm/e2e/ingest-data/replay.js b/x-pack/plugins/apm/e2e/ingest-data/replay.js index 3478039f39b50..ae3f62894afc0 100644 --- a/x-pack/plugins/apm/e2e/ingest-data/replay.js +++ b/x-pack/plugins/apm/e2e/ingest-data/replay.js @@ -99,11 +99,7 @@ async function init() { .split('\n') .filter((item) => item) .map((item) => JSON.parse(item)) - .filter((item) => { - return ( - item.url === '/intake/v2/events' || item.url === '/intake/v2/rum/events' - ); - }); + .filter((item) => item.url === '/intake/v2/events'); spinner.start(); requestProgress.total = items.length; diff --git a/x-pack/plugins/apm/e2e/run-e2e.sh b/x-pack/plugins/apm/e2e/run-e2e.sh index 43cc74a197f42..aa7c0e21425ad 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/2020-06-12.json --output ${TMP_DIR}/events.json + curl --silent https://storage.googleapis.com/apm-ui-e2e-static-data/events.json --output ${TMP_DIR}/events.json fi # echo "Deleting existing indices (apm* and .apm*)" diff --git a/x-pack/plugins/apm/e2e/yarn.lock b/x-pack/plugins/apm/e2e/yarn.lock index 975154d71b85d..a6729c56ecb09 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.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== +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== umd@^3.0.0: version "3.0.3" diff --git a/x-pack/plugins/apm/public/application/index.tsx b/x-pack/plugins/apm/public/application/index.tsx index 8800b2fd492bf..56c427e67ad4c 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, units } from '../style/variables'; +import { px, unit, 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,6 +33,7 @@ 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/Home/index.tsx b/x-pack/plugins/apm/public/components/app/Home/index.tsx index c325a72375359..74cbc00b17889 100644 --- a/x-pack/plugins/apm/public/components/app/Home/index.tsx +++ b/x-pack/plugins/apm/public/components/app/Home/index.tsx @@ -25,9 +25,6 @@ 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'; -import { EndUserExperienceLabel } from '../RumDashboard/translations'; function getHomeTabs({ serviceMapEnabled = true, @@ -73,27 +70,14 @@ function getHomeTabs({ }); } - 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' | 'rum-overview'; + tab: 'traces' | 'services' | 'service-map'; } export function Home({ tab }: Props) { @@ -109,11 +93,7 @@ export function Home({ tab }: Props) { -

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

+

APM

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 295f343b411a9..577af75e92d9e 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,13 +250,4 @@ 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 4965aa9db8760..167de1a37f427 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,5 +26,4 @@ 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/ChartWrapper/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ChartWrapper/index.tsx deleted file mode 100644 index a3cfbb28abee2..0000000000000 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ChartWrapper/index.tsx +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React, { 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 deleted file mode 100644 index 8c0a7c6a91f67..0000000000000 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -// @flow -import * as React from 'react'; -import styled from 'styled-components'; -import { EuiFlexGroup, EuiFlexItem, EuiStat } from '@elastic/eui'; -import { useFetcher } from '../../../../hooks/useFetcher'; -import { useUrlParams } from '../../../../hooks/useUrlParams'; -import { BackEndLabel, FrontEndLabel, PageViewsLabel } from '../translations'; - -export const formatBigValue = (val?: number | null, fixed?: number): string => { - if (val && val >= 1000) { - const result = val / 1000; - if (fixed) { - return result.toFixed(fixed) + 'k'; - } - return result + 'k'; - } - return val + ''; -}; - -const ClFlexGroup = styled(EuiFlexGroup)` - flex-direction: row; - @media only screen and (max-width: 768px) { - flex-direction: row; - justify-content: space-between; - } -`; - -export const ClientMetrics = () => { - const { urlParams, uiFilters } = useUrlParams(); - - const { start, end } = urlParams; - - const { data, status } = useFetcher( - (callApmApi) => { - if (start && end) { - return callApmApi({ - pathname: '/api/apm/rum/client-metrics', - params: { - query: { start, end, uiFilters: JSON.stringify(uiFilters) }, - }, - }); - } - }, - [start, end, uiFilters] - ); - - const STAT_STYLE = { width: '240px' }; - - return ( - - - - - - - - - - - - ); -}; 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 deleted file mode 100644 index 9c89b8bc161b7..0000000000000 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/PercentileAnnotations.tsx +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import * as React from 'react'; -import { - AnnotationDomainTypes, - LineAnnotation, - LineAnnotationDatum, - LineAnnotationStyle, -} from '@elastic/charts'; -import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; -import styled from 'styled-components'; - -interface Props { - percentiles?: Record; -} - -function generateAnnotationData( - values?: Record -): LineAnnotationDatum[] { - return Object.entries(values ?? {}).map((value, index) => ({ - dataValue: value[1], - details: `${(+value[0]).toFixed(0)}`, - })); -} - -const PercentileMarker = styled.span` - position: relative; - bottom: 140px; -`; - -export const PercentileAnnotations = ({ percentiles }: Props) => { - const dataValues = generateAnnotationData(percentiles) ?? []; - - const style: Partial = { - line: { - strokeWidth: 1, - stroke: euiLightVars.euiColorSecondary, - opacity: 1, - }, - }; - - 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 deleted file mode 100644 index c7a0b64f6a8b8..0000000000000 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React, { useState } from 'react'; -import { - EuiButton, - EuiFlexGroup, - EuiFlexItem, - EuiSpacer, - EuiTitle, -} from '@elastic/eui'; -import { - Axis, - Chart, - ScaleType, - LineSeries, - CurveType, - BrushEndListener, - Settings, - TooltipValueFormatter, - TooltipValue, -} from '@elastic/charts'; -import { Position } from '@elastic/charts/dist/utils/commons'; -import { useUrlParams } from '../../../../hooks/useUrlParams'; -import { useFetcher } from '../../../../hooks/useFetcher'; -import { ChartWrapper } from '../ChartWrapper'; -import { PercentileAnnotations } from './PercentileAnnotations'; -import { - PageLoadDistLabel, - PageLoadTimeLabel, - PercPageLoadedLabel, - ResetZoomLabel, -} from '../translations'; - -export const PageLoadDistribution = () => { - const { urlParams, uiFilters } = useUrlParams(); - - const { start, end } = urlParams; - - const [percentileRange, setPercentileRange] = useState<{ - min: string | null; - max: string | null; - }>({ - min: null, - max: null, - }); - - const { data, status } = useFetcher( - (callApmApi) => { - if (start && end) { - return callApmApi({ - pathname: '/api/apm/rum-client/page-load-distribution', - params: { - query: { - start, - end, - uiFilters: JSON.stringify(uiFilters), - ...(percentileRange.min && percentileRange.max - ? { - minPercentile: percentileRange.min, - maxPercentile: percentileRange.max, - } - : {}), - }, - }, - }); - } - }, - [end, start, uiFilters, percentileRange.min, percentileRange.max] - ); - - const onBrushEnd: BrushEndListener = ({ x }) => { - if (!x) { - return; - } - const [minX, maxX] = x; - setPercentileRange({ min: String(minX), max: String(maxX) }); - }; - - const headerFormatter: TooltipValueFormatter = (tooltip: TooltipValue) => { - return ( -
-

{tooltip.value} seconds

-
- ); - }; - - const tooltipProps = { - headerFormatter, - }; - - return ( -
- - - -

{PageLoadDistLabel}

-
-
- - { - setPercentileRange({ min: null, max: null }); - }} - fill={percentileRange.min !== null && percentileRange.max !== null} - > - {ResetZoomLabel} - - -
- - - - - - - Number(d).toFixed(1) + ' %'} - /> - - - -
- ); -}; 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 deleted file mode 100644 index cc41bd4352947..0000000000000 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import * as React from 'react'; -import { 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'; -import { useFetcher } from '../../../../hooks/useFetcher'; -import { ChartWrapper } from '../ChartWrapper'; -import { DateTimeLabel, PageViewsLabel } from '../translations'; -import { history } from '../../../../utils/history'; -import { fromQuery, toQuery } from '../../../shared/Links/url_helpers'; -import { formatBigValue } from '../ClientMetrics'; - -export const PageViewsTrend = () => { - const { urlParams, uiFilters } = useUrlParams(); - - const { start, end } = urlParams; - - const { data, status } = useFetcher( - (callApmApi) => { - if (start && end) { - return callApmApi({ - pathname: '/api/apm/rum-client/page-view-trends', - params: { - query: { - start, - end, - uiFilters: JSON.stringify(uiFilters), - }, - }, - }); - } - }, - [end, start, uiFilters] - ); - 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 ( -
- -

{PageViewsLabel}

-
- - - - - formatBigValue(Number(d))} - /> - - - -
- ); -}; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx deleted file mode 100644 index e3fa7374afb38..0000000000000 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { - EuiFlexGroup, - EuiFlexItem, - EuiTitle, - EuiSpacer, - EuiPanel, -} from '@elastic/eui'; -import React from 'react'; -import { ClientMetrics } from './ClientMetrics'; -import { PageViewsTrend } from './PageViewsTrend'; -import { PageLoadDistribution } from './PageLoadDistribution'; -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 ( - <> - -

{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 deleted file mode 100644 index 8f21065b0dab0..0000000000000 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/index.tsx +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { 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 './RumDashboard'; - -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/app/RumDashboard/translations.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts deleted file mode 100644 index c2aed41a55c7d..0000000000000 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; - -export const EndUserExperienceLabel = i18n.translate( - 'xpack.apm.rum.dashboard.title', - { - defaultMessage: 'End User Experience', - } -); - -export const getWhatIsGoingOnLabel = (environmentVal: string) => - i18n.translate('xpack.apm.rum.dashboard.environment.title', { - defaultMessage: `What's going on in {environmentVal}?`, - values: { environmentVal }, - }); - -export const BackEndLabel = i18n.translate('xpack.apm.rum.dashboard.backend', { - defaultMessage: 'Backend', -}); - -export const FrontEndLabel = i18n.translate( - 'xpack.apm.rum.dashboard.frontend', - { - 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 PercPageLoadedLabel = i18n.translate( - 'xpack.apm.rum.dashboard.pagesLoaded.label', - { - defaultMessage: 'Pages loaded', - } -); - -export const PageLoadTimeLabel = i18n.translate( - 'xpack.apm.rum.dashboard.pageLoadTime.label', - { - defaultMessage: 'Page load time (seconds)', - } -); - -export const PageLoadDistLabel = i18n.translate( - 'xpack.apm.rum.dashboard.pageLoadDistribution.label', - { - defaultMessage: 'Page load distribution', - } -); - -export const ResetZoomLabel = i18n.translate( - 'xpack.apm.rum.dashboard.resetZoom.label', - { - defaultMessage: 'Reset zoom', - } -); 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 81bdbdad805d6..2f35e329720de 100644 --- a/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceDetailTabs.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceDetailTabs.tsx @@ -22,8 +22,6 @@ 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'; @@ -112,20 +110,6 @@ 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 eab685a4c1ab4..d01deb8160858 100644 --- a/x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx @@ -76,10 +76,10 @@ export function KueryBar() { }); // The bar should be disabled when viewing the service map - const disabled = /\/(service-map|rum-overview)$/.test(location.pathname); + const disabled = /\/service-map$/.test(location.pathname); const disabledPlaceholder = i18n.translate( 'xpack.apm.kueryBar.disabledPlaceholder', - { defaultMessage: 'Search is not available here' } + { defaultMessage: 'Search is not available for service map' } ); async function onChange(inputValue: string, selectionStart: number) { 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 deleted file mode 100644 index abca9817bd69d..0000000000000 --- a/x-pack/plugins/apm/public/components/shared/Links/apm/RumOverviewLink.tsx +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -/* - * 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/errors/distribution/get_buckets.ts b/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.ts index db36ad1ede91c..7d96c490fcd70 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 '../../../../common/utils/range_filter'; +import { rangeFilter } from '../../helpers/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 3d20f84ccfbc2..b157abd0b7e76 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 '../../../common/utils/range_filter'; +import { rangeFilter } from '../helpers/range_filter'; import { Setup, SetupTimeRange, diff --git a/x-pack/plugins/apm/common/utils/range_filter.ts b/x-pack/plugins/apm/server/lib/helpers/range_filter.ts similarity index 100% rename from x-pack/plugins/apm/common/utils/range_filter.ts rename to x-pack/plugins/apm/server/lib/helpers/range_filter.ts 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 deleted file mode 100644 index 7d8f31aaeca7f..0000000000000 --- a/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap +++ /dev/null @@ -1,194 +0,0 @@ -// 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 { - "exists": Object { - "field": "transaction.marks.navigationTiming.fetchStart", - }, - }, - 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, - 75, - 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 { - "exists": Object { - "field": "transaction.marks.navigationTiming.fetchStart", - }, - }, - Object { - "term": Object { - "my.custom.ui.filter": "foo-bar", - }, - }, - ], - }, - }, - "size": 0, - }, - "index": "myIndex", -} -`; - -exports[`rum client dashboard queries fetches page view trends 1`] = ` -Object { - "body": Object { - "aggs": Object { - "pageViews": 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 { - "exists": Object { - "field": "transaction.marks.navigationTiming.fetchStart", - }, - }, - Object { - "term": Object { - "my.custom.ui.filter": "foo-bar", - }, - }, - ], - }, - }, - "size": 0, - }, - "index": "myIndex", -} -`; 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 deleted file mode 100644 index 8b3f733fc402a..0000000000000 --- a/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { getRumOverviewProjection } from '../../../common/projections/rum_overview'; -import { mergeProjection } from '../../../common/projections/util/merge_projection'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../helpers/setup_request'; - -export async function getClientMetrics({ - setup, -}: { - setup: Setup & SetupTimeRange & SetupUIFilters; -}) { - const projection = getRumOverviewProjection({ - setup, - }); - - const params = mergeProjection(projection, { - body: { - size: 0, - query: { - bool: projection.body.query.bool, - }, - aggs: { - pageViews: { value_count: { field: 'transaction.type' } }, - backEnd: { - avg: { - field: 'transaction.marks.agent.timeToFirstByte', - missing: 0, - }, - }, - domInteractive: { - avg: { - field: 'transaction.marks.agent.domInteractive', - missing: 0, - }, - }, - }, - }, - }); - - const { client } = setup; - - const response = await client.search(params); - const { backEnd, domInteractive, pageViews } = response.aggregations!; - - // Divide by 1000 to convert ms into seconds - return { - pageViews, - backEnd: { value: (backEnd.value || 0) / 1000 }, - frontEnd: { - value: ((domInteractive.value || 0) - (backEnd.value || 0)) / 1000, - }, - }; -} 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 deleted file mode 100644 index 3c563946e4052..0000000000000 --- a/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { getRumOverviewProjection } from '../../../common/projections/rum_overview'; -import { mergeProjection } from '../../../common/projections/util/merge_projection'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../helpers/setup_request'; - -export async function getPageLoadDistribution({ - setup, - minPercentile, - maxPercentile, -}: { - setup: Setup & SetupTimeRange & SetupUIFilters; - minPercentile?: string; - maxPercentile?: string; -}) { - const projection = getRumOverviewProjection({ - setup, - }); - - const params = mergeProjection(projection, { - body: { - size: 0, - query: { - bool: projection.body.query.bool, - }, - aggs: { - durationMinMax: { - min: { - field: 'transaction.duration.us', - missing: 0, - }, - }, - durationPercentiles: { - percentiles: { - field: 'transaction.duration.us', - percents: [50, 75, 90, 95, 99], - script: { - lang: 'painless', - source: "doc['transaction.duration.us'].value / params.timeUnit", - params: { - timeUnit: 1000, - }, - }, - }, - }, - }, - }, - }); - - const { client } = setup; - - const { - aggregations, - hits: { total }, - } = await client.search(params); - - if (total.value === 0) { - return null; - } - - const minDuration = (aggregations?.durationMinMax.value ?? 0) / 1000; - - const minPerc = minPercentile ? +minPercentile : minDuration; - - const maxPercentileQuery = - aggregations?.durationPercentiles.values['99.0'] ?? 100; - - const maxPerc = maxPercentile ? +maxPercentile : maxPercentileQuery; - - const pageDist = await getPercentilesDistribution(setup, minPerc, maxPerc); - return { - pageLoadDistribution: pageDist, - percentiles: aggregations?.durationPercentiles.values, - }; -} - -const getPercentilesDistribution = async ( - setup: Setup & SetupTimeRange & SetupUIFilters, - minPercentiles: number, - maxPercentile: number -) => { - const stepValue = (maxPercentile - minPercentiles) / 50; - const stepValues = []; - for (let i = 1; i < 50; i++) { - stepValues.push((stepValue * i + minPercentiles).toFixed(2)); - } - - const projection = getRumOverviewProjection({ - setup, - }); - - const params = mergeProjection(projection, { - body: { - size: 0, - query: { - bool: projection.body.query.bool, - }, - 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 { aggregations } = await client.search(params); - - const pageDist = (aggregations?.loadDistribution.values ?? []) as Array<{ - key: number; - value: number; - }>; - - 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/lib/rum_client/get_page_view_trends.ts b/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts deleted file mode 100644 index 126605206d299..0000000000000 --- a/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { getRumOverviewProjection } from '../../../common/projections/rum_overview'; -import { mergeProjection } from '../../../common/projections/util/merge_projection'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../helpers/setup_request'; - -export async function getPageViewTrends({ - setup, -}: { - setup: Setup & SetupTimeRange & SetupUIFilters; -}) { - const projection = getRumOverviewProjection({ - setup, - }); - - const params = mergeProjection(projection, { - body: { - size: 0, - query: { - bool: projection.body.query.bool, - }, - aggs: { - pageViews: { - 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?.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 deleted file mode 100644 index 5f5a48eced746..0000000000000 --- a/x-pack/plugins/apm/server/lib/rum_client/queries.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { - SearchParamsMock, - inspectSearchParams, -} from '../../../public/utils/testHelpers'; -import { getClientMetrics } from './get_client_metrics'; -import { getPageViewTrends } from './get_page_view_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 page view trends', async () => { - mock = await inspectSearchParams((setup) => - getPageViewTrends({ - setup, - }) - ); - - expect(mock.params).toMatchSnapshot(); - }); - - it('fetches page load distribution', async () => { - mock = await inspectSearchParams((setup) => - getPageLoadDistribution({ - setup, - minPercentile: '0', - maxPercentile: '99', - }) - ); - expect(mock.params).toMatchSnapshot(); - }); -}); 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 e521efa687388..d069e93397611 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 '../../../common/utils/range_filter'; +import { rangeFilter } from '../helpers/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 11c3a00f32980..6eba84f2205a1 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 '../../../common/utils/range_filter'; +import { rangeFilter } from '../helpers/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 6da5d195cf194..9829c5cb25182 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 '../../../../common/utils/range_filter'; +import { rangeFilter } from '../../helpers/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 8d75d746c7fca..0b016828d5f00 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 '../../../common/utils/range_filter'; +import { rangeFilter } from '../helpers/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 d88be4055dc21..963dea4d8322c 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 '../../../common/utils/range_filter'; +import { rangeFilter } from '../helpers/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 f9374558dfeeb..e96b323958fd7 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 '../../../common/utils/range_filter'; +import { rangeFilter } from '../helpers/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 e3d688b694380..90dd41cb9b0c8 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 '../../../../common/utils/range_filter'; +import { rangeFilter } from '../../helpers/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 ea6213f64ee36..cc23055e34672 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 '../../../../common/utils/range_filter'; +import { rangeFilter } from '../../helpers/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 5af8b9f78cec1..713423f8953d5 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 '../../../../common/utils/range_filter'; +import { rangeFilter } from '../../helpers/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 8e19af926ce02..71c40010a2a3f 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 '../../../../../common/utils/range_filter'; +import { rangeFilter } from '../../../helpers/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 3f8bf635712be..920552d1c1aeb 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 '../../../../../common/utils/range_filter'; +import { rangeFilter } from '../../../helpers/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 a7de93a3bf650..60dc16b6a546c 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 '../../../../common/utils/range_filter'; +import { rangeFilter } from '../../helpers/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 3fca30634be6a..ccbe7a19d2f82 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 '../../../common/utils/range_filter'; +import { rangeFilter } from '../helpers/range_filter'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { ENVIRONMENT_NOT_DEFINED } from '../../../common/environment_filter_values'; import { ESFilter } from '../../../typings/elasticsearch'; diff --git a/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts b/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts index 25a559cb07a3d..8f35664c2599c 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,11 +11,6 @@ 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 = { @@ -55,36 +50,6 @@ 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 a34690aff43b4..bdfb49fa30828 100644 --- a/x-pack/plugins/apm/server/routes/create_apm_api.ts +++ b/x-pack/plugins/apm/server/routes/create_apm_api.ts @@ -59,7 +59,6 @@ import { transactionsLocalFiltersRoute, serviceNodesLocalFiltersRoute, uiFiltersEnvironmentsRoute, - rumOverviewLocalFiltersRoute, } from './ui_filters'; import { createApi } from './create_api'; import { serviceMapRoute, serviceMapServiceNodeRoute } from './service_map'; @@ -71,11 +70,6 @@ import { listCustomLinksRoute, customLinkTransactionRoute, } from './settings/custom_link'; -import { - rumClientMetricsRoute, - rumPageViewsTrendRoute, - rumPageLoadDistributionRoute, -} from './rum_client'; const createApmApi = () => { const api = createApi() @@ -154,13 +148,7 @@ const createApmApi = () => { .add(updateCustomLinkRoute) .add(deleteCustomLinkRoute) .add(listCustomLinksRoute) - .add(customLinkTransactionRoute) - - // Rum Overview - .add(rumOverviewLocalFiltersRoute) - .add(rumPageViewsTrendRoute) - .add(rumPageLoadDistributionRoute) - .add(rumClientMetricsRoute); + .add(customLinkTransactionRoute); return api; }; diff --git a/x-pack/plugins/apm/server/routes/rum_client.ts b/x-pack/plugins/apm/server/routes/rum_client.ts deleted file mode 100644 index 9b5f6529b1783..0000000000000 --- a/x-pack/plugins/apm/server/routes/rum_client.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import * as t from 'io-ts'; -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 { getPageViewTrends } from '../lib/rum_client/get_page_view_trends'; -import { getPageLoadDistribution } from '../lib/rum_client/get_page_load_distribution'; - -export const percentileRangeRt = t.partial({ - minPercentile: t.string, - maxPercentile: t.string, -}); - -export const rumClientMetricsRoute = createRoute(() => ({ - path: '/api/apm/rum/client-metrics', - params: { - query: t.intersection([uiFiltersRt, rangeRt]), - }, - handler: async ({ context, request }) => { - const setup = await setupRequest(context, request); - - return getClientMetrics({ setup }); - }, -})); - -export const rumPageLoadDistributionRoute = createRoute(() => ({ - path: '/api/apm/rum-client/page-load-distribution', - params: { - query: t.intersection([uiFiltersRt, rangeRt, percentileRangeRt]), - }, - handler: async ({ context, request }) => { - const setup = await setupRequest(context, request); - - const { - query: { minPercentile, maxPercentile }, - } = context.params; - - return getPageLoadDistribution({ setup, minPercentile, maxPercentile }); - }, -})); - -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 getPageViewTrends({ setup }); - }, -})); diff --git a/x-pack/plugins/apm/server/routes/ui_filters.ts b/x-pack/plugins/apm/server/routes/ui_filters.ts index 280645d4de8d0..8f4ef94b86ac5 100644 --- a/x-pack/plugins/apm/server/routes/ui_filters.ts +++ b/x-pack/plugins/apm/server/routes/ui_filters.ts @@ -29,7 +29,6 @@ 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', @@ -222,16 +221,6 @@ 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< diff --git a/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts b/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts index 6ee26caa4ef7c..0739e8e6120bf 100644 --- a/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts +++ b/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts @@ -137,15 +137,6 @@ export interface AggregationOptionsByType { >; keyed?: boolean; }; - auto_date_histogram: { - field: string; - buckets: number; - }; - percentile_ranks: { - field: string; - values: string[]; - keyed?: boolean; - }; } type AggregationType = keyof AggregationOptionsByType; @@ -310,23 +301,6 @@ 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 diff --git a/x-pack/plugins/ingest_manager/common/types/rest_spec/fleet_setup.ts b/x-pack/plugins/ingest_manager/common/types/rest_spec/fleet_setup.ts index ae4cb4e3fce49..50f275bd59137 100644 --- a/x-pack/plugins/ingest_manager/common/types/rest_spec/fleet_setup.ts +++ b/x-pack/plugins/ingest_manager/common/types/rest_spec/fleet_setup.ts @@ -10,5 +10,10 @@ export interface CreateFleetSetupResponse { export interface GetFleetStatusResponse { isReady: boolean; - missing_requirements: Array<'tls_required' | 'api_keys' | 'fleet_admin_user'>; + missing_requirements: Array< + | 'tls_required' + | 'api_keys' + | 'fleet_admin_user' + | 'encrypted_saved_object_encryption_key_required' + >; } diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/setup_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/setup_page/index.tsx index ffab5866f3b6f..e9c9ce0c513d2 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/setup_page/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/setup_page/index.tsx @@ -39,7 +39,9 @@ export const SetupPage: React.FunctionComponent<{ }; const content = - missingRequirements.includes('tls_required') || missingRequirements.includes('api_keys') ? ( + missingRequirements.includes('tls_required') || + missingRequirements.includes('api_keys') || + missingRequirements.includes('encrypted_saved_object_encryption_key_required') ? ( <> @@ -53,12 +55,13 @@ export const SetupPage: React.FunctionComponent<{ - + , diff --git a/x-pack/plugins/ingest_manager/server/plugin.ts b/x-pack/plugins/ingest_manager/server/plugin.ts index cd44b61974b03..0d53092a0a8ff 100644 --- a/x-pack/plugins/ingest_manager/server/plugin.ts +++ b/x-pack/plugins/ingest_manager/server/plugin.ts @@ -67,7 +67,8 @@ export interface IngestManagerSetupDeps { export type IngestManagerStartDeps = object; export interface IngestManagerAppContext { - encryptedSavedObjects: EncryptedSavedObjectsPluginStart; + encryptedSavedObjectsStart: EncryptedSavedObjectsPluginStart; + encryptedSavedObjectsSetup?: EncryptedSavedObjectsPluginSetup; security?: SecurityPluginSetup; config$?: Observable; savedObjects: SavedObjectsServiceStart; @@ -115,6 +116,7 @@ export class IngestManagerPlugin private isProductionMode: boolean; private kibanaVersion: string; private httpSetup: HttpServiceSetup | undefined; + private encryptedSavedObjectsSetup: EncryptedSavedObjectsPluginSetup | undefined; constructor(private readonly initializerContext: PluginInitializerContext) { this.config$ = this.initializerContext.config.create(); @@ -129,6 +131,7 @@ export class IngestManagerPlugin if (deps.security) { this.security = deps.security; } + this.encryptedSavedObjectsSetup = deps.encryptedSavedObjects; this.cloud = deps.cloud; registerSavedObjects(core.savedObjects); @@ -187,12 +190,22 @@ export class IngestManagerPlugin } if (config.fleet.enabled) { - registerAgentRoutes(router); - registerEnrollmentApiKeyRoutes(router); - registerInstallScriptRoutes({ - router, - basePath: core.http.basePath, - }); + const isESOUsingEphemeralEncryptionKey = + deps.encryptedSavedObjects.usingEphemeralEncryptionKey; + if (isESOUsingEphemeralEncryptionKey) { + if (this.logger) { + this.logger.warn( + 'Fleet APIs are disabled due to the Encrypted Saved Objects plugin using an ephemeral encryption key. Please set xpack.encryptedSavedObjects.encryptionKey in kibana.yml.' + ); + } + } else { + registerAgentRoutes(router); + registerEnrollmentApiKeyRoutes(router); + registerInstallScriptRoutes({ + router, + basePath: core.http.basePath, + }); + } } } } @@ -204,7 +217,8 @@ export class IngestManagerPlugin } ) { appContextService.start({ - encryptedSavedObjects: plugins.encryptedSavedObjects, + encryptedSavedObjectsStart: plugins.encryptedSavedObjects, + encryptedSavedObjectsSetup: this.encryptedSavedObjectsSetup, security: this.security, config$: this.config$, savedObjects: core.savedObjects, diff --git a/x-pack/plugins/ingest_manager/server/routes/setup/handlers.ts b/x-pack/plugins/ingest_manager/server/routes/setup/handlers.ts index 30eb6c0ae8caa..9808343417390 100644 --- a/x-pack/plugins/ingest_manager/server/routes/setup/handlers.ts +++ b/x-pack/plugins/ingest_manager/server/routes/setup/handlers.ts @@ -20,6 +20,8 @@ export const getFleetStatusHandler: RequestHandler = async (context, request, re const isProductionMode = appContextService.getIsProductionMode(); const isCloud = appContextService.getCloud()?.isCloudEnabled ?? false; const isTLSCheckDisabled = appContextService.getConfig()?.fleet?.tlsCheckDisabled ?? false; + const isUsingEphemeralEncryptionKey = appContextService.getEncryptedSavedObjectsSetup() + .usingEphemeralEncryptionKey; const missingRequirements: GetFleetStatusResponse['missing_requirements'] = []; if (!isAdminUserSetup) { @@ -32,6 +34,10 @@ export const getFleetStatusHandler: RequestHandler = async (context, request, re missingRequirements.push('tls_required'); } + if (isUsingEphemeralEncryptionKey) { + missingRequirements.push('encrypted_saved_object_encryption_key_required'); + } + const body: GetFleetStatusResponse = { isReady: missingRequirements.length === 0, missing_requirements: missingRequirements, diff --git a/x-pack/plugins/ingest_manager/server/services/agents/acks.test.ts b/x-pack/plugins/ingest_manager/server/services/agents/acks.test.ts index 0d22529fdb031..efdcbdb5c36bb 100644 --- a/x-pack/plugins/ingest_manager/server/services/agents/acks.test.ts +++ b/x-pack/plugins/ingest_manager/server/services/agents/acks.test.ts @@ -24,7 +24,7 @@ describe('test agent acks services', () => { const mockSavedObjectsClient = savedObjectsClientMock.create(); const mockStartEncryptedSOPlugin = encryptedSavedObjectsMock.createStart(); appContextService.start(({ - encryptedSavedObjects: mockStartEncryptedSOPlugin, + encryptedSavedObjectsStart: mockStartEncryptedSOPlugin, } as unknown) as IngestManagerAppContext); const [ diff --git a/x-pack/plugins/ingest_manager/server/services/app_context.ts b/x-pack/plugins/ingest_manager/server/services/app_context.ts index 9e6220b6958f1..81a16caa8ce9e 100644 --- a/x-pack/plugins/ingest_manager/server/services/app_context.ts +++ b/x-pack/plugins/ingest_manager/server/services/app_context.ts @@ -6,7 +6,10 @@ import { BehaviorSubject, Observable } from 'rxjs'; import { first } from 'rxjs/operators'; import { SavedObjectsServiceStart, HttpServiceSetup, Logger } from 'src/core/server'; -import { EncryptedSavedObjectsClient } from '../../../encrypted_saved_objects/server'; +import { + EncryptedSavedObjectsClient, + EncryptedSavedObjectsPluginSetup, +} from '../../../encrypted_saved_objects/server'; import { SecurityPluginSetup } from '../../../security/server'; import { IngestManagerConfigType } from '../../common'; import { IngestManagerAppContext } from '../plugin'; @@ -14,6 +17,7 @@ import { CloudSetup } from '../../../cloud/server'; class AppContextService { private encryptedSavedObjects: EncryptedSavedObjectsClient | undefined; + private encryptedSavedObjectsSetup: EncryptedSavedObjectsPluginSetup | undefined; private security: SecurityPluginSetup | undefined; private config$?: Observable; private configSubject$?: BehaviorSubject; @@ -25,7 +29,8 @@ class AppContextService { private httpSetup?: HttpServiceSetup; public async start(appContext: IngestManagerAppContext) { - this.encryptedSavedObjects = appContext.encryptedSavedObjects?.getClient(); + this.encryptedSavedObjects = appContext.encryptedSavedObjectsStart?.getClient(); + this.encryptedSavedObjectsSetup = appContext.encryptedSavedObjectsSetup; this.security = appContext.security; this.savedObjects = appContext.savedObjects; this.isProductionMode = appContext.isProductionMode; @@ -95,6 +100,14 @@ class AppContextService { return this.httpSetup; } + public getEncryptedSavedObjectsSetup() { + if (!this.encryptedSavedObjectsSetup) { + throw new Error('encryptedSavedObjectsSetup is not set'); + } + + return this.encryptedSavedObjectsSetup; + } + public getKibanaVersion() { if (!this.kibanaVersion) { throw new Error('Kibana version is not set.'); diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index d119ddb5a1a1f..37cdbf5c0d8a9 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -4229,6 +4229,7 @@ "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 240baa3fe7744..2dfa0d40b9a8a 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -4232,6 +4232,7 @@ "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": "此功能当前为公测版。如果遇到任何错误或有任何反馈,请报告问题或访问我们的论坛。",