mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[ObsUX] Add Top Functions to Infra Profilling tab (#171974)
Closes https://github.com/elastic/kibana/issues/171962
## Summary
This integrated Profiling Top Functions embeddable into the Infra's
Profiling tab in asset details.

## How to Test
* Connect local kibana to oblt cluster that has Profiling configured
(e.g. edge)
* Add this to your dev `kibana.yml`
```
xpack.profiling.enabled: true
xpack.infra.profilingEnabled: true
# Direct ES URL on the oblt cluster that you're using, in case of edge it's https://edge-oblt.es.us-west2.gcp.elastic-cloud.com:443
xpack.profiling.elasticsearch.hosts: REMOTE_CLUSTER_ES_URL
# If needed create a new user on the remote oblt cluster
xpack.profiling.elasticsearch.username: REMOTE_CLUSTER_USER
xpack.profiling.elasticsearch.password: REMOTE_CLUSTER_PASWORD
```
* Open kibana, go to Hosts
* Open a flyout for one of the hosts and make sure you see the Profiling
tab with both Flamegraph and Top Functions
* Open Host details as a full page and also make sure you see the same
* Make sure Profiling data updates when you change dates in the date
picker
This commit is contained in:
parent
c662bb32e9
commit
ad2ca2443c
12 changed files with 365 additions and 91 deletions
|
@ -7,12 +7,24 @@
|
|||
|
||||
import * as rt from 'io-ts';
|
||||
|
||||
export const InfraProfilingRequestParamsRT = rt.type({
|
||||
export const InfraProfilingFlamegraphRequestParamsRT = rt.type({
|
||||
hostname: rt.string,
|
||||
timeRange: rt.type({
|
||||
from: rt.number,
|
||||
to: rt.number,
|
||||
}),
|
||||
from: rt.number,
|
||||
to: rt.number,
|
||||
});
|
||||
|
||||
export type InfraProfilingRequestParams = rt.TypeOf<typeof InfraProfilingRequestParamsRT>;
|
||||
export const InfraProfilingFunctionsRequestParamsRT = rt.type({
|
||||
hostname: rt.string,
|
||||
from: rt.number,
|
||||
to: rt.number,
|
||||
startIndex: rt.number,
|
||||
endIndex: rt.number,
|
||||
});
|
||||
|
||||
export type InfraProfilingFlamegraphRequestParams = rt.TypeOf<
|
||||
typeof InfraProfilingFlamegraphRequestParamsRT
|
||||
>;
|
||||
|
||||
export type InfraProfilingFunctionsRequestParams = rt.TypeOf<
|
||||
typeof InfraProfilingFunctionsRequestParamsRT
|
||||
>;
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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 { useEffect, useMemo } from 'react';
|
||||
import type { BaseFlameGraph } from '@kbn/profiling-utils';
|
||||
import { type InfraProfilingFlamegraphRequestParams } from '../../../../common/http_api/profiling_api';
|
||||
import { useHTTPRequest } from '../../../hooks/use_http_request';
|
||||
import { useRequestObservable } from './use_request_observable';
|
||||
|
||||
interface Props {
|
||||
params: InfraProfilingFlamegraphRequestParams;
|
||||
isActive: boolean;
|
||||
}
|
||||
|
||||
export function useProfilingFlamegraphData({ params, isActive }: Props) {
|
||||
const { request$ } = useRequestObservable<BaseFlameGraph>();
|
||||
const fetchOptions = useMemo(() => ({ query: params }), [params]);
|
||||
const { loading, error, response, makeRequest } = useHTTPRequest<BaseFlameGraph>(
|
||||
`/api/infra/profiling/flamegraph`,
|
||||
'GET',
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
true,
|
||||
fetchOptions
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
request$.next(makeRequest);
|
||||
}, [isActive, makeRequest, request$]);
|
||||
|
||||
return {
|
||||
loading,
|
||||
error,
|
||||
response,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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 { useEffect, useMemo } from 'react';
|
||||
import type { TopNFunctions } from '@kbn/profiling-utils';
|
||||
import { type InfraProfilingFunctionsRequestParams } from '../../../../common/http_api/profiling_api';
|
||||
import { useHTTPRequest } from '../../../hooks/use_http_request';
|
||||
import { useRequestObservable } from './use_request_observable';
|
||||
|
||||
interface Props {
|
||||
params: InfraProfilingFunctionsRequestParams;
|
||||
isActive: boolean;
|
||||
}
|
||||
|
||||
export function useProfilingFunctionsData({ params, isActive }: Props) {
|
||||
const { request$ } = useRequestObservable<TopNFunctions>();
|
||||
const fetchOptions = useMemo(() => ({ query: params }), [params]);
|
||||
const { loading, error, response, makeRequest } = useHTTPRequest<TopNFunctions>(
|
||||
'/api/infra/profiling/functions',
|
||||
'GET',
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
true,
|
||||
fetchOptions
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
request$.next(makeRequest);
|
||||
}, [isActive, makeRequest, request$]);
|
||||
|
||||
return {
|
||||
loading,
|
||||
error,
|
||||
response,
|
||||
};
|
||||
}
|
|
@ -1,50 +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 { useEffect } from 'react';
|
||||
import type { BaseFlameGraph } from '@kbn/profiling-utils';
|
||||
import type { Subject } from 'rxjs';
|
||||
import {
|
||||
type InfraProfilingRequestParams,
|
||||
InfraProfilingRequestParamsRT,
|
||||
} from '../../../../common/http_api/profiling_api';
|
||||
import { useHTTPRequest } from '../../../hooks/use_http_request';
|
||||
|
||||
interface Props extends InfraProfilingRequestParams {
|
||||
request$?: Subject<() => Promise<BaseFlameGraph>>;
|
||||
active: boolean;
|
||||
}
|
||||
|
||||
export function useProfilingFlamegraphData({ request$, active, ...params }: Props) {
|
||||
const { loading, error, response, makeRequest } = useHTTPRequest<BaseFlameGraph>(
|
||||
'/api/infra/profiling/flamegraph',
|
||||
'POST',
|
||||
JSON.stringify(InfraProfilingRequestParamsRT.encode(params)),
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!active) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (request$) {
|
||||
request$.next(makeRequest);
|
||||
} else {
|
||||
makeRequest();
|
||||
}
|
||||
}, [active, makeRequest, request$]);
|
||||
|
||||
return {
|
||||
loading,
|
||||
error,
|
||||
response,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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 { EuiEmptyPrompt } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
|
||||
export function ErrorPrompt() {
|
||||
return (
|
||||
<EuiEmptyPrompt
|
||||
color="warning"
|
||||
iconType="warning"
|
||||
titleSize="xs"
|
||||
title={
|
||||
<h2>
|
||||
{i18n.translate('xpack.infra.profiling.loadErrorTitle', {
|
||||
defaultMessage: 'Unable to load the Profiling data',
|
||||
})}
|
||||
</h2>
|
||||
}
|
||||
body={
|
||||
<p>
|
||||
{i18n.translate('xpack.infra.profiling.loadErrorBody', {
|
||||
defaultMessage:
|
||||
'There was an error while trying to load profiling data. Try refreshing the page',
|
||||
})}
|
||||
</p>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
|
@ -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 React, { useMemo } from 'react';
|
||||
import { EmbeddableFlamegraph } from '@kbn/observability-shared-plugin/public';
|
||||
import { useAssetDetailsRenderPropsContext } from '../../hooks/use_asset_details_render_props';
|
||||
import { useDatePickerContext } from '../../hooks/use_date_picker';
|
||||
import { useProfilingFlamegraphData } from '../../hooks/use_profiling_flamegraph_data';
|
||||
import { useTabSwitcherContext } from '../../hooks/use_tab_switcher';
|
||||
import { ContentTabIds } from '../../types';
|
||||
import { ErrorPrompt } from './error_prompt';
|
||||
|
||||
export function Flamegraph() {
|
||||
const { asset } = useAssetDetailsRenderPropsContext();
|
||||
const { activeTabId } = useTabSwitcherContext();
|
||||
const { getDateRangeInTimestamp } = useDatePickerContext();
|
||||
const { from, to } = getDateRangeInTimestamp();
|
||||
|
||||
const params = useMemo(
|
||||
() => ({
|
||||
hostname: asset.name,
|
||||
from,
|
||||
to,
|
||||
}),
|
||||
[asset.name, from, to]
|
||||
);
|
||||
const { error, loading, response } = useProfilingFlamegraphData({
|
||||
isActive: activeTabId === ContentTabIds.PROFILING,
|
||||
params,
|
||||
});
|
||||
|
||||
if (error !== null) {
|
||||
return <ErrorPrompt />;
|
||||
}
|
||||
|
||||
return <EmbeddableFlamegraph data={response ?? undefined} isLoading={loading} height="60vh" />;
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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 React, { useMemo } from 'react';
|
||||
import { EmbeddableFunctions } from '@kbn/observability-shared-plugin/public';
|
||||
import { useAssetDetailsRenderPropsContext } from '../../hooks/use_asset_details_render_props';
|
||||
import { useDatePickerContext } from '../../hooks/use_date_picker';
|
||||
import { useProfilingFunctionsData } from '../../hooks/use_profiling_functions_data';
|
||||
import { useTabSwitcherContext } from '../../hooks/use_tab_switcher';
|
||||
import { ContentTabIds } from '../../types';
|
||||
import { ErrorPrompt } from './error_prompt';
|
||||
|
||||
export function Functions() {
|
||||
const { asset } = useAssetDetailsRenderPropsContext();
|
||||
const { activeTabId } = useTabSwitcherContext();
|
||||
const { getDateRangeInTimestamp } = useDatePickerContext();
|
||||
const { from, to } = getDateRangeInTimestamp();
|
||||
|
||||
const params = useMemo(
|
||||
() => ({
|
||||
hostname: asset.name,
|
||||
from,
|
||||
to,
|
||||
startIndex: 0,
|
||||
endIndex: 10,
|
||||
}),
|
||||
[asset.name, from, to]
|
||||
);
|
||||
|
||||
const { error, loading, response } = useProfilingFunctionsData({
|
||||
isActive: activeTabId === ContentTabIds.PROFILING,
|
||||
params,
|
||||
});
|
||||
|
||||
if (error !== null) {
|
||||
return <ErrorPrompt />;
|
||||
}
|
||||
|
||||
return (
|
||||
<EmbeddableFunctions
|
||||
data={response ?? undefined}
|
||||
isLoading={loading}
|
||||
rangeFrom={from}
|
||||
rangeTo={to}
|
||||
/>
|
||||
);
|
||||
}
|
|
@ -4,28 +4,44 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { EuiSpacer, EuiTabbedContent, type EuiTabbedContentProps } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import { EmbeddableFlamegraph } from '@kbn/observability-shared-plugin/public';
|
||||
import { BaseFlameGraph } from '@kbn/profiling-utils';
|
||||
import { useAssetDetailsRenderPropsContext } from '../../hooks/use_asset_details_render_props';
|
||||
import { useDatePickerContext } from '../../hooks/use_date_picker';
|
||||
import { useProfilingFlamegraphData } from '../../hooks/use_profilling_flamegraph_data';
|
||||
import { useRequestObservable } from '../../hooks/use_request_observable';
|
||||
import { useTabSwitcherContext } from '../../hooks/use_tab_switcher';
|
||||
import { ContentTabIds } from '../../types';
|
||||
import { Flamegraph } from './flamegraph';
|
||||
import { Functions } from './functions';
|
||||
|
||||
export function Profiling() {
|
||||
const { request$ } = useRequestObservable<BaseFlameGraph>();
|
||||
const { asset } = useAssetDetailsRenderPropsContext();
|
||||
const { activeTabId } = useTabSwitcherContext();
|
||||
const { getDateRangeInTimestamp } = useDatePickerContext();
|
||||
const { loading, response } = useProfilingFlamegraphData({
|
||||
active: activeTabId === ContentTabIds.PROFILING,
|
||||
request$,
|
||||
hostname: asset.name,
|
||||
timeRange: getDateRangeInTimestamp(),
|
||||
});
|
||||
const tabs: EuiTabbedContentProps['tabs'] = [
|
||||
{
|
||||
id: 'flamegraph',
|
||||
name: i18n.translate('xpack.infra.profiling.flamegraphTabName', {
|
||||
defaultMessage: 'Flamegraph',
|
||||
}),
|
||||
content: (
|
||||
<>
|
||||
<EuiSpacer />
|
||||
<Flamegraph />
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'functions',
|
||||
name: i18n.translate('xpack.infra.tabs.profiling.functionsTabName', {
|
||||
defaultMessage: 'Top 10 Functions',
|
||||
}),
|
||||
content: (
|
||||
<>
|
||||
<EuiSpacer />
|
||||
<Functions />
|
||||
</>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return <EmbeddableFlamegraph data={response ?? undefined} isLoading={loading} height="60vh" />;
|
||||
return (
|
||||
<>
|
||||
<EuiTabbedContent tabs={tabs} initialSelectedTab={tabs[0]} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { HttpHandler, ToastInput } from '@kbn/core/public';
|
||||
import { HttpFetchOptions, HttpHandler, ToastInput } from '@kbn/core/public';
|
||||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import { AbortError } from '@kbn/kibana-utils-plugin/common';
|
||||
import { useTrackedPromise, CanceledPromiseError } from '../utils/use_tracked_promise';
|
||||
|
@ -20,7 +20,8 @@ export function useHTTPRequest<Response>(
|
|||
decode: (response: any) => Response = (response) => response,
|
||||
fetch?: HttpHandler,
|
||||
toastDanger?: (input: ToastInput) => void,
|
||||
abortable = false
|
||||
abortable = false,
|
||||
fetchOptions?: Omit<HttpFetchOptions, 'body' | 'method' | 'signal'>
|
||||
) {
|
||||
const kibana = useKibana();
|
||||
const fetchService = fetch ? fetch : kibana.services.http?.fetch;
|
||||
|
@ -100,6 +101,7 @@ export function useHTTPRequest<Response>(
|
|||
signal: abortController.current.signal,
|
||||
method,
|
||||
body,
|
||||
...fetchOptions,
|
||||
});
|
||||
},
|
||||
onResolve: (resp) => {
|
||||
|
@ -114,7 +116,7 @@ export function useHTTPRequest<Response>(
|
|||
onError(e);
|
||||
},
|
||||
},
|
||||
[pathname, body, method, fetch, toast, onError]
|
||||
[pathname, body, method, fetch, toast, onError, fetchOptions]
|
||||
);
|
||||
|
||||
const loading = request.state === 'uninitialized' || request.state === 'pending';
|
||||
|
|
|
@ -7,12 +7,18 @@
|
|||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { decodeOrThrow } from '@kbn/io-ts-utils';
|
||||
import { InfraProfilingRequestParamsRT } from '../../../common/http_api/profiling_api';
|
||||
import {
|
||||
InfraProfilingFlamegraphRequestParamsRT,
|
||||
InfraProfilingFunctionsRequestParamsRT,
|
||||
} from '../../../common/http_api/profiling_api';
|
||||
import type { InfraBackendLibs } from '../../lib/infra_types';
|
||||
import { fetchProfilingFlamegraph } from './lib/fetch_profiling_flamechart';
|
||||
import { fetchProfilingFlamegraph } from './lib/fetch_profiling_flamegraph';
|
||||
import { fetchProfilingFunctions } from './lib/fetch_profiling_functions';
|
||||
import { fetchProfilingStatus } from './lib/fetch_profiling_status';
|
||||
import { getProfilingDataAccess } from './lib/get_profiling_data_access';
|
||||
|
||||
const CACHE_CONTROL_HEADER_VALUE = 'private, max-age=3600';
|
||||
|
||||
export function initProfilingRoutes({ framework, getStartServices, logger }: InfraBackendLibs) {
|
||||
if (!Object.hasOwn(framework.plugins, 'profilingDataAccess')) {
|
||||
logger.info(
|
||||
|
@ -48,18 +54,18 @@ export function initProfilingRoutes({ framework, getStartServices, logger }: Inf
|
|||
|
||||
framework.registerRoute(
|
||||
{
|
||||
method: 'post',
|
||||
method: 'get',
|
||||
path: '/api/infra/profiling/flamegraph',
|
||||
validate: {
|
||||
/**
|
||||
* Allow any body object and validate it inside
|
||||
* the handler using RT.
|
||||
*/
|
||||
body: schema.object({}, { unknowns: 'allow' }),
|
||||
query: schema.object({
|
||||
hostname: schema.string(),
|
||||
from: schema.number(),
|
||||
to: schema.number(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
async (requestContext, request, response) => {
|
||||
const params = decodeOrThrow(InfraProfilingRequestParamsRT)(request.body);
|
||||
const params = decodeOrThrow(InfraProfilingFlamegraphRequestParamsRT)(request.query);
|
||||
|
||||
const [coreRequestContext, profilingDataAccess] = await Promise.all([
|
||||
requestContext.core,
|
||||
|
@ -74,6 +80,46 @@ export function initProfilingRoutes({ framework, getStartServices, logger }: Inf
|
|||
|
||||
return response.ok({
|
||||
body: flamegraph,
|
||||
headers: {
|
||||
'cache-control': CACHE_CONTROL_HEADER_VALUE,
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
framework.registerRoute(
|
||||
{
|
||||
method: 'get',
|
||||
path: '/api/infra/profiling/functions',
|
||||
validate: {
|
||||
query: schema.object({
|
||||
hostname: schema.string(),
|
||||
from: schema.number(),
|
||||
to: schema.number(),
|
||||
startIndex: schema.number(),
|
||||
endIndex: schema.number(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
async (requestContext, request, response) => {
|
||||
const params = decodeOrThrow(InfraProfilingFunctionsRequestParamsRT)(request.query);
|
||||
|
||||
const [coreRequestContext, profilingDataAccess] = await Promise.all([
|
||||
requestContext.core,
|
||||
getProfilingDataAccess(getStartServices),
|
||||
]);
|
||||
|
||||
const functions = await fetchProfilingFunctions(
|
||||
params,
|
||||
profilingDataAccess,
|
||||
coreRequestContext
|
||||
);
|
||||
|
||||
return response.ok({
|
||||
body: functions,
|
||||
headers: {
|
||||
'cache-control': CACHE_CONTROL_HEADER_VALUE,
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
|
|
|
@ -9,11 +9,11 @@ import type { CoreRequestHandlerContext } from '@kbn/core-http-request-handler-c
|
|||
import type { ProfilingDataAccessPluginStart } from '@kbn/profiling-data-access-plugin/server';
|
||||
import type { BaseFlameGraph } from '@kbn/profiling-utils';
|
||||
import { profilingUseLegacyFlamegraphAPI } from '@kbn/observability-plugin/common';
|
||||
import type { InfraProfilingRequestParams } from '../../../../common/http_api/profiling_api';
|
||||
import type { InfraProfilingFlamegraphRequestParams } from '../../../../common/http_api/profiling_api';
|
||||
import { HOST_FIELD } from '../../../../common/constants';
|
||||
|
||||
export async function fetchProfilingFlamegraph(
|
||||
{ hostname, timeRange }: InfraProfilingRequestParams,
|
||||
{ hostname, from, to }: InfraProfilingFlamegraphRequestParams,
|
||||
profilingDataAccess: ProfilingDataAccessPluginStart,
|
||||
coreRequestContext: CoreRequestHandlerContext
|
||||
): Promise<BaseFlameGraph> {
|
||||
|
@ -23,8 +23,8 @@ export async function fetchProfilingFlamegraph(
|
|||
|
||||
return await profilingDataAccess.services.fetchFlamechartData({
|
||||
esClient: coreRequestContext.elasticsearch.client.asCurrentUser,
|
||||
rangeFromMs: timeRange.from,
|
||||
rangeToMs: timeRange.to,
|
||||
rangeFromMs: from,
|
||||
rangeToMs: to,
|
||||
kuery: `${HOST_FIELD} : "${hostname}"`,
|
||||
useLegacyFlamegraphAPI,
|
||||
});
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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 type { CoreRequestHandlerContext } from '@kbn/core-http-request-handler-context-server';
|
||||
import type { ProfilingDataAccessPluginStart } from '@kbn/profiling-data-access-plugin/server';
|
||||
import type { TopNFunctions } from '@kbn/profiling-utils';
|
||||
import { HOST_FIELD } from '../../../../common/constants';
|
||||
import type { InfraProfilingFunctionsRequestParams } from '../../../../common/http_api/profiling_api';
|
||||
|
||||
export async function fetchProfilingFunctions(
|
||||
params: InfraProfilingFunctionsRequestParams,
|
||||
profilingDataAccess: ProfilingDataAccessPluginStart,
|
||||
coreRequestContext: CoreRequestHandlerContext
|
||||
): Promise<TopNFunctions> {
|
||||
const { hostname, from, to, startIndex, endIndex } = params;
|
||||
|
||||
return await profilingDataAccess.services.fetchFunction({
|
||||
esClient: coreRequestContext.elasticsearch.client.asCurrentUser,
|
||||
rangeFromMs: from,
|
||||
rangeToMs: to,
|
||||
kuery: `${HOST_FIELD} : "${hostname}"`,
|
||||
startIndex,
|
||||
endIndex,
|
||||
});
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue