Skip to content

Commit

Permalink
Top n queries query details page (#9)
Browse files Browse the repository at this point in the history
* Added query-details page

Signed-off-by: Emily Guo <LilyCaroline1717@gmail.com>

* Include dependences in package.json

Signed-off-by: Emily Guo <35637792+LilyCaroline17@users.noreply.github.com>

* Fixed double config function

Signed-off-by: Emily Guo <LilyCaroline1717@gmail.com>

---------

Signed-off-by: Emily Guo <LilyCaroline1717@gmail.com>
Signed-off-by: Emily Guo <35637792+LilyCaroline17@users.noreply.github.com>
  • Loading branch information
LilyCaroline17 authored Sep 5, 2024
1 parent 405f5e7 commit 8a9e342
Show file tree
Hide file tree
Showing 5 changed files with 236 additions and 26 deletions.
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
"test:jest:update-snapshots": "yarn run test:jest -u",
"lint": "node ../../scripts/eslint ."
},
"dependencies": {
"object-hash": "^3.0.0",
"plotly.js-dist": "^2.34.0"
},
"resolutions": {
"@types/react": "^16.9.8",
"**/@types/jest": "^29.3.1",
Expand Down
71 changes: 71 additions & 0 deletions public/pages/QueryDetails/Components/QuerySummary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React from 'react';
import { EuiFlexGrid, EuiFlexItem, EuiHorizontalRule, EuiPanel, EuiText } from '@elastic/eui';

const QuerySummary = ({ query }: { query: any }) => {
const convertTime = (unixTime: number) => {
const date = new Date(unixTime);
const loc = date.toDateString().split(' ');
return `${loc[1]} ${loc[2]}, ${loc[3]} @ ${date.toLocaleTimeString('en-US')}`;
};
return (
<EuiPanel>
<EuiText size="xs">
<h2>Summary</h2>
</EuiText>
<EuiHorizontalRule margin="m" />
<EuiFlexGrid columns={4}>
<EuiFlexItem>
<EuiText size="xs">
<h4>Timestamp</h4>
</EuiText>
<EuiText size="xs">{convertTime(query.timestamp)}</EuiText>
</EuiFlexItem>
<EuiFlexItem>
<EuiText size="xs">
<h4>Latency</h4>
</EuiText>
<EuiText size="xs">{`${query.latency} ms`}</EuiText>
</EuiFlexItem>
<EuiFlexItem>
<EuiText size="xs">
<h4>CPU Usage</h4>
</EuiText>
<EuiText size="xs">{`${query.cpu} ns`}</EuiText>
</EuiFlexItem>
<EuiFlexItem>
<EuiText size="xs">
<h4>Memory</h4>
</EuiText>
<EuiText size="xs">{`${query.memory} B`}</EuiText>
</EuiFlexItem>
<EuiFlexItem>
<EuiText size="xs">
<h4>Indexes</h4>
</EuiText>
<EuiText size="xs">{query.indices.toString()}</EuiText>
</EuiFlexItem>
<EuiFlexItem>
<EuiText size="xs">
<h4>Search type</h4>
</EuiText>
<EuiText size="xs">{query.search_type.replaceAll('_', ' ')}</EuiText>
</EuiFlexItem>
<EuiFlexItem>
<EuiText size="xs">
<h4>Coordinator node ID</h4>
</EuiText>
<EuiText size="xs">{query.node_id}</EuiText>
</EuiFlexItem>
<EuiFlexItem>
<EuiText size="xs">
<h4>Total shards</h4>
</EuiText>
<EuiText size="xs">{query.total_shards}</EuiText>
</EuiFlexItem>
</EuiFlexGrid>
</EuiPanel>
);
};

// eslint-disable-next-line import/no-default-export
export default QuerySummary;
148 changes: 148 additions & 0 deletions public/pages/QueryDetails/QueryDetails.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import React, { useEffect } from 'react';
import Plotly from 'plotly.js-dist';
import {
EuiButton,
EuiCodeBlock,
EuiFlexGrid,
EuiFlexGroup,
EuiFlexItem,
EuiHorizontalRule,
EuiPanel,
EuiSpacer,
EuiText,
EuiTitle,
} from '@elastic/eui';
import hash from 'object-hash';
import { useParams, useHistory, useLocation } from 'react-router-dom';
import { CoreStart } from '../../../../../src/core/public';
import QuerySummary from './Components/QuerySummary';
import { QUERY_INSIGHTS } from '../TopNQueries/TopNQueries';

const QueryDetails = ({ queries, core }: { queries: any; core: CoreStart }) => {
const { hashedQuery } = useParams<{ hashedQuery: string }>();
const query = queries.find((q: any) => hash(q) === hashedQuery);

const convertTime = (unixTime: number) => {
const date = new Date(unixTime);
const loc = date.toDateString().split(' ');
return loc[1] + ' ' + loc[2] + ', ' + loc[3] + ' @ ' + date.toLocaleTimeString('en-US');
};

const history = useHistory();
const location = useLocation();

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

useEffect(() => {
let x: number[] = Object.values(query.phase_latency_map);
if (x.length < 3) {
x = [0, 0, 0];
}
const data = [
{
x: x.reverse(),
y: ['Fetch ', 'Query ', 'Expand '],
type: 'bar',
orientation: 'h',
width: 0.5,
marker: { color: ['#F990C0', '#1BA9F5', '#7DE2D1'] },
base: [x[2] + x[1], x[2], 0],
text: x.map((value) => `${value}ms`),
textposition: 'outside',
cliponaxis: false,
},
];
const layout = {
autosize: true,
margin: { l: 80, r: 80, t: 25, b: 15, pad: 0 },
autorange: true,
height: 120,
xaxis: {
side: 'top',
zeroline: false,
ticksuffix: 'ms',
autorangeoptions: { clipmin: 0 },
tickfont: { color: '#535966' },
linecolor: '#D4DAE5',
gridcolor: '#D4DAE5',
},
yaxis: { linecolor: '#D4DAE5' },
};
const config = { responsive: true };
Plotly.newPlot('latency', data, layout, config);
}, [query]);

const queryString = JSON.stringify(JSON.parse(JSON.stringify(query.source)), null, 2);
const queryDisplay = `{\n "query": ${queryString ? queryString.replace(/\n/g, '\n ') : ''}\n}`;

return (
<div>
<EuiTitle size="l">
<h1>Query details</h1>
</EuiTitle>
<EuiSpacer size="l" />
<EuiFlexItem>
<QuerySummary query={query} />
<EuiSpacer size="m" />
<EuiFlexGrid columns={2}>
<EuiFlexItem grow={1}>
<EuiPanel>
<EuiFlexGroup alignItems="center" justifyContent="spaceBetween">
<EuiFlexItem>
<EuiText size="xs">
<h2>Query</h2>
</EuiText>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton
iconSide="right"
iconType="popout"
target="_blank"
href="https://playground.opensearch.org/app/searchRelevance#/"
>
Open in search comparision
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
<EuiHorizontalRule margin="xs" />
<EuiSpacer size="xs" />
<EuiCodeBlock
language="jsx"
paddingSize="m"
fontSize="s"
overflowHeight={600}
isCopyable
>
{queryDisplay}
</EuiCodeBlock>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem grow={1} style={{ alignSelf: 'start' }}>
<EuiPanel>
<EuiText size="xs">
<h2>Latency</h2>
</EuiText>
<EuiHorizontalRule margin="m" />
<div id="latency" />
</EuiPanel>
</EuiFlexItem>
</EuiFlexGrid>
</EuiFlexItem>
</div>
);
};

// eslint-disable-next-line import/no-default-export
export default QueryDetails;
11 changes: 9 additions & 2 deletions public/pages/QueryInsights/QueryInsights.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useEffect, useState } from 'react';
import { EuiBasicTableColumn, EuiInMemoryTable, EuiSuperDatePicker } from '@elastic/eui';
import { EuiBasicTableColumn, EuiInMemoryTable, EuiLink, EuiSuperDatePicker } from '@elastic/eui';
import { useHistory, useLocation } from 'react-router-dom';
import hash from 'object-hash';
import { CoreStart } from '../../../../../src/core/public';
import { QUERY_INSIGHTS } from '../TopNQueries/TopNQueries';

Expand Down Expand Up @@ -59,7 +60,13 @@ const QueryInsights = ({
// Make into flyout instead?
name: 'Timestamp',
render: (query: any) => {
return <span>{convertTime(query.timestamp)}</span>;
return (
<span>
<EuiLink onClick={() => history.push(`/query-details/${hash(query)}`)}>
{convertTime(query.timestamp)}
</EuiLink>
</span>
);
},
sortable: (query) => query.timestamp,
truncateText: true,
Expand Down
28 changes: 4 additions & 24 deletions public/pages/TopNQueries/TopNQueries.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { EuiTab, EuiTabs, EuiTitle, EuiSpacer } from '@elastic/eui';
import dateMath from '@elastic/datemath';
import QueryInsights from '../QueryInsights/QueryInsights';
import Configuration from '../Configuration/Configuration';
import QueryDetails from '../QueryDetails/QueryDetails';
import { CoreStart } from '../../../../../src/core/public';

export const QUERY_INSIGHTS = '/queryInsights';
Expand Down Expand Up @@ -222,30 +223,6 @@ const TopNQueries = ({ core }: { core: CoreStart }) => {
[core]
);

const retrieveConfigInfo = useCallback(
async (
get: boolean,
enabled: boolean = false,
metric: string = '',
newTopN: string = '',
newWindowSize: string = '',
newTimeUnit: string = ''
) => {
try {
setMetricSettings(metric, {
isEnabled: enabled,
currTopN: newTopN,
currWindowSize: newWindowSize,
currTimeUnit: newTimeUnit,
});
} catch (error) {
// eslint-disable-next-line no-console
console.error('Failed to set settings:', error);
}
},
[]
);

const onTimeChange = ({ start, end }: { start: string; end: string }) => {
const usedRange = recentlyUsedRanges.filter(
(range) => !(range.start === start && range.end === end)
Expand All @@ -270,6 +247,9 @@ const TopNQueries = ({ core }: { core: CoreStart }) => {
return (
<div style={{ padding: '35px 35px' }}>
<Switch>
<Route exact path="/query-details/:hashedQuery">
<QueryDetails queries={queries} core={core} />
</Route>
<Route exact path={QUERY_INSIGHTS}>
<EuiTitle size="l">
<h1>Query insights - Top N queries</h1>
Expand Down

0 comments on commit 8a9e342

Please sign in to comment.