From dba72d541326dd7d8d039a83e9e80df718f13614 Mon Sep 17 00:00:00 2001 From: Dario Gieselaar Date: Wed, 5 Oct 2022 15:03:18 +0200 Subject: [PATCH 1/4] [Profiling] Auto-abort requests --- .../components/flame_graphs_view/index.tsx | 64 ++++++++++--------- .../public/components/flamegraph.tsx | 24 +++---- .../components/functions_view/index.tsx | 50 +++++++++------ .../components/stack_traces_view/index.tsx | 48 +++++++------- .../profiling/public/hooks/use_async.ts | 56 ++++++++++++++-- x-pack/plugins/profiling/public/plugin.tsx | 2 +- x-pack/plugins/profiling/public/services.ts | 52 +++++---------- .../utils/create_profiling_es_client.ts | 1 + 8 files changed, 171 insertions(+), 126 deletions(-) diff --git a/x-pack/plugins/profiling/public/components/flame_graphs_view/index.tsx b/x-pack/plugins/profiling/public/components/flame_graphs_view/index.tsx index 6a8802599f6cc..dab912902ba46 100644 --- a/x-pack/plugins/profiling/public/components/flame_graphs_view/index.tsx +++ b/x-pack/plugins/profiling/public/components/flame_graphs_view/index.tsx @@ -43,35 +43,40 @@ export function FlameGraphsView({ children }: { children: React.ReactElement }) services: { fetchElasticFlamechart }, } = useProfilingDependencies(); - const state = useTimeRangeAsync(() => { - return Promise.all([ - fetchElasticFlamechart({ - timeFrom: new Date(timeRange.start).getTime() / 1000, - timeTo: new Date(timeRange.end).getTime() / 1000, - kuery, - }), - comparisonTimeRange.start && comparisonTimeRange.end - ? fetchElasticFlamechart({ - timeFrom: new Date(comparisonTimeRange.start).getTime() / 1000, - timeTo: new Date(comparisonTimeRange.end).getTime() / 1000, - kuery: comparisonKuery, - }) - : Promise.resolve(undefined), - ]).then(([primaryFlamegraph, comparisonFlamegraph]) => { - return { - primaryFlamegraph, - comparisonFlamegraph, - }; - }); - }, [ - timeRange.start, - timeRange.end, - kuery, - comparisonTimeRange.start, - comparisonTimeRange.end, - comparisonKuery, - fetchElasticFlamechart, - ]); + const state = useTimeRangeAsync( + ({ http }) => { + return Promise.all([ + fetchElasticFlamechart({ + http, + timeFrom: new Date(timeRange.start).getTime() / 1000, + timeTo: new Date(timeRange.end).getTime() / 1000, + kuery, + }), + comparisonTimeRange.start && comparisonTimeRange.end + ? fetchElasticFlamechart({ + http, + timeFrom: new Date(comparisonTimeRange.start).getTime() / 1000, + timeTo: new Date(comparisonTimeRange.end).getTime() / 1000, + kuery: comparisonKuery, + }) + : Promise.resolve(undefined), + ]).then(([primaryFlamegraph, comparisonFlamegraph]) => { + return { + primaryFlamegraph, + comparisonFlamegraph, + }; + }); + }, + [ + timeRange.start, + timeRange.end, + kuery, + comparisonTimeRange.start, + comparisonTimeRange.end, + comparisonKuery, + fetchElasticFlamechart, + ] + ); const { data } = state; @@ -173,7 +178,6 @@ export function FlameGraphsView({ children }: { children: React.ReactElement }) = ({ id, - height, comparisonMode, primaryFlamegraph, comparisonFlamegraph, @@ -207,16 +205,20 @@ export const FlameGraph: React.FC = ({ }; }, [primaryFlamegraph, highlightedVmIndex]); - const { data: highlightedFrame, status: highlightedFrameStatus } = useAsync(() => { - if (!highlightedFrameQueryParams) { - return Promise.resolve(undefined); - } + const { data: highlightedFrame, status: highlightedFrameStatus } = useAsync( + ({ http }) => { + if (!highlightedFrameQueryParams) { + return Promise.resolve(undefined); + } - return fetchFrameInformation({ - frameID: highlightedFrameQueryParams.frameID, - executableID: highlightedFrameQueryParams.executableID, - }); - }, [highlightedFrameQueryParams, fetchFrameInformation]); + return fetchFrameInformation({ + http, + frameID: highlightedFrameQueryParams.frameID, + executableID: highlightedFrameQueryParams.executableID, + }); + }, + [highlightedFrameQueryParams, fetchFrameInformation] + ); const selected: undefined | React.ComponentProps['frame'] = primaryFlamegraph && highlightedFrame && highlightedVmIndex !== undefined diff --git a/x-pack/plugins/profiling/public/components/functions_view/index.tsx b/x-pack/plugins/profiling/public/components/functions_view/index.tsx index 94410f961c469..2c7b25754f3d9 100644 --- a/x-pack/plugins/profiling/public/components/functions_view/index.tsx +++ b/x-pack/plugins/profiling/public/components/functions_view/index.tsx @@ -42,28 +42,36 @@ export function FunctionsView({ children }: { children: React.ReactElement }) { services: { fetchTopNFunctions }, } = useProfilingDependencies(); - const state = useTimeRangeAsync(() => { - return fetchTopNFunctions({ - timeFrom: new Date(timeRange.start).getTime() / 1000, - timeTo: new Date(timeRange.end).getTime() / 1000, - startIndex: 0, - endIndex: 1000, - kuery, - }); - }, [timeRange.start, timeRange.end, kuery, fetchTopNFunctions]); + const state = useTimeRangeAsync( + ({ http }) => { + return fetchTopNFunctions({ + http, + timeFrom: new Date(timeRange.start).getTime() / 1000, + timeTo: new Date(timeRange.end).getTime() / 1000, + startIndex: 0, + endIndex: 1000, + kuery, + }); + }, + [timeRange.start, timeRange.end, kuery, fetchTopNFunctions] + ); - const comparisonState = useTimeRangeAsync(() => { - if (!comparisonTimeRange.start || !comparisonTimeRange.end) { - return undefined; - } - return fetchTopNFunctions({ - timeFrom: new Date(comparisonTimeRange.start).getTime() / 1000, - timeTo: new Date(comparisonTimeRange.end).getTime() / 1000, - startIndex: 0, - endIndex: 1000, - kuery: comparisonKuery, - }); - }, [comparisonTimeRange.start, comparisonTimeRange.end, comparisonKuery, fetchTopNFunctions]); + const comparisonState = useTimeRangeAsync( + ({ http }) => { + if (!comparisonTimeRange.start || !comparisonTimeRange.end) { + return undefined; + } + return fetchTopNFunctions({ + http, + timeFrom: new Date(comparisonTimeRange.start).getTime() / 1000, + timeTo: new Date(comparisonTimeRange.end).getTime() / 1000, + startIndex: 0, + endIndex: 1000, + kuery: comparisonKuery, + }); + }, + [comparisonTimeRange.start, comparisonTimeRange.end, comparisonKuery, fetchTopNFunctions] + ); const routePath = useProfilingRoutePath() as | '/functions' diff --git a/x-pack/plugins/profiling/public/components/stack_traces_view/index.tsx b/x-pack/plugins/profiling/public/components/stack_traces_view/index.tsx index 23bb4a7bd4b6f..19834410c6b7a 100644 --- a/x-pack/plugins/profiling/public/components/stack_traces_view/index.tsx +++ b/x-pack/plugins/profiling/public/components/stack_traces_view/index.tsx @@ -50,29 +50,33 @@ export function StackTracesView() { rangeTo, }); - const state = useTimeRangeAsync(() => { - if (!topNType) { - return Promise.resolve({ charts: [], metadata: {} }); - } - return fetchTopN({ - type: topNType, - timeFrom: new Date(timeRange.start).getTime() / 1000, - timeTo: new Date(timeRange.end).getTime() / 1000, - kuery, - }).then((response: TopNResponse) => { - const totalCount = response.TotalCount; - const samples = response.TopN; - const charts = groupSamplesByCategory({ - samples, - totalCount, - metadata: response.Metadata, - labels: response.Labels, + const state = useTimeRangeAsync( + ({ http }) => { + if (!topNType) { + return Promise.resolve({ charts: [], metadata: {} }); + } + return fetchTopN({ + http, + type: topNType, + timeFrom: new Date(timeRange.start).getTime() / 1000, + timeTo: new Date(timeRange.end).getTime() / 1000, + kuery, + }).then((response: TopNResponse) => { + const totalCount = response.TotalCount; + const samples = response.TopN; + const charts = groupSamplesByCategory({ + samples, + totalCount, + metadata: response.Metadata, + labels: response.Labels, + }); + return { + charts, + }; }); - return { - charts, - }; - }); - }, [topNType, timeRange.start, timeRange.end, fetchTopN, kuery]); + }, + [topNType, timeRange.start, timeRange.end, fetchTopN, kuery] + ); const [highlightedSubchart, setHighlightedSubchart] = useState( undefined diff --git a/x-pack/plugins/profiling/public/hooks/use_async.ts b/x-pack/plugins/profiling/public/hooks/use_async.ts index ea6da578c3879..6a8c29cd02e88 100644 --- a/x-pack/plugins/profiling/public/hooks/use_async.ts +++ b/x-pack/plugins/profiling/public/hooks/use_async.ts @@ -4,8 +4,10 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { HttpStart } from '@kbn/core-http-browser'; -import { useEffect, useState } from 'react'; +import { HttpFetchOptions, HttpHandler, HttpStart, isHttpFetchError } from '@kbn/core-http-browser'; +import { useEffect, useRef, useState } from 'react'; +import { Overwrite, ValuesType } from 'utility-types'; +import { AbortError } from '@kbn/kibana-utils-plugin/common'; import { useProfilingDependencies } from '../components/contexts/profiling_dependencies/use_profiling_dependencies'; export enum AsyncStatus { @@ -20,8 +22,22 @@ export interface AsyncState { status: AsyncStatus; } +const HTTP_METHODS = ['fetch', 'get', 'post', 'put', 'delete', 'patch'] as const; + +type HttpMethod = ValuesType; + +type AutoAbortedHttpMethod = ( + path: string, + options: Omit +) => ReturnType; + +export type AutoAbortedHttpService = Overwrite< + HttpStart, + Record +>; + export type UseAsync = ( - fn: ({ http }: { http: HttpStart }) => Promise | undefined, + fn: ({ http }: { http: AutoAbortedHttpService }) => Promise | undefined, dependencies: any[] ) => AsyncState; @@ -37,8 +53,30 @@ export const useAsync: UseAsync = (fn, dependencies) => { const { data, error } = asyncState; + const controllerRef = useRef(new AbortController()); + useEffect(() => { - const returnValue = fn({ http }); + controllerRef.current.abort(); + + controllerRef.current = new AbortController(); + + const autoAbortedMethods = {} as Record; + + for (const key of HTTP_METHODS) { + autoAbortedMethods[key] = (path, options) => { + return http[key](path, { ...options, signal: controllerRef.current.signal }).catch( + (err) => { + if (err.name === 'AbortError') { + // return never-resolving promise + return new Promise(() => {}); + } + throw err; + } + ); + }; + } + + const returnValue = fn({ http: { ...http, ...autoAbortedMethods } }); if (returnValue === undefined) { setAsyncState({ @@ -63,13 +101,23 @@ export const useAsync: UseAsync = (fn, dependencies) => { }); returnValue.catch((nextError) => { + if (nextError instanceof AbortError) { + return; + } setAsyncState({ status: AsyncStatus.Settled, error: nextError, }); + throw nextError; }); // eslint-disable-next-line react-hooks/exhaustive-deps }, [http, ...dependencies]); + useEffect(() => { + return () => { + controllerRef.current.abort(); + }; + }, []); + return asyncState; }; diff --git a/x-pack/plugins/profiling/public/plugin.tsx b/x-pack/plugins/profiling/public/plugin.tsx index 080941729b014..ead023a079e29 100644 --- a/x-pack/plugins/profiling/public/plugin.tsx +++ b/x-pack/plugins/profiling/public/plugin.tsx @@ -90,7 +90,7 @@ export class ProfilingPlugin implements Plugin { unknown ]; - const profilingFetchServices = getServices(coreStart); + const profilingFetchServices = getServices(); const { renderApp } = await import('./app'); function pushKueryToSubject(location: Location) { diff --git a/x-pack/plugins/profiling/public/services.ts b/x-pack/plugins/profiling/public/services.ts index 07234ca124b36..48f56e0a90d51 100644 --- a/x-pack/plugins/profiling/public/services.ts +++ b/x-pack/plugins/profiling/public/services.ts @@ -4,22 +4,24 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -import { CoreStart, HttpFetchQuery } from '@kbn/core/public'; +import { HttpFetchQuery } from '@kbn/core/public'; import { getRoutePaths } from '../common'; import { ElasticFlameGraph } from '../common/flamegraph'; import { TopNFunctions } from '../common/functions'; import { StackFrameMetadata } from '../common/profiling'; import { TopNResponse } from '../common/topn'; +import { AutoAbortedHttpService } from './hooks/use_async'; export interface Services { fetchTopN: (params: { + http: AutoAbortedHttpService; type: string; timeFrom: number; timeTo: number; kuery: string; }) => Promise; fetchTopNFunctions: (params: { + http: AutoAbortedHttpService; timeFrom: number; timeTo: number; startIndex: number; @@ -27,46 +29,36 @@ export interface Services { kuery: string; }) => Promise; fetchElasticFlamechart: (params: { + http: AutoAbortedHttpService; timeFrom: number; timeTo: number; kuery: string; }) => Promise; fetchFrameInformation: (params: { + http: AutoAbortedHttpService; frameID: string; executableID: string; }) => Promise; } -export function getServices(core: CoreStart): Services { +export function getServices(): Services { const paths = getRoutePaths(); return { - fetchTopN: async ({ type, timeFrom, timeTo, kuery }) => { + fetchTopN: async ({ http, type, timeFrom, timeTo, kuery }) => { try { const query: HttpFetchQuery = { timeFrom, timeTo, kuery, }; - return await core.http.get(`${paths.TopN}/${type}`, { query }); + return await http.get(`${paths.TopN}/${type}`, { query }); } catch (e) { return e; } }, - fetchTopNFunctions: async ({ - timeFrom, - timeTo, - startIndex, - endIndex, - kuery, - }: { - timeFrom: number; - timeTo: number; - startIndex: number; - endIndex: number; - kuery: string; - }) => { + fetchTopNFunctions: async ({ http, timeFrom, timeTo, startIndex, endIndex, kuery }) => { try { const query: HttpFetchQuery = { timeFrom, @@ -75,45 +67,31 @@ export function getServices(core: CoreStart): Services { endIndex, kuery, }; - return await core.http.get(paths.TopNFunctions, { query }); + return await http.get(paths.TopNFunctions, { query }); } catch (e) { return e; } }, - fetchElasticFlamechart: async ({ - timeFrom, - timeTo, - kuery, - }: { - timeFrom: number; - timeTo: number; - kuery: string; - }) => { + fetchElasticFlamechart: async ({ http, timeFrom, timeTo, kuery }) => { try { const query: HttpFetchQuery = { timeFrom, timeTo, kuery, }; - return await core.http.get(paths.Flamechart, { query }); + return await http.get(paths.Flamechart, { query }); } catch (e) { return e; } }, - fetchFrameInformation: async ({ - frameID, - executableID, - }: { - frameID: string; - executableID: string; - }) => { + fetchFrameInformation: async ({ http, frameID, executableID }) => { try { const query: HttpFetchQuery = { frameID, executableID, }; - return await core.http.get(paths.FrameInformation, { query }); + return await http.get(paths.FrameInformation, { query }); } catch (e) { return e; } diff --git a/x-pack/plugins/profiling/server/utils/create_profiling_es_client.ts b/x-pack/plugins/profiling/server/utils/create_profiling_es_client.ts index 71116bd8c643b..c30274554df05 100644 --- a/x-pack/plugins/profiling/server/utils/create_profiling_es_client.ts +++ b/x-pack/plugins/profiling/server/utils/create_profiling_es_client.ts @@ -20,6 +20,7 @@ export function cancelEsRequestOnAbort>( ): T { const subscription = request.events.aborted$.subscribe(() => { controller.abort(); + console.log('Aborted ES request'); }); return promise.finally(() => subscription.unsubscribe()) as T; From 3469b1b42c51fe536f22fa80aa7caadafe2f05b3 Mon Sep 17 00:00:00 2001 From: Dario Gieselaar Date: Thu, 29 Sep 2022 11:41:57 +0200 Subject: [PATCH 2/4] [Profiling] Configurable ES client --- x-pack/plugins/profiling/server/index.ts | 9 +- x-pack/plugins/profiling/server/plugin.ts | 27 ++++- .../profiling/server/routes/flamechart.ts | 7 +- .../plugins/profiling/server/routes/frames.ts | 8 +- .../profiling/server/routes/functions.ts | 7 +- .../plugins/profiling/server/routes/index.ts | 9 ++ .../plugins/profiling/server/routes/topn.ts | 114 ++++++++---------- 7 files changed, 106 insertions(+), 75 deletions(-) diff --git a/x-pack/plugins/profiling/server/index.ts b/x-pack/plugins/profiling/server/index.ts index 26858b770b736..2632f8c9ebaf7 100644 --- a/x-pack/plugins/profiling/server/index.ts +++ b/x-pack/plugins/profiling/server/index.ts @@ -11,9 +11,16 @@ import { ProfilingPlugin } from './plugin'; const configSchema = schema.object({ enabled: schema.boolean({ defaultValue: false }), + elasticsearch: schema.maybe( + schema.object({ + hosts: schema.string(), + username: schema.string(), + password: schema.string(), + }) + ), }); -type ProfilingConfig = TypeOf; +export type ProfilingConfig = TypeOf; // plugin config export const config: PluginConfigDescriptor = { diff --git a/x-pack/plugins/profiling/server/plugin.ts b/x-pack/plugins/profiling/server/plugin.ts index 40071b54c0c4e..923f87a87267d 100644 --- a/x-pack/plugins/profiling/server/plugin.ts +++ b/x-pack/plugins/profiling/server/plugin.ts @@ -6,7 +6,7 @@ */ import { CoreSetup, CoreStart, Logger, Plugin, PluginInitializerContext } from '@kbn/core/server'; - +import { ProfilingConfig } from '.'; import { PROFILING_FEATURE } from './feature'; import { registerRoutes } from './routes'; import { @@ -16,6 +16,7 @@ import { ProfilingPluginStartDeps, ProfilingRequestHandlerContext, } from './types'; +import { createProfilingEsClient } from './utils/create_profiling_es_client'; export class ProfilingPlugin implements @@ -28,7 +29,8 @@ export class ProfilingPlugin { private readonly logger: Logger; - constructor(initializerContext: PluginInitializerContext) { + constructor(private readonly initializerContext: PluginInitializerContext) { + this.initializerContext = initializerContext; this.logger = initializerContext.logger.get(); } @@ -38,7 +40,17 @@ export class ProfilingPlugin deps.features.registerKibanaFeature(PROFILING_FEATURE); - core.getStartServices().then(([_, depsStart]) => { + const config = this.initializerContext.config.get(); + + core.getStartServices().then(([coreStart, depsStart]) => { + const profilingSpecificEsClient = config.elasticsearch + ? coreStart.elasticsearch.createClient('profiling', { + hosts: [config.elasticsearch.hosts], + username: config.elasticsearch.username, + password: config.elasticsearch.password, + }) + : undefined; + registerRoutes({ router, logger: this.logger!, @@ -46,6 +58,15 @@ export class ProfilingPlugin start: depsStart, setup: deps, }, + services: { + createProfilingEsClient: ({ request, esClient: defaultEsClient }) => { + const esClient = profilingSpecificEsClient + ? profilingSpecificEsClient.asScoped(request).asInternalUser + : defaultEsClient; + + return createProfilingEsClient({ request, esClient }); + }, + }, }); }); diff --git a/x-pack/plugins/profiling/server/routes/flamechart.ts b/x-pack/plugins/profiling/server/routes/flamechart.ts index 6d27305a82c69..a24a9bab598dd 100644 --- a/x-pack/plugins/profiling/server/routes/flamechart.ts +++ b/x-pack/plugins/profiling/server/routes/flamechart.ts @@ -10,13 +10,16 @@ import { RouteRegisterParameters } from '.'; import { getRoutePaths } from '../../common'; import { createCalleeTree } from '../../common/callee'; import { createFlameGraph } from '../../common/flamegraph'; -import { createProfilingEsClient } from '../utils/create_profiling_es_client'; import { withProfilingSpan } from '../utils/with_profiling_span'; import { getClient } from './compat'; import { getExecutablesAndStackTraces } from './get_executables_and_stacktraces'; import { createCommonFilter } from './query'; -export function registerFlameChartSearchRoute({ router, logger }: RouteRegisterParameters) { +export function registerFlameChartSearchRoute({ + router, + logger, + services: { createProfilingEsClient }, +}: RouteRegisterParameters) { const paths = getRoutePaths(); router.get( { diff --git a/x-pack/plugins/profiling/server/routes/frames.ts b/x-pack/plugins/profiling/server/routes/frames.ts index 4a0ce745c7246..1d81a85108cfc 100644 --- a/x-pack/plugins/profiling/server/routes/frames.ts +++ b/x-pack/plugins/profiling/server/routes/frames.ts @@ -15,7 +15,7 @@ import { StackFrame, StackFrameMetadata, } from '../../common/profiling'; -import { createProfilingEsClient, ProfilingESClient } from '../utils/create_profiling_es_client'; +import { ProfilingESClient } from '../utils/create_profiling_es_client'; import { mgetStackFrames, mgetExecutables } from './stacktrace'; async function getFrameInformation({ @@ -57,7 +57,11 @@ async function getFrameInformation({ } export function registerFrameInformationRoute(params: RouteRegisterParameters) { - const { logger, router } = params; + const { + logger, + router, + services: { createProfilingEsClient }, + } = params; const routePaths = getRoutePaths(); diff --git a/x-pack/plugins/profiling/server/routes/functions.ts b/x-pack/plugins/profiling/server/routes/functions.ts index adbbc59003376..ed71c1c60d398 100644 --- a/x-pack/plugins/profiling/server/routes/functions.ts +++ b/x-pack/plugins/profiling/server/routes/functions.ts @@ -9,7 +9,6 @@ import { schema, TypeOf } from '@kbn/config-schema'; import { RouteRegisterParameters } from '.'; import { getRoutePaths } from '../../common'; import { createTopNFunctions } from '../../common/functions'; -import { createProfilingEsClient } from '../utils/create_profiling_es_client'; import { withProfilingSpan } from '../utils/with_profiling_span'; import { getClient } from './compat'; import { getExecutablesAndStackTraces } from './get_executables_and_stacktraces'; @@ -25,7 +24,11 @@ const querySchema = schema.object({ type QuerySchemaType = TypeOf; -export function registerTopNFunctionsSearchRoute({ router, logger }: RouteRegisterParameters) { +export function registerTopNFunctionsSearchRoute({ + router, + logger, + services: { createProfilingEsClient }, +}: RouteRegisterParameters) { const paths = getRoutePaths(); router.get( { diff --git a/x-pack/plugins/profiling/server/routes/index.ts b/x-pack/plugins/profiling/server/routes/index.ts index 6e44bf6909585..c430d98468b54 100644 --- a/x-pack/plugins/profiling/server/routes/index.ts +++ b/x-pack/plugins/profiling/server/routes/index.ts @@ -6,11 +6,14 @@ */ import type { IRouter, Logger } from '@kbn/core/server'; +import type { KibanaRequest } from '@kbn/core-http-server'; +import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import { ProfilingPluginSetupDeps, ProfilingPluginStartDeps, ProfilingRequestHandlerContext, } from '../types'; +import { ProfilingESClient } from '../utils/create_profiling_es_client'; import { registerFlameChartSearchRoute } from './flamechart'; import { registerFrameInformationRoute } from './frames'; @@ -31,6 +34,12 @@ export interface RouteRegisterParameters { start: ProfilingPluginStartDeps; setup: ProfilingPluginSetupDeps; }; + services: { + createProfilingEsClient: (params: { + request: KibanaRequest; + esClient: ElasticsearchClient; + }) => ProfilingESClient; + }; } export function registerRoutes(params: RouteRegisterParameters) { diff --git a/x-pack/plugins/profiling/server/routes/topn.ts b/x-pack/plugins/profiling/server/routes/topn.ts index 790f40049e167..2613cfa429379 100644 --- a/x-pack/plugins/profiling/server/routes/topn.ts +++ b/x-pack/plugins/profiling/server/routes/topn.ts @@ -6,7 +6,7 @@ */ import { schema } from '@kbn/config-schema'; -import type { IRouter, Logger } from '@kbn/core/server'; +import type { Logger } from '@kbn/core/server'; import { RouteRegisterParameters } from '.'; import { getRoutePaths, INDEX_EVENTS } from '../../common'; import { ProfilingESField } from '../../common/elasticsearch'; @@ -14,8 +14,7 @@ import { computeBucketWidthFromTimeRangeAndBucketCount } from '../../common/hist import { groupStackFrameMetadataByStackTrace, StackTraceID } from '../../common/profiling'; import { getFieldNameForTopNType, TopNType } from '../../common/stack_traces'; import { createTopNSamples, getTopNAggregationRequest, TopNResponse } from '../../common/topn'; -import { ProfilingRequestHandlerContext } from '../types'; -import { createProfilingEsClient, ProfilingESClient } from '../utils/create_profiling_es_client'; +import { ProfilingESClient } from '../utils/create_profiling_es_client'; import { withProfilingSpan } from '../utils/with_profiling_span'; import { getClient } from './compat'; import { findDownsampledIndex } from './downsampling'; @@ -155,13 +154,18 @@ export async function topNElasticSearchQuery({ }; } -export function queryTopNCommon( - router: IRouter, - logger: Logger, - pathName: string, - searchField: string, - highCardinality: boolean -) { +export function queryTopNCommon({ + logger, + router, + services: { createProfilingEsClient }, + pathName, + searchField, + highCardinality, +}: RouteRegisterParameters & { + pathName: string; + searchField: string; + highCardinality: boolean; +}) { router.get( { path: pathName, @@ -203,72 +207,52 @@ export function queryTopNCommon( ); } -export function registerTraceEventsTopNContainersSearchRoute({ - router, - logger, -}: RouteRegisterParameters) { +export function registerTraceEventsTopNContainersSearchRoute(parameters: RouteRegisterParameters) { const paths = getRoutePaths(); - return queryTopNCommon( - router, - logger, - paths.TopNContainers, - getFieldNameForTopNType(TopNType.Containers), - false - ); + return queryTopNCommon({ + ...parameters, + pathName: paths.TopNContainers, + searchField: getFieldNameForTopNType(TopNType.Containers), + highCardinality: false, + }); } -export function registerTraceEventsTopNDeploymentsSearchRoute({ - router, - logger, -}: RouteRegisterParameters) { +export function registerTraceEventsTopNDeploymentsSearchRoute(parameters: RouteRegisterParameters) { const paths = getRoutePaths(); - return queryTopNCommon( - router, - logger, - paths.TopNDeployments, - getFieldNameForTopNType(TopNType.Deployments), - false - ); + return queryTopNCommon({ + ...parameters, + pathName: paths.TopNDeployments, + searchField: getFieldNameForTopNType(TopNType.Deployments), + highCardinality: false, + }); } -export function registerTraceEventsTopNHostsSearchRoute({ - router, - logger, -}: RouteRegisterParameters) { +export function registerTraceEventsTopNHostsSearchRoute(parameters: RouteRegisterParameters) { const paths = getRoutePaths(); - return queryTopNCommon( - router, - logger, - paths.TopNHosts, - getFieldNameForTopNType(TopNType.Hosts), - false - ); + return queryTopNCommon({ + ...parameters, + pathName: paths.TopNHosts, + searchField: getFieldNameForTopNType(TopNType.Hosts), + highCardinality: false, + }); } -export function registerTraceEventsTopNStackTracesSearchRoute({ - router, - logger, -}: RouteRegisterParameters) { +export function registerTraceEventsTopNStackTracesSearchRoute(parameters: RouteRegisterParameters) { const paths = getRoutePaths(); - return queryTopNCommon( - router, - logger, - paths.TopNTraces, - getFieldNameForTopNType(TopNType.Traces), - false - ); + return queryTopNCommon({ + ...parameters, + pathName: paths.TopNTraces, + searchField: getFieldNameForTopNType(TopNType.Traces), + highCardinality: false, + }); } -export function registerTraceEventsTopNThreadsSearchRoute({ - router, - logger, -}: RouteRegisterParameters) { +export function registerTraceEventsTopNThreadsSearchRoute(parameters: RouteRegisterParameters) { const paths = getRoutePaths(); - return queryTopNCommon( - router, - logger, - paths.TopNThreads, - getFieldNameForTopNType(TopNType.Threads), - true - ); + return queryTopNCommon({ + ...parameters, + pathName: paths.TopNThreads, + searchField: getFieldNameForTopNType(TopNType.Threads), + highCardinality: true, + }); } From 7bf63c5efc6c679591a6913717a909e3b8546216 Mon Sep 17 00:00:00 2001 From: Dario Gieselaar Date: Wed, 5 Oct 2022 15:28:43 +0200 Subject: [PATCH 3/4] Handle request aborted errors --- .../profiling/public/hooks/use_async.ts | 4 +- .../profiling/server/routes/flamechart.ts | 11 ++--- .../plugins/profiling/server/routes/frames.ts | 9 +--- .../profiling/server/routes/functions.ts | 11 ++--- .../plugins/profiling/server/routes/topn.ts | 12 ++---- .../utils/create_profiling_es_client.ts | 1 - .../utils/handle_route_error_handler.ts | 41 +++++++++++++++++++ 7 files changed, 54 insertions(+), 35 deletions(-) create mode 100644 x-pack/plugins/profiling/server/utils/handle_route_error_handler.ts diff --git a/x-pack/plugins/profiling/public/hooks/use_async.ts b/x-pack/plugins/profiling/public/hooks/use_async.ts index 6a8c29cd02e88..7156b4e8bfffd 100644 --- a/x-pack/plugins/profiling/public/hooks/use_async.ts +++ b/x-pack/plugins/profiling/public/hooks/use_async.ts @@ -4,10 +4,10 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { HttpFetchOptions, HttpHandler, HttpStart, isHttpFetchError } from '@kbn/core-http-browser'; +import { HttpFetchOptions, HttpHandler, HttpStart } from '@kbn/core-http-browser'; +import { AbortError } from '@kbn/kibana-utils-plugin/common'; import { useEffect, useRef, useState } from 'react'; import { Overwrite, ValuesType } from 'utility-types'; -import { AbortError } from '@kbn/kibana-utils-plugin/common'; import { useProfilingDependencies } from '../components/contexts/profiling_dependencies/use_profiling_dependencies'; export enum AsyncStatus { diff --git a/x-pack/plugins/profiling/server/routes/flamechart.ts b/x-pack/plugins/profiling/server/routes/flamechart.ts index a24a9bab598dd..1112e36898932 100644 --- a/x-pack/plugins/profiling/server/routes/flamechart.ts +++ b/x-pack/plugins/profiling/server/routes/flamechart.ts @@ -10,6 +10,7 @@ import { RouteRegisterParameters } from '.'; import { getRoutePaths } from '../../common'; import { createCalleeTree } from '../../common/callee'; import { createFlameGraph } from '../../common/flamegraph'; +import { handleRouteHandlerError } from '../utils/handle_route_error_handler'; import { withProfilingSpan } from '../utils/with_profiling_span'; import { getClient } from './compat'; import { getExecutablesAndStackTraces } from './get_executables_and_stacktraces'; @@ -96,14 +97,8 @@ export function registerFlameChartSearchRoute({ logger.info('returning payload response to client'); return response.ok({ body: flamegraph }); - } catch (e) { - logger.error(e); - return response.customError({ - statusCode: e.statusCode ?? 500, - body: { - message: e.message, - }, - }); + } catch (error) { + return handleRouteHandlerError({ error, logger, response }); } } ); diff --git a/x-pack/plugins/profiling/server/routes/frames.ts b/x-pack/plugins/profiling/server/routes/frames.ts index 1d81a85108cfc..be9882d14cdce 100644 --- a/x-pack/plugins/profiling/server/routes/frames.ts +++ b/x-pack/plugins/profiling/server/routes/frames.ts @@ -17,6 +17,7 @@ import { } from '../../common/profiling'; import { ProfilingESClient } from '../utils/create_profiling_es_client'; import { mgetStackFrames, mgetExecutables } from './stacktrace'; +import { handleRouteHandlerError } from '../utils/handle_route_error_handler'; async function getFrameInformation({ frameID, @@ -93,13 +94,7 @@ export function registerFrameInformationRoute(params: RouteRegisterParameters) { return response.ok({ body: frame }); } catch (error: any) { - logger.error(error); - return response.custom({ - statusCode: error.statusCode ?? 500, - body: { - message: error.message ?? 'An internal server error occured', - }, - }); + return handleRouteHandlerError({ error, logger, response }); } } ); diff --git a/x-pack/plugins/profiling/server/routes/functions.ts b/x-pack/plugins/profiling/server/routes/functions.ts index ed71c1c60d398..36798b5f31711 100644 --- a/x-pack/plugins/profiling/server/routes/functions.ts +++ b/x-pack/plugins/profiling/server/routes/functions.ts @@ -9,6 +9,7 @@ import { schema, TypeOf } from '@kbn/config-schema'; import { RouteRegisterParameters } from '.'; import { getRoutePaths } from '../../common'; import { createTopNFunctions } from '../../common/functions'; +import { handleRouteHandlerError } from '../utils/handle_route_error_handler'; import { withProfilingSpan } from '../utils/with_profiling_span'; import { getClient } from './compat'; import { getExecutablesAndStackTraces } from './get_executables_and_stacktraces'; @@ -75,14 +76,8 @@ export function registerTopNFunctionsSearchRoute({ return response.ok({ body: topNFunctions, }); - } catch (e) { - logger.error(e); - return response.customError({ - statusCode: e.statusCode ?? 500, - body: { - message: e.message, - }, - }); + } catch (error) { + return handleRouteHandlerError({ error, logger, response }); } } ); diff --git a/x-pack/plugins/profiling/server/routes/topn.ts b/x-pack/plugins/profiling/server/routes/topn.ts index 2613cfa429379..de231e4938fdd 100644 --- a/x-pack/plugins/profiling/server/routes/topn.ts +++ b/x-pack/plugins/profiling/server/routes/topn.ts @@ -15,6 +15,7 @@ import { groupStackFrameMetadataByStackTrace, StackTraceID } from '../../common/ import { getFieldNameForTopNType, TopNType } from '../../common/stack_traces'; import { createTopNSamples, getTopNAggregationRequest, TopNResponse } from '../../common/topn'; import { ProfilingESClient } from '../utils/create_profiling_es_client'; +import { handleRouteHandlerError } from '../utils/handle_route_error_handler'; import { withProfilingSpan } from '../utils/with_profiling_span'; import { getClient } from './compat'; import { findDownsampledIndex } from './downsampling'; @@ -193,15 +194,8 @@ export function queryTopNCommon({ kuery, }), }); - } catch (e) { - logger.error(e); - - return response.customError({ - statusCode: e.statusCode ?? 500, - body: { - message: 'Profiling TopN request failed: ' + e.message + '; full error ' + e.toString(), - }, - }); + } catch (error) { + return handleRouteHandlerError({ error, logger, response }); } } ); diff --git a/x-pack/plugins/profiling/server/utils/create_profiling_es_client.ts b/x-pack/plugins/profiling/server/utils/create_profiling_es_client.ts index c30274554df05..71116bd8c643b 100644 --- a/x-pack/plugins/profiling/server/utils/create_profiling_es_client.ts +++ b/x-pack/plugins/profiling/server/utils/create_profiling_es_client.ts @@ -20,7 +20,6 @@ export function cancelEsRequestOnAbort>( ): T { const subscription = request.events.aborted$.subscribe(() => { controller.abort(); - console.log('Aborted ES request'); }); return promise.finally(() => subscription.unsubscribe()) as T; diff --git a/x-pack/plugins/profiling/server/utils/handle_route_error_handler.ts b/x-pack/plugins/profiling/server/utils/handle_route_error_handler.ts new file mode 100644 index 0000000000000..782beeeae15cb --- /dev/null +++ b/x-pack/plugins/profiling/server/utils/handle_route_error_handler.ts @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { KibanaResponseFactory } from '@kbn/core-http-server'; +import { Logger } from '@kbn/logging'; +import { WrappedElasticsearchClientError } from '@kbn/observability-plugin/server'; +import { errors } from '@elastic/elasticsearch'; + +export function handleRouteHandlerError({ + error, + logger, + response, +}: { + error: any; + response: KibanaResponseFactory; + logger: Logger; +}) { + if ( + error instanceof WrappedElasticsearchClientError && + error.originalError instanceof errors.RequestAbortedError + ) { + return response.custom({ + statusCode: 499, + body: { + message: 'Client closed request', + }, + }); + } + logger.error(error); + + return response.customError({ + statusCode: error.statusCode ?? 500, + body: { + message: error.message, + }, + }); +} From 1d27011303fc31a3f388f11fd065f8015c95e9c0 Mon Sep 17 00:00:00 2001 From: Dario Gieselaar Date: Wed, 5 Oct 2022 15:31:41 +0200 Subject: [PATCH 4/4] Revert "[Profiling] Configurable ES client" This reverts commit 3469b1b42c51fe536f22fa80aa7caadafe2f05b3. --- x-pack/plugins/profiling/server/index.ts | 9 +- x-pack/plugins/profiling/server/plugin.ts | 27 +---- .../profiling/server/routes/flamechart.ts | 7 +- .../plugins/profiling/server/routes/frames.ts | 8 +- .../profiling/server/routes/functions.ts | 7 +- .../plugins/profiling/server/routes/index.ts | 9 -- .../plugins/profiling/server/routes/topn.ts | 114 ++++++++++-------- 7 files changed, 75 insertions(+), 106 deletions(-) diff --git a/x-pack/plugins/profiling/server/index.ts b/x-pack/plugins/profiling/server/index.ts index 2632f8c9ebaf7..26858b770b736 100644 --- a/x-pack/plugins/profiling/server/index.ts +++ b/x-pack/plugins/profiling/server/index.ts @@ -11,16 +11,9 @@ import { ProfilingPlugin } from './plugin'; const configSchema = schema.object({ enabled: schema.boolean({ defaultValue: false }), - elasticsearch: schema.maybe( - schema.object({ - hosts: schema.string(), - username: schema.string(), - password: schema.string(), - }) - ), }); -export type ProfilingConfig = TypeOf; +type ProfilingConfig = TypeOf; // plugin config export const config: PluginConfigDescriptor = { diff --git a/x-pack/plugins/profiling/server/plugin.ts b/x-pack/plugins/profiling/server/plugin.ts index 923f87a87267d..40071b54c0c4e 100644 --- a/x-pack/plugins/profiling/server/plugin.ts +++ b/x-pack/plugins/profiling/server/plugin.ts @@ -6,7 +6,7 @@ */ import { CoreSetup, CoreStart, Logger, Plugin, PluginInitializerContext } from '@kbn/core/server'; -import { ProfilingConfig } from '.'; + import { PROFILING_FEATURE } from './feature'; import { registerRoutes } from './routes'; import { @@ -16,7 +16,6 @@ import { ProfilingPluginStartDeps, ProfilingRequestHandlerContext, } from './types'; -import { createProfilingEsClient } from './utils/create_profiling_es_client'; export class ProfilingPlugin implements @@ -29,8 +28,7 @@ export class ProfilingPlugin { private readonly logger: Logger; - constructor(private readonly initializerContext: PluginInitializerContext) { - this.initializerContext = initializerContext; + constructor(initializerContext: PluginInitializerContext) { this.logger = initializerContext.logger.get(); } @@ -40,17 +38,7 @@ export class ProfilingPlugin deps.features.registerKibanaFeature(PROFILING_FEATURE); - const config = this.initializerContext.config.get(); - - core.getStartServices().then(([coreStart, depsStart]) => { - const profilingSpecificEsClient = config.elasticsearch - ? coreStart.elasticsearch.createClient('profiling', { - hosts: [config.elasticsearch.hosts], - username: config.elasticsearch.username, - password: config.elasticsearch.password, - }) - : undefined; - + core.getStartServices().then(([_, depsStart]) => { registerRoutes({ router, logger: this.logger!, @@ -58,15 +46,6 @@ export class ProfilingPlugin start: depsStart, setup: deps, }, - services: { - createProfilingEsClient: ({ request, esClient: defaultEsClient }) => { - const esClient = profilingSpecificEsClient - ? profilingSpecificEsClient.asScoped(request).asInternalUser - : defaultEsClient; - - return createProfilingEsClient({ request, esClient }); - }, - }, }); }); diff --git a/x-pack/plugins/profiling/server/routes/flamechart.ts b/x-pack/plugins/profiling/server/routes/flamechart.ts index 1112e36898932..cd59352ae2f91 100644 --- a/x-pack/plugins/profiling/server/routes/flamechart.ts +++ b/x-pack/plugins/profiling/server/routes/flamechart.ts @@ -11,16 +11,13 @@ import { getRoutePaths } from '../../common'; import { createCalleeTree } from '../../common/callee'; import { createFlameGraph } from '../../common/flamegraph'; import { handleRouteHandlerError } from '../utils/handle_route_error_handler'; +import { createProfilingEsClient } from '../utils/create_profiling_es_client'; import { withProfilingSpan } from '../utils/with_profiling_span'; import { getClient } from './compat'; import { getExecutablesAndStackTraces } from './get_executables_and_stacktraces'; import { createCommonFilter } from './query'; -export function registerFlameChartSearchRoute({ - router, - logger, - services: { createProfilingEsClient }, -}: RouteRegisterParameters) { +export function registerFlameChartSearchRoute({ router, logger }: RouteRegisterParameters) { const paths = getRoutePaths(); router.get( { diff --git a/x-pack/plugins/profiling/server/routes/frames.ts b/x-pack/plugins/profiling/server/routes/frames.ts index be9882d14cdce..d677b535192c8 100644 --- a/x-pack/plugins/profiling/server/routes/frames.ts +++ b/x-pack/plugins/profiling/server/routes/frames.ts @@ -15,7 +15,7 @@ import { StackFrame, StackFrameMetadata, } from '../../common/profiling'; -import { ProfilingESClient } from '../utils/create_profiling_es_client'; +import { createProfilingEsClient, ProfilingESClient } from '../utils/create_profiling_es_client'; import { mgetStackFrames, mgetExecutables } from './stacktrace'; import { handleRouteHandlerError } from '../utils/handle_route_error_handler'; @@ -58,11 +58,7 @@ async function getFrameInformation({ } export function registerFrameInformationRoute(params: RouteRegisterParameters) { - const { - logger, - router, - services: { createProfilingEsClient }, - } = params; + const { logger, router } = params; const routePaths = getRoutePaths(); diff --git a/x-pack/plugins/profiling/server/routes/functions.ts b/x-pack/plugins/profiling/server/routes/functions.ts index 36798b5f31711..9d3eed222b908 100644 --- a/x-pack/plugins/profiling/server/routes/functions.ts +++ b/x-pack/plugins/profiling/server/routes/functions.ts @@ -10,6 +10,7 @@ import { RouteRegisterParameters } from '.'; import { getRoutePaths } from '../../common'; import { createTopNFunctions } from '../../common/functions'; import { handleRouteHandlerError } from '../utils/handle_route_error_handler'; +import { createProfilingEsClient } from '../utils/create_profiling_es_client'; import { withProfilingSpan } from '../utils/with_profiling_span'; import { getClient } from './compat'; import { getExecutablesAndStackTraces } from './get_executables_and_stacktraces'; @@ -25,11 +26,7 @@ const querySchema = schema.object({ type QuerySchemaType = TypeOf; -export function registerTopNFunctionsSearchRoute({ - router, - logger, - services: { createProfilingEsClient }, -}: RouteRegisterParameters) { +export function registerTopNFunctionsSearchRoute({ router, logger }: RouteRegisterParameters) { const paths = getRoutePaths(); router.get( { diff --git a/x-pack/plugins/profiling/server/routes/index.ts b/x-pack/plugins/profiling/server/routes/index.ts index c430d98468b54..6e44bf6909585 100644 --- a/x-pack/plugins/profiling/server/routes/index.ts +++ b/x-pack/plugins/profiling/server/routes/index.ts @@ -6,14 +6,11 @@ */ import type { IRouter, Logger } from '@kbn/core/server'; -import type { KibanaRequest } from '@kbn/core-http-server'; -import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import { ProfilingPluginSetupDeps, ProfilingPluginStartDeps, ProfilingRequestHandlerContext, } from '../types'; -import { ProfilingESClient } from '../utils/create_profiling_es_client'; import { registerFlameChartSearchRoute } from './flamechart'; import { registerFrameInformationRoute } from './frames'; @@ -34,12 +31,6 @@ export interface RouteRegisterParameters { start: ProfilingPluginStartDeps; setup: ProfilingPluginSetupDeps; }; - services: { - createProfilingEsClient: (params: { - request: KibanaRequest; - esClient: ElasticsearchClient; - }) => ProfilingESClient; - }; } export function registerRoutes(params: RouteRegisterParameters) { diff --git a/x-pack/plugins/profiling/server/routes/topn.ts b/x-pack/plugins/profiling/server/routes/topn.ts index de231e4938fdd..a8a7efc01bb52 100644 --- a/x-pack/plugins/profiling/server/routes/topn.ts +++ b/x-pack/plugins/profiling/server/routes/topn.ts @@ -6,7 +6,7 @@ */ import { schema } from '@kbn/config-schema'; -import type { Logger } from '@kbn/core/server'; +import type { IRouter, Logger } from '@kbn/core/server'; import { RouteRegisterParameters } from '.'; import { getRoutePaths, INDEX_EVENTS } from '../../common'; import { ProfilingESField } from '../../common/elasticsearch'; @@ -14,8 +14,9 @@ import { computeBucketWidthFromTimeRangeAndBucketCount } from '../../common/hist import { groupStackFrameMetadataByStackTrace, StackTraceID } from '../../common/profiling'; import { getFieldNameForTopNType, TopNType } from '../../common/stack_traces'; import { createTopNSamples, getTopNAggregationRequest, TopNResponse } from '../../common/topn'; -import { ProfilingESClient } from '../utils/create_profiling_es_client'; import { handleRouteHandlerError } from '../utils/handle_route_error_handler'; +import { ProfilingRequestHandlerContext } from '../types'; +import { createProfilingEsClient, ProfilingESClient } from '../utils/create_profiling_es_client'; import { withProfilingSpan } from '../utils/with_profiling_span'; import { getClient } from './compat'; import { findDownsampledIndex } from './downsampling'; @@ -155,18 +156,13 @@ export async function topNElasticSearchQuery({ }; } -export function queryTopNCommon({ - logger, - router, - services: { createProfilingEsClient }, - pathName, - searchField, - highCardinality, -}: RouteRegisterParameters & { - pathName: string; - searchField: string; - highCardinality: boolean; -}) { +export function queryTopNCommon( + router: IRouter, + logger: Logger, + pathName: string, + searchField: string, + highCardinality: boolean +) { router.get( { path: pathName, @@ -201,52 +197,72 @@ export function queryTopNCommon({ ); } -export function registerTraceEventsTopNContainersSearchRoute(parameters: RouteRegisterParameters) { +export function registerTraceEventsTopNContainersSearchRoute({ + router, + logger, +}: RouteRegisterParameters) { const paths = getRoutePaths(); - return queryTopNCommon({ - ...parameters, - pathName: paths.TopNContainers, - searchField: getFieldNameForTopNType(TopNType.Containers), - highCardinality: false, - }); + return queryTopNCommon( + router, + logger, + paths.TopNContainers, + getFieldNameForTopNType(TopNType.Containers), + false + ); } -export function registerTraceEventsTopNDeploymentsSearchRoute(parameters: RouteRegisterParameters) { +export function registerTraceEventsTopNDeploymentsSearchRoute({ + router, + logger, +}: RouteRegisterParameters) { const paths = getRoutePaths(); - return queryTopNCommon({ - ...parameters, - pathName: paths.TopNDeployments, - searchField: getFieldNameForTopNType(TopNType.Deployments), - highCardinality: false, - }); + return queryTopNCommon( + router, + logger, + paths.TopNDeployments, + getFieldNameForTopNType(TopNType.Deployments), + false + ); } -export function registerTraceEventsTopNHostsSearchRoute(parameters: RouteRegisterParameters) { +export function registerTraceEventsTopNHostsSearchRoute({ + router, + logger, +}: RouteRegisterParameters) { const paths = getRoutePaths(); - return queryTopNCommon({ - ...parameters, - pathName: paths.TopNHosts, - searchField: getFieldNameForTopNType(TopNType.Hosts), - highCardinality: false, - }); + return queryTopNCommon( + router, + logger, + paths.TopNHosts, + getFieldNameForTopNType(TopNType.Hosts), + false + ); } -export function registerTraceEventsTopNStackTracesSearchRoute(parameters: RouteRegisterParameters) { +export function registerTraceEventsTopNStackTracesSearchRoute({ + router, + logger, +}: RouteRegisterParameters) { const paths = getRoutePaths(); - return queryTopNCommon({ - ...parameters, - pathName: paths.TopNTraces, - searchField: getFieldNameForTopNType(TopNType.Traces), - highCardinality: false, - }); + return queryTopNCommon( + router, + logger, + paths.TopNTraces, + getFieldNameForTopNType(TopNType.Traces), + false + ); } -export function registerTraceEventsTopNThreadsSearchRoute(parameters: RouteRegisterParameters) { +export function registerTraceEventsTopNThreadsSearchRoute({ + router, + logger, +}: RouteRegisterParameters) { const paths = getRoutePaths(); - return queryTopNCommon({ - ...parameters, - pathName: paths.TopNThreads, - searchField: getFieldNameForTopNType(TopNType.Threads), - highCardinality: true, - }); + return queryTopNCommon( + router, + logger, + paths.TopNThreads, + getFieldNameForTopNType(TopNType.Threads), + true + ); }