Skip to content

Commit

Permalink
adds monitoring metrics component
Browse files Browse the repository at this point in the history
  • Loading branch information
invincibleJai committed Jan 8, 2020
1 parent 196d87b commit eba9d22
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 1 deletion.
@@ -0,0 +1,21 @@
import * as React from 'react';
import {
EmptyState,
EmptyStateBody,
EmptyStateIcon,
EmptyStateVariant,
Title,
} from '@patternfly/react-core';
import { ChartLineIcon } from '@patternfly/react-icons';

const EmptyStateQuery: React.FC = () => (
<EmptyState variant={EmptyStateVariant.full}>
<EmptyStateIcon size="sm" icon={ChartLineIcon} />
<Title size="sm">No Query Entered</Title>
<EmptyStateBody>
Enter a query in the box below to explore metrics for this cluster.
</EmptyStateBody>
</EmptyState>
);

export default EmptyStateQuery;
@@ -0,0 +1,53 @@
import * as _ from 'lodash';
import * as React from 'react';
import { connect } from 'react-redux';
import { RootState } from '@console/internal/redux';
import { getActiveNamespace, queryBrowserDeleteAllQueries } from '@console/internal/actions/ui';
import { QueryBrowser, QueryObj } from '@console/internal/components/monitoring/query-browser';
import { QueryTable } from '@console/internal/components/monitoring/metrics';
import EmptyStateQuery from './EmptyStateQuery';

interface StateProps {
queries: QueryObj[];
}
type MetricsChartProps = {
deleteAll: () => never;
queries: QueryObj[];
};
const MetricsChart: React.FC<MetricsChartProps> = ({ deleteAll, queries }) => {
React.useEffect(() => deleteAll, [deleteAll]);
const namespace = getActiveNamespace();
/* eslint-disable react-hooks/exhaustive-deps */
// Use React.useMemo() to prevent these two arrays being recreated on every render, which would trigger unnecessary
// re-renders of QueryBrowser, which can be quite slow
const queriesMemoKey = JSON.stringify(_.map(queries, 'query'));
const queryStrings = React.useMemo(() => _.map(queries, 'query'), [queriesMemoKey]);
const disabledSeriesMemoKey = JSON.stringify(
_.reject(_.map(queries, 'disabledSeries'), _.isEmpty),
);
const disabledSeries = React.useMemo(() => _.map(queries, 'disabledSeries'), [
disabledSeriesMemoKey,
]);
return queryStrings.join('') === '' ? (
<EmptyStateQuery />
) : (
<>
<QueryBrowser
defaultTimespan={30 * 60 * 1000}
disabledSeries={disabledSeries}
namespace={namespace}
queries={queryStrings}
/>
<QueryTable index={0} namespace={namespace} />
</>
);
};

const mapStateToProps = ({ UI }: RootState): StateProps => ({
queries: UI.getIn(['queryBrowser', 'queries']).toJS(),
});

export default connect(
mapStateToProps,
{ deleteAll: queryBrowserDeleteAllQueries },
)(MetricsChart);
@@ -0,0 +1,8 @@
.odc-metrics-dropdown {
margin-bottom: 20px;
&__menu {
max-height: 50vh;
overflow: auto;
width: 100%;
}
}
@@ -0,0 +1,63 @@
import * as React from 'react';
import { connect } from 'react-redux';
import * as fuzzy from 'fuzzysearch';
import { Dropdown } from '@console/internal/components/utils';
import {
getActiveNamespace,
queryBrowserRunQueries,
queryBrowserPatchQuery,
} from '@console/internal/actions/ui';
import { QueryObj } from '@console/internal/components/monitoring/query-browser';
import { metricsQuery, getTopMetricsQueries } from '../queries';
import './MetricsDropdown.scss';

const ADD_NEW_QUERY = '#ADD_NEW_QUERY#';
export type MetricsDropdownProps = {
patchQuery: (patch: QueryObj) => void;
runQueries: () => never;
};

const MetricsDropdown: React.FC<MetricsDropdownProps> = ({ patchQuery, runQueries }) => {
const namespace = getActiveNamespace();
const items = metricsQuery;
const title: React.ReactNode = 'Select Query';
const autocompleteFilter = (text, item) => fuzzy(text, item);
const defaultActionItem = [
{
actionTitle: `Add Query`,
actionKey: ADD_NEW_QUERY,
},
];

const onChange = (metric: string) => {
if (metric !== ADD_NEW_QUERY) {
const query = getTopMetricsQueries(namespace)[metric];
patchQuery({ text: query });
runQueries();
}
};

return (
<Dropdown
autocompleteFilter={autocompleteFilter}
id="metrics-dropdown"
items={items || {}}
actionItems={defaultActionItem}
dropDownClassName="odc-metrics-dropdown dropdown--full-width"
menuClassName="odc-metrics-dropdown__menu dropdown-menu--text-wrap"
onChange={onChange}
title={title}
/>
);
};

const mapDispatchToProps = (dispatch) =>
Object.assign(
{ runQueries: () => dispatch(queryBrowserRunQueries()) },
{ patchQuery: (v: QueryObj) => dispatch(queryBrowserPatchQuery(0, v)) },
);

export default connect(
null,
mapDispatchToProps,
)(MetricsDropdown);
@@ -1,12 +1,26 @@
import * as React from 'react';
import { Helmet } from 'react-helmet';
import MetricsDropdown from './MetricsDropdown';
import MetricsChart from './MetricsChart';

const MonitoringMetrics: React.FC = () => {
return (
<>
<Helmet>
<title>Metrics</title>
</Helmet>
<div className="co-m-pane__body">
<div className="row">
<div className="col-xs-12 col-md-7">
<MetricsDropdown />
</div>
</div>
<div className="row">
<div className="col-xs-12">
<MetricsChart />
</div>
</div>
</div>
</>
);
};
Expand Down
32 changes: 32 additions & 0 deletions frontend/packages/dev-console/src/components/monitoring/queries.ts
@@ -0,0 +1,32 @@
import * as _ from 'lodash';

export const metricsQuery = {
PODS_BY_CPU: 'PODS_BY_CPU',
PODS_BY_MEMORY: 'PODS_BY_MEMORY',
PODS_BY_FILESYSTEM: 'PODS_BY_FILESYSTEM',
PODS_BY_NETWORK: 'PODS_BY_NETWORK',
};

const topMetricsQueries = {
[metricsQuery.PODS_BY_CPU]: _.template(
`topk(25, sort_desc(sum(avg_over_time(pod:container_cpu_usage:sum{container="",pod!="",namespace='<%= project %>'}[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='<%= project %>'}[5m])) BY (pod, namespace)))`,
),
[metricsQuery.PODS_BY_FILESYSTEM]: _.template(
`topk(25, sort_desc(sum(pod:container_fs_usage_bytes:sum{container="",pod!="",namespace='<%= project %>'}) BY (pod, namespace)))`,
),
[metricsQuery.PODS_BY_NETWORK]: _.template(
`topk(25, sort_desc(sum(rate(container_network_receive_bytes_total{ container="POD", pod!= "", namespace = '<%= project %>'}[5m]) + rate(container_network_transmit_bytes_total{ container="POD", pod!= "", namespace = '<%= project %>'}[5m])) BY (namespace, pod)))`,
),
};

export const getTopMetricsQueries = (project: string) => ({
[metricsQuery.PODS_BY_CPU]: topMetricsQueries[metricsQuery.PODS_BY_CPU]({ project }),
[metricsQuery.PODS_BY_MEMORY]: topMetricsQueries[metricsQuery.PODS_BY_MEMORY]({ project }),
[metricsQuery.PODS_BY_FILESYSTEM]: topMetricsQueries[metricsQuery.PODS_BY_FILESYSTEM]({
project,
}),
[metricsQuery.PODS_BY_NETWORK]: topMetricsQueries[metricsQuery.PODS_BY_NETWORK]({ project }),
});
2 changes: 1 addition & 1 deletion frontend/public/components/monitoring/metrics.tsx
Expand Up @@ -779,7 +779,7 @@ const QueryTable_: React.FC<QueryTableProps> = ({
</>
);
};
const QueryTable = connect(
export const QueryTable = connect(
queryTableStateToProps,
queryDispatchToProps,
)(QueryTable_);
Expand Down

0 comments on commit eba9d22

Please sign in to comment.