Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug 1827753: autoselect query from metric dropdown #5184

Merged
merged 1 commit into from May 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -1,12 +1,13 @@
import * as React from 'react';
import * as _ from 'lodash';
// FIXME upgrading redux types is causing many errors at this time
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
import { useSelector, useDispatch } from 'react-redux';
import * as fuzzy from 'fuzzysearch';
import { RootState } from '@console/internal/redux';
import { Button } from '@patternfly/react-core';
import { Dropdown } from '@console/internal/components/utils';
import { Dropdown, removeQueryArgument } from '@console/internal/components/utils';
import { queryBrowserRunQueries, queryBrowserPatchQuery } from '@console/internal/actions/ui';
import { getActiveNamespace } from '@console/internal/reducers/ui';
import { QueryInput } from '@console/internal/components/monitoring/metrics';
Expand All @@ -17,7 +18,11 @@ import './MetricsQueryInput.scss';
const ADD_NEW_QUERY = '#ADD_NEW_QUERY#';
const CUSTOM_QUERY = 'Custom Query';

const MetricsQueryInput: React.FC = () => {
type MetricsQueryInputProps = {
query?: string;
};

const MetricsQueryInput: React.FC<MetricsQueryInputProps> = ({ query }) => {
const items = metricsQuery;
const autocompleteFilter = (strText, item) => fuzzy(strText, item);
const defaultActionItem = [
Expand All @@ -32,8 +37,8 @@ const MetricsQueryInput: React.FC = () => {
state.UI.getIn(['queryBrowser', 'queries', 0]).toJS(),
);
const dispatch = useDispatch();

const [title, setTitle] = React.useState('Select Query');
const [selectedKey, setSelectedKey] = React.useState('');
const [metric, setMetric] = React.useState('');
const [showPromQl, setShowPromQl] = React.useState(false);
const [isPromQlDisabled, setIsPromQlDisabled] = React.useState(false);
Expand All @@ -48,13 +53,26 @@ const MetricsQueryInput: React.FC = () => {
}, [dispatch, metric, namespace]);

React.useEffect(() => {
const query = queries?.query;
const q = queries?.query;
const text = queries?.text;
if (text && text.localeCompare(query) !== 0) {
if (text && text.localeCompare(q) !== 0) {
setTitle(CUSTOM_QUERY);
setIsPromQlDisabled(true);
if (query) {
removeQueryArgument('query0');
}
Comment on lines +61 to +63
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the use of this , i see one in onChange

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It removes query params from the URL. If the user starts editing the promql or changes the query using the query dropdown.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we handle both scenarios in hook itself

}
}, [queries]);
}, [query, queries]);

React.useEffect(() => {
if (query) {
const topMetricsQueries = getTopMetricsQueries(namespace);
const selectedQuery = _.findKey(topMetricsQueries, (topQuery) => topQuery === query);
const sKey = _.findKey(items, (item) => item === selectedQuery);
setMetric(selectedQuery);
selectedQuery ? setSelectedKey(sKey) : setTitle(CUSTOM_QUERY);
}
}, [query, namespace, items]);

const onChange = (selectedValue: string) => {
setMetric(metricsQuery[selectedValue]);
Expand All @@ -66,6 +84,9 @@ const MetricsQueryInput: React.FC = () => {
setTitle(metricsQuery[selectedValue]);
setIsPromQlDisabled(false);
}
if (query) {
removeQueryArgument('query0');
}
};

return (
Expand All @@ -75,6 +96,7 @@ const MetricsQueryInput: React.FC = () => {
<Dropdown
autocompleteFilter={autocompleteFilter}
items={items || {}}
selectedKey={selectedKey}
actionItems={defaultActionItem}
dropDownClassName="odc-metrics-query-input dropdown--full-width"
menuClassName="odc-metrics-query-input__menu dropdown-menu--text-wrap"
Expand Down
Expand Up @@ -16,8 +16,10 @@ export const MonitoringMetrics: React.FC<MonitoringMetricsProps> = ({ patchQuery
const params = getURLSearchParams();
const query = params.query0;
React.useEffect(() => {
patchQuery({ text: query });
runQueries();
if (query) {
patchQuery({ text: query });
runQueries();
}
}, [query, patchQuery, runQueries]);

return (
Expand All @@ -26,7 +28,7 @@ export const MonitoringMetrics: React.FC<MonitoringMetricsProps> = ({ patchQuery
<title>Metrics</title>
</Helmet>
<div className="co-m-pane__body">
<MetricsQueryInput />
<MetricsQueryInput query={query} />
<div className="row">
<div className="col-xs-12">
<ConnectedMetricsChart />
Expand Down
63 changes: 30 additions & 33 deletions frontend/packages/dev-console/src/components/monitoring/queries.ts
Expand Up @@ -24,42 +24,10 @@ export const metricsQuery = {
PODS_BY_NETWORK_OUT: 'Transmit Bandwidth',
};

const topMetricsQueries = {
[metricsQuery.PODS_BY_CPU]: _.template(
`topk(25, sort_desc(sum(avg_over_time(pod:container_cpu_usage:sum{container="",pod!="",namespace='<%= namespace %>'}[5m])) BY (pod, namespace)))`,
),
[metricsQuery.PODS_BY_MEMORY]: _.template(
`topk(25, sort_desc(sum(avg_over_time(container_memory_working_set_bytes{container="",pod!="",namespace='<%= namespace %>'}[5m])) BY (pod, namespace)))`,
),
[metricsQuery.PODS_BY_FILESYSTEM]: _.template(
`topk(25, sort_desc(sum(pod:container_fs_usage_bytes:sum{container="",pod!="",namespace='<%= namespace %>'}) BY (pod, namespace)))`,
),
[metricsQuery.PODS_BY_NETWORK_IN]: _.template(
`topk(25, sort_desc(sum(rate(container_network_receive_bytes_total{ container="POD", pod!= "", namespace='<%= namespace %>'}[5m])) BY (namespace, pod)))`,
),
[metricsQuery.PODS_BY_NETWORK_OUT]: _.template(
`topk(25, sort_desc(sum(rate(container_network_transmit_bytes_total{ container="POD", pod!= "", namespace='<%= namespace %>'}[5m])) BY (namespace, pod)))`,
),
};

export const getTopMetricsQueries = (namespace: string) => ({
[metricsQuery.PODS_BY_CPU]: topMetricsQueries[metricsQuery.PODS_BY_CPU]({ namespace }),
[metricsQuery.PODS_BY_MEMORY]: topMetricsQueries[metricsQuery.PODS_BY_MEMORY]({ namespace }),
[metricsQuery.PODS_BY_FILESYSTEM]: topMetricsQueries[metricsQuery.PODS_BY_FILESYSTEM]({
namespace,
}),
[metricsQuery.PODS_BY_NETWORK_IN]: topMetricsQueries[metricsQuery.PODS_BY_NETWORK_IN]({
namespace,
}),
[metricsQuery.PODS_BY_NETWORK_OUT]: topMetricsQueries[metricsQuery.PODS_BY_NETWORK_OUT]({
namespace,
}),
});

export const monitoringDashboardQueries: MonitoringQuery[] = [
{
query: _.template(
`sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_rate{cluster="",namespace='<%= namespace %>'}) by (pod)`,
`sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_rate{cluster="", namespace='<%= namespace %>'}) by (pod)`,
),
chartType: GraphTypes.area,
title: 'CPU Usage',
Expand Down Expand Up @@ -236,3 +204,32 @@ export const workloadMetricsQueries: MonitoringQuery[] = [
),
},
];

const getMetricsQuery = (title: string): _.TemplateExecutor => {
const queryObject = _.find(monitoringDashboardQueries, (q) => q.title === title);
return queryObject.query;
};

const topMetricsQueries = {
PODS_BY_CPU: getMetricsQuery('CPU Usage'),
PODS_BY_MEMORY: getMetricsQuery('Memory Usage'),
PODS_BY_FILESYSTEM: _.template(
`topk(25, sort_desc(sum(pod:container_fs_usage_bytes:sum{container="",pod!="",namespace='<%= namespace %>'}) BY (pod, namespace)))`,
),
PODS_BY_NETWORK_IN: getMetricsQuery('Receive Bandwidth'),
PODS_BY_NETWORK_OUT: getMetricsQuery('Transmit Bandwidth'),
};

export const getTopMetricsQueries = (namespace: string) => ({
[metricsQuery.PODS_BY_CPU]: topMetricsQueries.PODS_BY_CPU({ namespace }),
[metricsQuery.PODS_BY_MEMORY]: topMetricsQueries.PODS_BY_MEMORY({ namespace }),
[metricsQuery.PODS_BY_FILESYSTEM]: topMetricsQueries.PODS_BY_FILESYSTEM({
namespace,
}),
[metricsQuery.PODS_BY_NETWORK_IN]: topMetricsQueries.PODS_BY_NETWORK_IN({
namespace,
}),
[metricsQuery.PODS_BY_NETWORK_OUT]: topMetricsQueries.PODS_BY_NETWORK_OUT({
namespace,
}),
});