mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[UX Dashboard] Remove search url query from APM server (#132654)
* Migrate service list query out of APM. * Rename non-snakecase files. * Migrate UX search filter input query out of APM server. * Fix bug that could cause incorrect loading state to show. * Remove obsolete API tests. * Delete obsolete API tests. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
591aa648d6
commit
a15e5ddea9
7 changed files with 71 additions and 192 deletions
|
@ -14,7 +14,6 @@ import { getLongTaskMetrics } from './get_long_task_metrics';
|
|||
import { getPageLoadDistribution } from './get_page_load_distribution';
|
||||
import { getPageViewTrends } from './get_page_view_trends';
|
||||
import { getPageLoadDistBreakdown } from './get_pl_dist_breakdown';
|
||||
import { getUrlSearch } from './get_url_search';
|
||||
import { getVisitorBreakdown } from './get_visitor_breakdown';
|
||||
import { getWebCoreVitals } from './get_web_core_vitals';
|
||||
import { hasRumData } from './has_rum_data';
|
||||
|
@ -280,34 +279,6 @@ const rumLongTaskMetrics = createApmServerRoute({
|
|||
},
|
||||
});
|
||||
|
||||
const rumUrlSearch = createApmServerRoute({
|
||||
endpoint: 'GET /internal/apm/ux/url-search',
|
||||
params: t.type({
|
||||
query: uxQueryRt,
|
||||
}),
|
||||
options: { tags: ['access:apm'] },
|
||||
handler: async (
|
||||
resources
|
||||
): Promise<{
|
||||
total: number;
|
||||
items: Array<{ url: string; count: number; pld: number }>;
|
||||
}> => {
|
||||
const setup = await setupUXRequest(resources);
|
||||
|
||||
const {
|
||||
query: { urlQuery, percentile, start, end },
|
||||
} = resources.params;
|
||||
|
||||
return getUrlSearch({
|
||||
setup,
|
||||
urlQuery,
|
||||
percentile: Number(percentile),
|
||||
start,
|
||||
end,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const rumJSErrors = createApmServerRoute({
|
||||
endpoint: 'GET /internal/apm/ux/js-errors',
|
||||
params: t.type({
|
||||
|
@ -412,7 +383,6 @@ export const rumRouteRepository = {
|
|||
...rumVisitorsBreakdownRoute,
|
||||
...rumWebCoreVitals,
|
||||
...rumLongTaskMetrics,
|
||||
...rumUrlSearch,
|
||||
...rumJSErrors,
|
||||
...rumHasDataRoute,
|
||||
};
|
||||
|
|
|
@ -6,20 +6,12 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import datemath from '@kbn/datemath';
|
||||
import { useEsSearch } from '@kbn/observability-plugin/public';
|
||||
import { serviceNameQuery } from '../../../../services/data/service_name_query';
|
||||
import { ServiceNameFilter } from '../url_filter/service_name_filter';
|
||||
import { useLegacyUrlParams } from '../../../../context/url_params_context/use_url_params';
|
||||
import { useDataView } from '../local_uifilters/use_data_view';
|
||||
|
||||
function callDateMath(value: unknown): number {
|
||||
const DEFAULT_RETURN_VALUE = 0;
|
||||
if (typeof value === 'string') {
|
||||
return datemath.parse(value)?.valueOf() ?? DEFAULT_RETURN_VALUE;
|
||||
}
|
||||
return DEFAULT_RETURN_VALUE;
|
||||
}
|
||||
import { callDateMath } from '../../../../services/data/call_date_math';
|
||||
|
||||
export function WebApplicationSelect() {
|
||||
const {
|
||||
|
@ -42,6 +34,9 @@ export function WebApplicationSelect() {
|
|||
data?.aggregations?.services?.buckets.map(({ key }) => key as string) ?? [];
|
||||
|
||||
return (
|
||||
<ServiceNameFilter loading={!!loading} serviceNames={rumServiceNames} />
|
||||
<ServiceNameFilter
|
||||
loading={loading ?? true}
|
||||
serviceNames={rumServiceNames}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ export function URLSearch({
|
|||
|
||||
const [items, setItems] = useState<UrlOption[]>([]);
|
||||
|
||||
const { data, status } = useUrlSearch({ query: searchValue, popoverIsOpen });
|
||||
const { data, loading } = useUrlSearch({ query: searchValue, popoverIsOpen });
|
||||
|
||||
useEffect(() => {
|
||||
const newItems = formatOptions(
|
||||
|
@ -151,8 +151,6 @@ export function URLSearch({
|
|||
setSearchValue(val);
|
||||
};
|
||||
|
||||
const isLoading = status !== 'success';
|
||||
|
||||
const onApply = () => {
|
||||
const { includedItems, excludedItems } = processItems(items);
|
||||
|
||||
|
@ -184,7 +182,7 @@ export function URLSearch({
|
|||
|
||||
return (
|
||||
<SelectableUrlList
|
||||
loading={isLoading}
|
||||
loading={loading ?? true}
|
||||
onInputChange={onInputChange}
|
||||
data={{ items, total: data?.total ?? 0 }}
|
||||
onSelectionChange={onChange}
|
||||
|
|
|
@ -6,10 +6,12 @@
|
|||
*/
|
||||
|
||||
import useDebounce from 'react-use/lib/useDebounce';
|
||||
import { useState } from 'react';
|
||||
import { useFetcher } from '../../../../../hooks/use_fetcher';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useEsSearch } from '@kbn/observability-plugin/public';
|
||||
import { useUxQuery } from '../../hooks/use_ux_query';
|
||||
import { useLegacyUrlParams } from '../../../../../context/url_params_context/use_url_params';
|
||||
import { useDataView } from '../../local_uifilters/use_data_view';
|
||||
import { urlSearchQuery } from '../../../../../services/data/url_search_query';
|
||||
|
||||
interface Props {
|
||||
popoverIsOpen: boolean;
|
||||
|
@ -34,22 +36,33 @@ export const useUrlSearch = ({ popoverIsOpen, query }: Props) => {
|
|||
[query]
|
||||
);
|
||||
|
||||
return useFetcher(
|
||||
(callApmApi) => {
|
||||
if (uxQuery && popoverIsOpen) {
|
||||
return callApmApi('GET /internal/apm/ux/url-search', {
|
||||
params: {
|
||||
query: {
|
||||
...uxQuery,
|
||||
uiFilters: JSON.stringify(restFilters),
|
||||
urlQuery: searchValue,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
return Promise.resolve(null);
|
||||
const { dataViewTitle } = useDataView();
|
||||
const { data: asyncSearchResult, loading } = useEsSearch(
|
||||
{
|
||||
// when `index` is undefined, the hook will not send a request,
|
||||
// so we pass this to ensure the search values load lazily
|
||||
index: uxQuery && popoverIsOpen ? dataViewTitle : undefined,
|
||||
...urlSearchQuery(restFilters, uxQuery, searchValue),
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[uxQuery, searchValue, popoverIsOpen]
|
||||
[dataViewTitle, popoverIsOpen, uxQuery, searchValue],
|
||||
{ name: 'UX_URL_SEARCH' }
|
||||
);
|
||||
|
||||
const data = useMemo(() => {
|
||||
if (!asyncSearchResult) return asyncSearchResult;
|
||||
const { urls, totalUrls } = asyncSearchResult.aggregations ?? {};
|
||||
|
||||
const pkey = Number(uxQuery?.percentile ?? 0).toFixed(1);
|
||||
|
||||
return {
|
||||
total: totalUrls?.value || 0,
|
||||
items: (urls?.buckets ?? []).map((bucket) => ({
|
||||
url: bucket.key as string,
|
||||
count: bucket.doc_count,
|
||||
pld: bucket.medianPLD.values[pkey] ?? 0,
|
||||
})),
|
||||
};
|
||||
}, [asyncSearchResult, uxQuery?.percentile]);
|
||||
|
||||
return { data, loading };
|
||||
};
|
||||
|
|
16
x-pack/plugins/ux/public/services/data/call_date_math.ts
Normal file
16
x-pack/plugins/ux/public/services/data/call_date_math.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import datemath from '@kbn/datemath';
|
||||
|
||||
export function callDateMath(value: unknown): number {
|
||||
const DEFAULT_RETURN_VALUE = 0;
|
||||
if (typeof value === 'string') {
|
||||
return datemath.parse(value)?.valueOf() ?? DEFAULT_RETURN_VALUE;
|
||||
}
|
||||
return DEFAULT_RETURN_VALUE;
|
||||
}
|
|
@ -5,34 +5,28 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { mergeProjection } from '../../projections/util/merge_projection';
|
||||
import { SetupUX } from './route';
|
||||
import { getRumPageLoadTransactionsProjection } from '../../projections/rum_page_load_transactions';
|
||||
import {
|
||||
TRANSACTION_DURATION,
|
||||
TRANSACTION_URL,
|
||||
} from '../../../common/elasticsearch_fieldnames';
|
||||
import { SetupUX } from '../../../typings/ui_filters';
|
||||
import { getRumPageLoadTransactionsProjection } from './projections';
|
||||
import { callDateMath } from './call_date_math';
|
||||
import { mergeProjection } from '../../../common/utils/merge_projection';
|
||||
|
||||
export async function getUrlSearch({
|
||||
setup,
|
||||
urlQuery,
|
||||
percentile,
|
||||
start,
|
||||
end,
|
||||
}: {
|
||||
setup: SetupUX;
|
||||
urlQuery?: string;
|
||||
percentile: number;
|
||||
start: number;
|
||||
end: number;
|
||||
}) {
|
||||
export function urlSearchQuery(
|
||||
restFilters: any,
|
||||
uxQuery: any,
|
||||
searchValue: string
|
||||
) {
|
||||
const setup: SetupUX = { uiFilters: restFilters ? restFilters : {} };
|
||||
const projection = getRumPageLoadTransactionsProjection({
|
||||
setup,
|
||||
urlQuery,
|
||||
start,
|
||||
end,
|
||||
urlQuery: searchValue,
|
||||
...uxQuery,
|
||||
start: callDateMath(uxQuery?.start),
|
||||
end: callDateMath(uxQuery?.end),
|
||||
});
|
||||
|
||||
const params = mergeProjection(projection, {
|
||||
body: {
|
||||
size: 0,
|
||||
|
@ -51,7 +45,7 @@ export async function getUrlSearch({
|
|||
medianPLD: {
|
||||
percentiles: {
|
||||
field: TRANSACTION_DURATION,
|
||||
percents: [percentile],
|
||||
percents: [Number(uxQuery?.percentile)],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -59,20 +53,6 @@ export async function getUrlSearch({
|
|||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { apmEventClient } = setup;
|
||||
|
||||
const response = await apmEventClient.search('get_url_search', params);
|
||||
const { urls, totalUrls } = response.aggregations ?? {};
|
||||
|
||||
const pkey = percentile.toFixed(1);
|
||||
|
||||
return {
|
||||
total: totalUrls?.value || 0,
|
||||
items: (urls?.buckets ?? []).map((bucket) => ({
|
||||
url: bucket.key as string,
|
||||
count: bucket.doc_count,
|
||||
pld: bucket.medianPLD.values[pkey] ?? 0,
|
||||
})),
|
||||
};
|
||||
const { apm: _apm, ...rest } = params;
|
||||
return rest;
|
||||
}
|
|
@ -1,93 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { FtrProviderContext } from '../../common/ftr_provider_context';
|
||||
|
||||
export default function rumServicesApiTests({ getService }: FtrProviderContext) {
|
||||
const registry = getService('registry');
|
||||
const supertest = getService('legacySupertestAsApmReadUser');
|
||||
|
||||
registry.when('CSM url search api without data', { config: 'trial', archives: [] }, () => {
|
||||
it('returns empty list', async () => {
|
||||
const response = await supertest.get('/internal/apm/ux/url-search').query({
|
||||
start: '2020-09-07T20:35:54.654Z',
|
||||
end: '2020-09-14T20:35:54.654Z',
|
||||
uiFilters: '{"serviceName":["elastic-co-rum-test"]}',
|
||||
percentile: 50,
|
||||
});
|
||||
|
||||
expect(response.status).to.be(200);
|
||||
expectSnapshot(response.body).toMatchInline(`
|
||||
Object {
|
||||
"items": Array [],
|
||||
"total": 0,
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
registry.when(
|
||||
'CSM url search api with data',
|
||||
{ config: 'trial', archives: ['8.0.0', 'rum_8.0.0'] },
|
||||
() => {
|
||||
it('returns top urls when no query', async () => {
|
||||
const response = await supertest.get('/internal/apm/ux/url-search').query({
|
||||
start: '2020-09-07T20:35:54.654Z',
|
||||
end: '2020-09-16T20:35:54.654Z',
|
||||
uiFilters: '{"serviceName":["kibana-frontend-8_0_0"]}',
|
||||
percentile: 50,
|
||||
});
|
||||
|
||||
expect(response.status).to.be(200);
|
||||
|
||||
expectSnapshot(response.body).toMatchInline(`
|
||||
Object {
|
||||
"items": Array [
|
||||
Object {
|
||||
"count": 5,
|
||||
"pld": 4924000,
|
||||
"url": "http://localhost:5601/nfw/app/csm?rangeFrom=now-15m&rangeTo=now&serviceName=kibana-frontend-8_0_0",
|
||||
},
|
||||
Object {
|
||||
"count": 1,
|
||||
"pld": 2760000,
|
||||
"url": "http://localhost:5601/nfw/app/home",
|
||||
},
|
||||
],
|
||||
"total": 2,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('returns specific results against query', async () => {
|
||||
const response = await supertest.get('/internal/apm/ux/url-search').query({
|
||||
start: '2020-09-07T20:35:54.654Z',
|
||||
end: '2020-09-16T20:35:54.654Z',
|
||||
uiFilters: '{"serviceName":["kibana-frontend-8_0_0"]}',
|
||||
urlQuery: 'csm',
|
||||
percentile: 50,
|
||||
});
|
||||
|
||||
expect(response.status).to.be(200);
|
||||
|
||||
expectSnapshot(response.body).toMatchInline(`
|
||||
Object {
|
||||
"items": Array [
|
||||
Object {
|
||||
"count": 5,
|
||||
"pld": 4924000,
|
||||
"url": "http://localhost:5601/nfw/app/csm?rangeFrom=now-15m&rangeTo=now&serviceName=kibana-frontend-8_0_0",
|
||||
},
|
||||
],
|
||||
"total": 1,
|
||||
}
|
||||
`);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue