Skip to content

Commit

Permalink
Added all relevant changes to overview page
Browse files Browse the repository at this point in the history
Signed-off-by: Emily Guo <[email protected]>
  • Loading branch information
LilyCaroline17 committed Aug 31, 2024
1 parent 9ccdb5b commit 6c8cd1f
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 93 deletions.
127 changes: 95 additions & 32 deletions public/pages/QueryInsights/QueryInsights.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import React, { useState } from 'react';
import { EuiBasicTableColumn, EuiSuperDatePicker, EuiInMemoryTable, EuiLink } from '@elastic/eui';
import { useHistory } from 'react-router-dom';
import React, { useEffect, useState } from 'react';
import { EuiBasicTableColumn, EuiInMemoryTable, EuiLink, EuiSuperDatePicker } from '@elastic/eui';
import hash from 'object-hash';
import { useHistory, useLocation } from 'react-router-dom';
import { CoreStart } from '../../../../../src/core/public';
import { QUERY_INSIGHTS } from '../TopNQueries/TopNQueries';

const TIMESTAMP_FIELD = 'timestamp';
const LATENCY_FIELD = 'latency';
Expand All @@ -10,19 +13,42 @@ const INDICES_FIELD = 'indices';
const SEARCH_TYPE_FIELD = 'search_type';
const NODE_ID_FIELD = 'node_id';
const TOTAL_SHARDS_FIELD = 'total_shards';
const METRIC_DEFAULT_MSG = 'Not enabled';

const QueryInsights = ({
queries,
loading,
onQueriesChange,
defaultStart,
onTimeChange,
recentlyUsedRanges,
currStart,
currEnd,
core,
}: {
queries: any[];
loading: boolean;
onQueriesChange: any;
defaultStart: string;
onTimeChange: any;
recentlyUsedRanges: any[];
currStart: string;
currEnd: string;
core: CoreStart;
}) => {
const history = useHistory();
const location = useLocation();
const [pagination, setPagination] = useState({ pageIndex: 0 });

useEffect(() => {
core.chrome.setBreadcrumbs([
{
text: 'Query insights',
href: QUERY_INSIGHTS,
onClick: (e) => {
e.preventDefault();
history.push(QUERY_INSIGHTS);
},
},
]);
}, [core.chrome, history, location]);

const convertTime = (unixTime: number) => {
const date = new Date(unixTime);
const loc = date.toDateString().split(' ');
Expand All @@ -31,11 +57,12 @@ const QueryInsights = ({

const cols: Array<EuiBasicTableColumn<any>> = [
{
name: 'Time stamp',
// Make into flyout instead?
name: 'Timestamp',
render: (query: any) => {
return (
<span>
<EuiLink onClick={() => history.push(`/query-details/${query.node_id}`)}>
<EuiLink onClick={() => history.push(`/query-details/${hash(query)}`)}>
{convertTime(query.timestamp)}
</EuiLink>
</span>
Expand All @@ -47,28 +74,30 @@ const QueryInsights = ({
{
field: LATENCY_FIELD,
name: 'Latency',
render: (latency: number) => `${latency} ms`,
render: (latency: number) =>
typeof latency !== 'undefined' ? `${latency} ms` : `${METRIC_DEFAULT_MSG}`,
sortable: true,
truncateText: true,
},
{
field: CPU_FIELD,
name: 'CPU usage',
render: (cpu: number) => `${cpu} ns`,
render: (cpu: number) => (typeof cpu !== 'undefined' ? `${cpu} ns` : `${METRIC_DEFAULT_MSG}`),
sortable: true,
truncateText: true,
},
{
field: MEMORY_FIELD,
name: 'Memory',
render: (memory: number) => `${memory} B`,
render: (memory: number) =>
typeof memory !== 'undefined' ? `${memory} B` : `${METRIC_DEFAULT_MSG}`,
sortable: true,
truncateText: true,
},
{
field: INDICES_FIELD,
name: 'Indices',
render: (indices: string[]) => indices.toString(),
render: (indices: string[]) => Array.from(new Set(indices.flat())).join(', '),
sortable: true,
truncateText: true,
},
Expand All @@ -93,27 +122,15 @@ const QueryInsights = ({
},
];

const [recentlyUsedRanges, setRecentlyUsedRanges] = useState([
{ start: defaultStart, end: 'now' },
]);
const [currStart, setStart] = useState(defaultStart);
const [currEnd, setEnd] = useState('now');

const onTimeChange = ({ start, end }: { start: string; end: string }) => {
const usedRange = recentlyUsedRanges.filter(
(range) => !(range.start === start && range.end === end)
);
usedRange.unshift({ start, end });
setStart(start);
setEnd(end);
setRecentlyUsedRanges(usedRange.length > 10 ? usedRange.slice(0, 9) : usedRange);
onQueriesChange(start, end);
};

const onRefresh = async ({ start, end }: { start: string; end: string }) => {
onQueriesChange(start, end);
onTimeChange({ start, end });
};

const filterDuplicates = (options: any[]) =>
options.filter(
(value, index, self) => index === self.findIndex((t) => t.value === value.value)
);

return (
<EuiInMemoryTable
items={queries}
Expand All @@ -124,18 +141,64 @@ const QueryInsights = ({
direction: 'desc',
},
}}
onTableChange={({ page: { index } }) => setPagination({ pageIndex: index })}
pagination={pagination}
loading={loading}
search={{
box: {
placeholder: 'Search queries',
schema: false,
},
filters: [
{
type: 'field_value_selection',
field: INDICES_FIELD,
name: 'Indices',
multiSelect: true,
options: filterDuplicates(
queries.map((query) => {
const values = Array.from(new Set(query[INDICES_FIELD].flat()));
return {
value: values.join(','),
name: values.join(','),
view: values.join(', '),
};
})
),
},
{
type: 'field_value_selection',
field: SEARCH_TYPE_FIELD,
name: 'Search type',
multiSelect: false,
options: filterDuplicates(
queries.map((query) => ({
value: query[SEARCH_TYPE_FIELD],
name: query[SEARCH_TYPE_FIELD],
view: query[SEARCH_TYPE_FIELD],
}))
),
},
{
type: 'field_value_selection',
field: NODE_ID_FIELD,
name: 'Coordinator node ID',
multiSelect: true,
options: filterDuplicates(
queries.map((query) => ({
value: query[NODE_ID_FIELD],
name: query[NODE_ID_FIELD],
view: query[NODE_ID_FIELD].replaceAll('_', ' '),
}))
),
},
],
toolsRight: [
<EuiSuperDatePicker
start={currStart}
end={currEnd}
recentlyUsedRanges={recentlyUsedRanges}
onTimeChange={onTimeChange}
recentlyUsedRanges={recentlyUsedRanges}
onRefresh={onRefresh}
updateButtonProps={{ fill: false }}
/>,
Expand Down
113 changes: 52 additions & 61 deletions public/pages/TopNQueries/TopNQueries.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
import React, { useState, useEffect, useCallback, useMemo } from 'react';
import { useHistory, useLocation, Switch, Route, Redirect } from 'react-router-dom';
import { EuiTab, EuiTabs, EuiTitle } from '@elastic/eui';
import dateMath from '@elastic/datemath';
import React, { useCallback, useEffect, useState } from 'react';
import { Redirect, Route, Switch, useHistory, useLocation } from 'react-router-dom';
import { EuiTab, EuiTabs, EuiTitle, EuiSpacer } from '@elastic/eui';
import QueryInsights from '../QueryInsights/QueryInsights';
import { CoreStart } from '../../../../../src/core/public';

const QUERY_INSIGHTS = '/queryInsights';
const CONFIGURATION = '/configuration';

export interface MetricSettings {
isEnabled: boolean;
currTopN: string;
currWindowSize: string;
currTimeUnit: string;
}

const TopNQueries = ({ core }: { core: CoreStart }) => {
const history = useHistory();
const location = useLocation();
const [loading, setLoading] = useState(false);
const defaultStart: string = 'now-1d';
const allQueries = useMemo(() => [], []);
const [currStart, setStart] = useState('now-1d');
const [currEnd, setEnd] = useState('now');
const [recentlyUsedRanges, setRecentlyUsedRanges] = useState([
{ start: currStart, end: currEnd },
]);

const [queries, setQueries] = useState<any[]>([]);

const tabs: Array<{ id: string; name: string; route: string }> = [
Expand All @@ -22,11 +31,6 @@ const TopNQueries = ({ core }: { core: CoreStart }) => {
name: 'Top N queries',
route: QUERY_INSIGHTS,
},
{
id: 'configuration',
name: 'Configuration',
route: CONFIGURATION,
},
];

const onSelectedTabChanged = (route: string) => {
Expand All @@ -46,46 +50,38 @@ const TopNQueries = ({ core }: { core: CoreStart }) => {
</EuiTab>
);

const parseDateString = (dateString: string) => {
const date = dateMath.parse(dateString);
return date ? date.toDate().getTime() : new Date().getTime();
const retrieveQueries = useCallback(async (start: string, end: string) => {
try {
setLoading(true);
const noDuplicates: any[] = [];
setQueries(noDuplicates);
} catch (error) {
// eslint-disable-next-line no-console
console.error('Error retrieving queries:', error);
} finally {
setLoading(false);
}
}, []);

const onTimeChange = ({ start, end }: { start: string; end: string }) => {
const usedRange = recentlyUsedRanges.filter(
(range) => !(range.start === start && range.end === end)
);
usedRange.unshift({ start, end });
setStart(start);
setEnd(end);
setRecentlyUsedRanges(usedRange.length > 10 ? usedRange.slice(0, 9) : usedRange);
retrieveQueries(start, end);
};

const retrieveQueries = useCallback(
async (start: string, end: string) => {
setLoading(true);
try {
const startTimestamp = parseDateString(start);
const endTimestamp = parseDateString(end);
setQueries((prevQueries) => {
// @ts-ignore
const newQueries = allQueries.filter(
(item) => item.timestamp >= startTimestamp && item.timestamp <= endTimestamp
);
return newQueries;
});
} catch (error) {
// console.error('Failed to retrieve queries:', error);
} finally {
setLoading(false);
}
},
[allQueries]
);
useEffect(() => {
onTimeChange({ start: currStart, end: currEnd });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currStart, currEnd]);

useEffect(() => {
retrieveQueries(defaultStart, 'now');
core.chrome.setBreadcrumbs([
{
text: 'Query insights',
href: '/queryInsights',
onClick: (e) => {
e.preventDefault();
history.push('/queryInsights');
},
},
]);
}, [retrieveQueries, core.chrome, history, defaultStart]);
retrieveQueries(currStart, currEnd);
}, [currStart, currEnd, retrieveQueries]);

return (
<div style={{ padding: '35px 35px' }}>
Expand All @@ -94,24 +90,19 @@ const TopNQueries = ({ core }: { core: CoreStart }) => {
<EuiTitle size="l">
<h1>Query insights - Top N queries</h1>
</EuiTitle>
<div style={{ padding: '25px 0px' }}>
<EuiTabs>{tabs.map(renderTab)}</EuiTabs>
</div>
<EuiSpacer size="l" />
<EuiTabs>{tabs.map(renderTab)}</EuiTabs>
<EuiSpacer size="l" />
<QueryInsights
queries={queries}
loading={loading}
onQueriesChange={retrieveQueries}
defaultStart={defaultStart}
onTimeChange={onTimeChange}
recentlyUsedRanges={recentlyUsedRanges}
currStart={currStart}
currEnd={currEnd}
core={core}
/>
</Route>
<Route exact path={CONFIGURATION}>
<EuiTitle size="l">
<h1>Query insights - Configuration</h1>
</EuiTitle>
<div style={{ padding: '25px 0px' }}>
<EuiTabs>{tabs.map(renderTab)}</EuiTabs>
</div>
</Route>
<Redirect to={QUERY_INSIGHTS} />
</Switch>
</div>
Expand Down

0 comments on commit 6c8cd1f

Please sign in to comment.