Skip to content

Commit

Permalink
Monitoring Dashboards: Add stacked area graphs
Browse files Browse the repository at this point in the history
  • Loading branch information
kyoto committed Jan 15, 2020
1 parent 154760d commit 7d86011
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 50 deletions.
4 changes: 3 additions & 1 deletion frontend/public/components/monitoring/dashboards/graph.tsx
Expand Up @@ -2,17 +2,19 @@ import * as React from 'react';

import { QueryBrowser } from '../query-browser';

const Graph: React.FC<Props> = ({ pollInterval, queries, timespan }) => (
const Graph: React.FC<Props> = ({ isStack, pollInterval, queries, timespan }) => (
<QueryBrowser
defaultSamples={30}
defaultTimespan={timespan}
hideControls
isStack={isStack}
pollInterval={pollInterval}
queries={queries}
/>
);

type Props = {
isStack: boolean;
pollInterval: number;
queries: string[];
timespan: number;
Expand Down
7 changes: 6 additions & 1 deletion frontend/public/components/monitoring/dashboards/index.tsx
Expand Up @@ -120,7 +120,12 @@ const Card_: React.FC<CardProps> = ({ panel, pollInterval, timespan, variables }
<DashboardCardBody>
{panel.type === 'grafana-piechart-panel' && <BarChart query={queries[0]} />}
{panel.type === 'graph' && (
<Graph pollInterval={pollInterval} queries={queries} timespan={timespan} />
<Graph
isStack={panel.stack}
pollInterval={pollInterval}
queries={queries}
timespan={timespan}
/>
)}
{panel.type === 'row' && !_.isEmpty(panel.panels) && (
<div className="row">
Expand Down
1 change: 1 addition & 0 deletions frontend/public/components/monitoring/dashboards/types.ts
Expand Up @@ -12,6 +12,7 @@ export type Panel = {
postfix?: string;
prefix?: string;
span: number;
stack: boolean;
targets: {
expr: string;
};
Expand Down
129 changes: 81 additions & 48 deletions frontend/public/components/monitoring/query-browser.tsx
Expand Up @@ -3,9 +3,11 @@ import * as React from 'react';
import * as _ from 'lodash-es';
import {
Chart,
ChartArea,
ChartAxis,
ChartGroup,
ChartLine,
ChartStack,
ChartThemeColor,
ChartThemeVariant,
ChartTooltip,
Expand Down Expand Up @@ -223,59 +225,78 @@ const graphContainer = (
/>
);

const Graph: React.FC<GraphProps> = React.memo(({ allSeries, disabledSeries, span, xDomain }) => {
const [containerRef, width] = useRefWidth();
const Graph: React.FC<GraphProps> = React.memo(
({ allSeries, disabledSeries, isStack, span, xDomain }) => {
const [containerRef, width] = useRefWidth();

// Remove any disabled series
const data = _.flatMap(allSeries, (series, i) => {
return _.map(series, ([metric, values]) => {
return _.some(disabledSeries[i], (s) => _.isEqual(s, metric)) ? [{}] : values;
// Remove any disabled series
const data = _.flatMap(allSeries, (series, i) => {
return _.map(series, ([metric, values]) => {
return _.some(disabledSeries[i], (s) => _.isEqual(s, metric)) ? [{}] : values;
});
});
});

// Set a reasonable Y-axis range based on the min and max values in the data
const findMin = (series) => _.minBy(series, 'y');
const findMax = (series) => _.maxBy(series, 'y');
let minY = _.get(findMin(_.map(data, findMin)), 'y', 0);
let maxY = _.get(findMax(_.map(data, findMax)), 'y', 0);
if (minY === 0 && maxY === 0) {
minY = -1;
maxY = 1;
} else if (minY > 0 && maxY > 0) {
minY = 0;
} else if (minY < 0 && maxY < 0) {
maxY = 0;
}
const domain = { x: xDomain || [Date.now() - span, Date.now()], y: undefined };

let yTickFormat = formatValue;

if (!isStack) {
// Set a reasonable Y-axis range based on the min and max values in the data
const findMin = (series) => _.minBy(series, 'y');
const findMax = (series) => _.maxBy(series, 'y');
let minY = _.get(findMin(_.map(data, findMin)), 'y', 0);
let maxY = _.get(findMax(_.map(data, findMax)), 'y', 0);
if (minY === 0 && maxY === 0) {
minY = -1;
maxY = 1;
} else if (minY > 0 && maxY > 0) {
minY = 0;
} else if (minY < 0 && maxY < 0) {
maxY = 0;
}

const xTickFormat = span < 5 * 60 * 1000 ? twentyFourHourTimeWithSeconds : twentyFourHourTime;
domain.y = [minY, maxY];

const yTickFormat =
Math.abs(maxY - minY) < 0.005 ? (v) => (v === 0 ? '0' : v.toExponential(1)) : formatValue;
if (Math.abs(maxY - minY) < 0.005) {
yTickFormat = (v) => (v === 0 ? '0' : v.toExponential(1));
}
}

return (
<div ref={containerRef} style={{ width: '100%' }}>
{width > 0 && (
<Chart
containerComponent={graphContainer}
domain={{ x: xDomain || [Date.now() - span, Date.now()], y: [minY, maxY] }}
domainPadding={{ y: 1 }}
height={200}
scale={{ x: 'time', y: 'linear' }}
theme={chartTheme}
width={width}
>
<ChartAxis tickCount={5} tickFormat={xTickFormat} />
<ChartAxis crossAxis={false} dependentAxis tickCount={6} tickFormat={yTickFormat} />
<ChartGroup>
{_.map(data, (values, i) => (
<ChartLine key={i} data={values} />
))}
</ChartGroup>
</Chart>
)}
</div>
);
});
const xTickFormat = span < 5 * 60 * 1000 ? twentyFourHourTimeWithSeconds : twentyFourHourTime;

return (
<div ref={containerRef} style={{ width: '100%' }}>
{width > 0 && (
<Chart
containerComponent={graphContainer}
domain={domain}
domainPadding={{ y: 1 }}
height={200}
scale={{ x: 'time', y: 'linear' }}
theme={chartTheme}
width={width}
>
<ChartAxis tickCount={5} tickFormat={xTickFormat} />
<ChartAxis crossAxis={false} dependentAxis tickCount={6} tickFormat={yTickFormat} />
{isStack ? (
<ChartStack>
{_.map(data, (values, i) => (
<ChartArea key={i} data={values} />
))}
</ChartStack>
) : (
<ChartGroup>
{_.map(data, (values, i) => (
<ChartLine key={i} data={values} />
))}
</ChartGroup>
)}
</Chart>
)}
</div>
);
},
);

const formatSeriesValues = (
values: PrometheusValue[],
Expand Down Expand Up @@ -331,6 +352,7 @@ const minPollInterval = 10 * 1000;
const ZoomableGraph: React.FC<ZoomableGraphProps> = ({
allSeries,
disabledSeries,
isStack,
onZoom,
span,
xDomain,
Expand Down Expand Up @@ -386,7 +408,13 @@ const ZoomableGraph: React.FC<ZoomableGraphProps> = ({
style={{ left: Math.min(x1, x2), width: Math.abs(x1 - x2) }}
/>
)}
<Graph allSeries={allSeries} disabledSeries={disabledSeries} span={span} xDomain={xDomain} />
<Graph
allSeries={allSeries}
disabledSeries={disabledSeries}
isStack={isStack}
span={span}
xDomain={xDomain}
/>
</div>
);
};
Expand All @@ -399,6 +427,7 @@ const QueryBrowser_: React.FC<QueryBrowserProps> = ({
GraphLink,
hideControls,
hideGraphs,
isStack = false,
namespace,
patchQuery,
pollInterval,
Expand Down Expand Up @@ -585,6 +614,7 @@ const QueryBrowser_: React.FC<QueryBrowserProps> = ({
<ZoomableGraph
allSeries={graphData}
disabledSeries={disabledSeries}
isStack={isStack}
onZoom={onZoom}
span={span}
xDomain={xDomain}
Expand Down Expand Up @@ -627,13 +657,15 @@ type PrometheusValue = [number, string];
type GraphProps = {
allSeries: Series[];
disabledSeries?: Labels[][];
isStack?: boolean;
span: number;
xDomain?: AxisDomain;
};

type ZoomableGraphProps = {
allSeries: Series[];
disabledSeries?: Labels[][];
isStack?: boolean;
onZoom: (from: number, to: number) => void;
span: number;
xDomain?: AxisDomain;
Expand All @@ -647,6 +679,7 @@ type QueryBrowserProps = {
GraphLink?: React.ComponentType<{}>;
hideControls?: boolean;
hideGraphs: boolean;
isStack?: boolean;
namespace?: string;
patchQuery: (index: number, patch: QueryObj) => any;
pollInterval?: number;
Expand Down

0 comments on commit 7d86011

Please sign in to comment.