Skip to content

Commit

Permalink
[Metrics UI] Refactor Process List API to fetch only top processes (#…
Browse files Browse the repository at this point in the history
…84716)

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
Zacqary and kibanamachine committed Dec 7, 2020
1 parent a7c5b49 commit de289de
Show file tree
Hide file tree
Showing 14 changed files with 859 additions and 372 deletions.
129 changes: 126 additions & 3 deletions x-pack/plugins/infra/common/http_api/host_details/process_list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,139 @@
*/

import * as rt from 'io-ts';
import { MetricsAPITimerangeRT, MetricsAPISeriesRT } from '../metrics_api';
import { MetricsAPISeriesRT, MetricsAPIRow } from '../metrics_api';

const AggValueRT = rt.type({
value: rt.number,
});

export const ProcessListAPIRequestRT = rt.type({
hostTerm: rt.record(rt.string, rt.string),
timerange: MetricsAPITimerangeRT,
timefield: rt.string,
indexPattern: rt.string,
to: rt.number,
sortBy: rt.type({
name: rt.string,
isAscending: rt.boolean,
}),
searchFilter: rt.array(rt.record(rt.string, rt.record(rt.string, rt.unknown))),
});

export const ProcessListAPIResponseRT = rt.array(MetricsAPISeriesRT);
export const ProcessListAPIQueryAggregationRT = rt.type({
summaryEvent: rt.type({
summary: rt.type({
hits: rt.type({
hits: rt.array(
rt.type({
_source: rt.type({
system: rt.type({
process: rt.type({
summary: rt.record(rt.string, rt.number),
}),
}),
}),
})
),
}),
}),
}),
processes: rt.type({
filteredProcs: rt.type({
buckets: rt.array(
rt.type({
key: rt.string,
cpu: AggValueRT,
memory: AggValueRT,
startTime: rt.type({
value_as_string: rt.string,
}),
meta: rt.type({
hits: rt.type({
hits: rt.array(
rt.type({
_source: rt.type({
process: rt.type({
pid: rt.number,
}),
system: rt.type({
process: rt.type({
state: rt.string,
}),
}),
user: rt.type({
name: rt.string,
}),
}),
})
),
}),
}),
})
),
}),
}),
});

export const ProcessListAPIResponseRT = rt.type({
processList: rt.array(
rt.type({
cpu: rt.number,
memory: rt.number,
startTime: rt.number,
pid: rt.number,
state: rt.string,
user: rt.string,
command: rt.string,
})
),
summary: rt.record(rt.string, rt.number),
});

export type ProcessListAPIQueryAggregation = rt.TypeOf<typeof ProcessListAPIQueryAggregationRT>;

export type ProcessListAPIRequest = rt.TypeOf<typeof ProcessListAPIRequestRT>;

export type ProcessListAPIResponse = rt.TypeOf<typeof ProcessListAPIResponseRT>;

export const ProcessListAPIChartRequestRT = rt.type({
hostTerm: rt.record(rt.string, rt.string),
timefield: rt.string,
indexPattern: rt.string,
to: rt.number,
command: rt.string,
});

export const ProcessListAPIChartQueryAggregationRT = rt.type({
process: rt.type({
filteredProc: rt.type({
buckets: rt.array(
rt.type({
timeseries: rt.type({
buckets: rt.array(
rt.type({
key: rt.number,
memory: AggValueRT,
cpu: AggValueRT,
})
),
}),
})
),
}),
}),
});

export const ProcessListAPIChartResponseRT = rt.type({
cpu: MetricsAPISeriesRT,
memory: MetricsAPISeriesRT,
});

export type ProcessListAPIChartQueryAggregation = rt.TypeOf<
typeof ProcessListAPIChartQueryAggregationRT
>;

export type ProcessListAPIChartRequest = rt.TypeOf<typeof ProcessListAPIChartRequestRT>;

export type ProcessListAPIChartResponse = rt.TypeOf<typeof ProcessListAPIChartResponseRT>;

export type ProcessListAPIRow = MetricsAPIRow;
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,28 @@
*/

import React, { useMemo, useState } from 'react';
import { debounce } from 'lodash';
import { i18n } from '@kbn/i18n';
import { EuiSearchBar, EuiSpacer, EuiEmptyPrompt, EuiButton, Query } from '@elastic/eui';
import { useProcessList } from '../../../../hooks/use_process_list';
import { EuiSearchBar, EuiSpacer, EuiEmptyPrompt, EuiButton } from '@elastic/eui';
import {
useProcessList,
SortBy,
ProcessListContextProvider,
} from '../../../../hooks/use_process_list';
import { TabContent, TabProps } from '../shared';
import { STATE_NAMES } from './states';
import { SummaryTable } from './summary_table';
import { ProcessesTable } from './processes_table';
import { parseSearchString } from './parse_search_string';

const TabComponent = ({ currentTime, node, nodeType, options }: TabProps) => {
const [searchFilter, setSearchFilter] = useState<Query>(EuiSearchBar.Query.MATCH_ALL);
const [searchFilter, setSearchFilter] = useState<string>('');
const [sortBy, setSortBy] = useState<SortBy>({
name: 'cpu',
isAscending: false,
});

const timefield = options.fields!.timestamp;

const hostTerm = useMemo(() => {
const field =
Expand All @@ -26,69 +38,80 @@ const TabComponent = ({ currentTime, node, nodeType, options }: TabProps) => {

const { loading, error, response, makeRequest: reload } = useProcessList(
hostTerm,
'metricbeat-*',
options.fields!.timestamp,
currentTime
timefield,
currentTime,
sortBy,
parseSearchString(searchFilter)
);

if (error) {
return (
<TabContent>
<EuiEmptyPrompt
iconType="tableDensityNormal"
title={
<h4>
{i18n.translate('xpack.infra.metrics.nodeDetails.processListError', {
defaultMessage: 'Unable to show process data',
})}
</h4>
}
actions={
<EuiButton color="primary" fill onClick={reload}>
{i18n.translate('xpack.infra.metrics.nodeDetails.processListRetry', {
defaultMessage: 'Try again',
})}
</EuiButton>
}
/>
</TabContent>
);
}
const debouncedSearchOnChange = useMemo(
() =>
debounce<(props: { queryText: string }) => void>(
({ queryText }) => setSearchFilter(queryText),
500
),
[setSearchFilter]
);

return (
<TabContent>
<SummaryTable isLoading={loading} processList={response ?? []} />
<EuiSpacer size="m" />
<EuiSearchBar
query={searchFilter}
onChange={({ query }) => setSearchFilter(query ?? EuiSearchBar.Query.MATCH_ALL)}
box={{
incremental: true,
placeholder: i18n.translate('xpack.infra.metrics.nodeDetails.searchForProcesses', {
defaultMessage: 'Search for processes…',
}),
}}
filters={[
{
type: 'field_value_selection',
field: 'state',
name: 'State',
operator: 'exact',
multiSelect: false,
options: Object.entries(STATE_NAMES).map(([value, view]: [string, string]) => ({
value,
view,
})),
},
]}
/>
<EuiSpacer size="m" />
<ProcessesTable
currentTime={currentTime}
isLoading={loading || !response}
processList={response ?? []}
searchFilter={searchFilter}
/>
<ProcessListContextProvider hostTerm={hostTerm} to={currentTime} timefield={timefield}>
<SummaryTable
isLoading={loading}
processSummary={(!error ? response?.summary : null) ?? { total: 0 }}
/>
<EuiSpacer size="m" />
<EuiSearchBar
onChange={debouncedSearchOnChange}
box={{
incremental: true,
placeholder: i18n.translate('xpack.infra.metrics.nodeDetails.searchForProcesses', {
defaultMessage: 'Search for processes…',
}),
}}
filters={[
{
type: 'field_value_selection',
field: 'state',
name: 'State',
operator: 'exact',
multiSelect: false,
options: Object.entries(STATE_NAMES).map(([value, view]: [string, string]) => ({
value,
view,
})),
},
]}
/>
<EuiSpacer size="m" />
{!error ? (
<ProcessesTable
currentTime={currentTime}
isLoading={loading || !response}
processList={response?.processList ?? []}
sortBy={sortBy}
setSortBy={setSortBy}
/>
) : (
<EuiEmptyPrompt
iconType="tableDensityNormal"
title={
<h4>
{i18n.translate('xpack.infra.metrics.nodeDetails.processListError', {
defaultMessage: 'Unable to show process data',
})}
</h4>
}
actions={
<EuiButton color="primary" fill onClick={reload}>
{i18n.translate('xpack.infra.metrics.nodeDetails.processListRetry', {
defaultMessage: 'Try again',
})}
</EuiButton>
}
/>
)}
</ProcessListContextProvider>
</TabContent>
);
};
Expand Down

This file was deleted.

Loading

0 comments on commit de289de

Please sign in to comment.