From 657fea868834ef239ab312381ac0956f3a84a07c Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Wed, 21 Mar 2018 13:36:43 -0600 Subject: Add summary statistics prometheus dashboard --- .../javascripts/monitoring/components/graph.vue | 32 ++-- .../monitoring/components/graph/axis.vue | 127 +++++++++++++ .../monitoring/components/graph/flag.vue | 2 +- .../monitoring/components/graph/legend.vue | 203 +++++---------------- .../monitoring/utils/multiple_time_series.js | 82 +++++++-- 5 files changed, 255 insertions(+), 191 deletions(-) create mode 100644 app/assets/javascripts/monitoring/components/graph/axis.vue (limited to 'app/assets/javascripts/monitoring') diff --git a/app/assets/javascripts/monitoring/components/graph.vue b/app/assets/javascripts/monitoring/components/graph.vue index 04d546fafa0..9bf32d8a2da 100644 --- a/app/assets/javascripts/monitoring/components/graph.vue +++ b/app/assets/javascripts/monitoring/components/graph.vue @@ -3,6 +3,7 @@ import { scaleLinear, scaleTime } from 'd3-scale'; import { axisLeft, axisBottom } from 'd3-axis'; import { max, extent } from 'd3-array'; import { select } from 'd3-selection'; +import GraphAxis from './graph/axis.vue'; import GraphLegend from './graph/legend.vue'; import GraphFlag from './graph/flag.vue'; import GraphDeployment from './graph/deployment.vue'; @@ -18,10 +19,11 @@ const d3 = { scaleLinear, scaleTime, axisLeft, axisBottom, max, extent, select } export default { components: { - GraphLegend, + GraphAxis, GraphFlag, GraphDeployment, GraphPath, + GraphLegend, }, mixins: [MonitoringMixin], props: { @@ -138,7 +140,7 @@ export default { this.legendTitle = query.label || 'Average'; this.graphWidth = this.$refs.baseSvg.clientWidth - this.margin.left - this.margin.right; this.graphHeight = this.graphHeight - this.margin.top - this.margin.bottom; - this.baseGraphHeight = this.graphHeight; + this.baseGraphHeight = this.graphHeight - 50; this.baseGraphWidth = this.graphWidth; // pixel offsets inside the svg and outside are not 1:1 @@ -177,14 +179,10 @@ export default { this.graphHeightOffset, ); - if (!this.showLegend) { - this.baseGraphHeight -= 50; - } else if (this.timeSeries.length > 3) { - this.baseGraphHeight = this.baseGraphHeight += (this.timeSeries.length - 3) * 20; - } - - const axisXScale = d3.scaleTime().range([0, this.graphWidth - 70]); - const axisYScale = d3.scaleLinear().range([this.graphHeight - this.graphHeightOffset, 0]); + const axisXScale = d3.scaleTime() + .range([0, this.graphWidth - 70]); + const axisYScale = d3.scaleLinear() + .range([this.graphHeight - this.graphHeightOffset, 0]); const allValues = this.timeSeries.reduce((all, { values }) => all.concat(values), []); axisXScale.domain(d3.extent(allValues, d => d.time)); @@ -251,17 +249,12 @@ export default { class="y-axis" transform="translate(70, 20)" /> - + diff --git a/app/assets/javascripts/monitoring/components/graph/axis.vue b/app/assets/javascripts/monitoring/components/graph/axis.vue new file mode 100644 index 00000000000..ae397fc39e2 --- /dev/null +++ b/app/assets/javascripts/monitoring/components/graph/axis.vue @@ -0,0 +1,127 @@ + + diff --git a/app/assets/javascripts/monitoring/components/graph/flag.vue b/app/assets/javascripts/monitoring/components/graph/flag.vue index 906c7c51f52..8e6a830f08c 100644 --- a/app/assets/javascripts/monitoring/components/graph/flag.vue +++ b/app/assets/javascripts/monitoring/components/graph/flag.vue @@ -160,7 +160,7 @@ export default {
- +
-import { formatRelevantDigits } from '../../../lib/utils/number_utils'; +import { formatRelevantDigits } from '~/lib/utils/number_utils'; export default { props: { - graphWidth: { - type: Number, - required: true, - }, - graphHeight: { - type: Number, - required: true, - }, - margin: { - type: Object, - required: true, - }, - measurements: { - type: Object, - required: true, - }, legendTitle: { type: String, required: true, }, - yAxisLabel: { - type: String, - required: true, - }, timeSeries: { type: Array, required: true, }, - unitOfDisplay: { - type: String, - required: true, - }, currentDataIndex: { type: Number, required: true, }, - showLegendGroup: { - type: Boolean, - required: false, - default: true, - }, - }, - data() { - return { - yLabelWidth: 0, - yLabelHeight: 0, - seriesXPosition: 0, - metricUsageXPosition: 0, - }; - }, - computed: { - textTransform() { - const yCoordinate = - (this.graphHeight - this.margin.top + this.measurements.axisLabelLineOffset) / 2 || 0; - - return `translate(15, ${yCoordinate}) rotate(-90)`; - }, - rectTransform() { - const yCoordinate = - (this.graphHeight - this.margin.top + this.measurements.axisLabelLineOffset) / 2 + - this.yLabelWidth / 2 || 0; - - return `translate(0, ${yCoordinate}) rotate(-90)`; - }, - xPosition() { - return (this.graphWidth + this.measurements.axisLabelLineOffset) / 2 - this.margin.right || 0; - }, - yPosition() { - return this.graphHeight - this.margin.top + this.measurements.axisLabelLineOffset || 0; + unitOfDisplay: { + type: String, + required: true, }, }, - mounted() { - this.$nextTick(() => { - const bbox = this.$refs.ylabel.getBBox(); - this.metricUsageXPosition = 0; - this.seriesXPosition = 0; - if (this.$refs.legendTitleSvg != null) { - this.seriesXPosition = this.$refs.legendTitleSvg[0].getBBox().width; - } - if (this.$refs.seriesTitleSvg != null) { - this.metricUsageXPosition = this.$refs.seriesTitleSvg[0].getBBox().width; - } - this.yLabelWidth = bbox.width + 10; // Added some padding - this.yLabelHeight = bbox.height + 5; - }); - }, methods: { - translateLegendGroup(index) { - return `translate(0, ${12 * index})`; - }, formatMetricUsage(series) { const value = - series.values[this.currentDataIndex] && series.values[this.currentDataIndex].value; + series.values[this.currentDataIndex] && + series.values[this.currentDataIndex].value; if (isNaN(value)) { return '-'; } return `${formatRelevantDigits(value)} ${this.unitOfDisplay}`; }, + createSeriesString(index, series) { if (series.metricTag) { return `${series.metricTag} ${this.formatMetricUsage(series)}`; } - return `${this.legendTitle} series ${index + 1} ${this.formatMetricUsage(series)}`; + return `${this.legendTitle} series ${index + 1} ${this.formatMetricUsage( + series, + )}`; + }, + + summaryMetrics(series) { + return `Avg: ${formatRelevantDigits(series.average)} ${this.unitOfDisplay}, + Max: ${formatRelevantDigits(series.max)} ${this.unitOfDisplay}`; }, + strokeDashArray(type) { if (type === 'dashed') return '6, 3'; if (type === 'dotted') return '3, 3'; @@ -116,89 +54,38 @@ export default { }; diff --git a/app/assets/javascripts/monitoring/utils/multiple_time_series.js b/app/assets/javascripts/monitoring/utils/multiple_time_series.js index b5b8e3c255d..95db31c7a2a 100644 --- a/app/assets/javascripts/monitoring/utils/multiple_time_series.js +++ b/app/assets/javascripts/monitoring/utils/multiple_time_series.js @@ -1,10 +1,20 @@ import _ from 'underscore'; import { scaleLinear, scaleTime } from 'd3-scale'; import { line, area, curveLinear } from 'd3-shape'; -import { extent, max } from 'd3-array'; +import { extent, max, sum } from 'd3-array'; import { timeMinute } from 'd3-time'; -const d3 = { scaleLinear, scaleTime, line, area, curveLinear, extent, max, timeMinute }; +const d3 = { + scaleLinear, + scaleTime, + line, + area, + curveLinear, + extent, + max, + timeMinute, + sum, +}; const defaultColorPalette = { blue: ['#1f78d1', '#8fbce8'], @@ -18,7 +28,15 @@ const defaultColorOrder = ['blue', 'orange', 'red', 'green', 'purple']; const defaultStyleOrder = ['solid', 'dashed', 'dotted']; -function queryTimeSeries(query, graphWidth, graphHeight, graphHeightOffset, xDom, yDom, lineStyle) { +function queryTimeSeries( + query, + graphWidth, + graphHeight, + graphHeightOffset, + xDom, + yDom, + lineStyle, +) { let usedColors = []; function pickColor(name) { @@ -42,11 +60,14 @@ function queryTimeSeries(query, graphWidth, graphHeight, graphHeightOffset, xDom let metricTag = ''; let lineColor = ''; let areaColor = ''; + const timeSeriesValues = timeSeries.values.map(d => d.value); + const maximumValue = d3.max(timeSeriesValues); + const accum = d3.sum(timeSeriesValues); - const timeSeriesScaleX = d3.scaleTime() - .range([0, graphWidth - 70]); + const timeSeriesScaleX = d3.scaleTime().range([0, graphWidth - 70]); - const timeSeriesScaleY = d3.scaleLinear() + const timeSeriesScaleY = d3 + .scaleLinear() .range([graphHeight - graphHeightOffset, 0]); timeSeriesScaleX.domain(xDom); @@ -55,28 +76,35 @@ function queryTimeSeries(query, graphWidth, graphHeight, graphHeightOffset, xDom const defined = d => !isNaN(d.value) && d.value != null; - const lineFunction = d3.line() + const lineFunction = d3 + .line() .defined(defined) .curve(d3.curveLinear) // d3 v4 uses curbe instead of interpolate .x(d => timeSeriesScaleX(d.time)) .y(d => timeSeriesScaleY(d.value)); - const areaFunction = d3.area() + const areaFunction = d3 + .area() .defined(defined) .curve(d3.curveLinear) .x(d => timeSeriesScaleX(d.time)) .y0(graphHeight - graphHeightOffset) .y1(d => timeSeriesScaleY(d.value)); - const timeSeriesMetricLabel = timeSeries.metric[Object.keys(timeSeries.metric)[0]]; - const seriesCustomizationData = query.series != null && + const timeSeriesMetricLabel = + timeSeries.metric[Object.keys(timeSeries.metric)[0]]; + const seriesCustomizationData = + query.series != null && _.findWhere(query.series[0].when, { value: timeSeriesMetricLabel }); if (seriesCustomizationData) { metricTag = seriesCustomizationData.value || timeSeriesMetricLabel; [lineColor, areaColor] = pickColor(seriesCustomizationData.color); } else { - metricTag = timeSeriesMetricLabel || query.label || `series ${timeSeriesNumber + 1}`; + metricTag = + timeSeriesMetricLabel || + query.label || + `series ${timeSeriesNumber + 1}`; [lineColor, areaColor] = pickColor(); } @@ -89,6 +117,8 @@ function queryTimeSeries(query, graphWidth, graphHeight, graphHeightOffset, xDom areaPath: areaFunction(timeSeries.values), timeSeriesScaleX, values: timeSeries.values, + max: maximumValue, + average: accum / timeSeries.values.length, lineStyle, lineColor, areaColor, @@ -97,10 +127,22 @@ function queryTimeSeries(query, graphWidth, graphHeight, graphHeightOffset, xDom }); } -export default function createTimeSeries(queries, graphWidth, graphHeight, graphHeightOffset) { - const allValues = queries.reduce((allQueryResults, query) => allQueryResults.concat( - query.result.reduce((allResults, result) => allResults.concat(result.values), []), - ), []); +export default function createTimeSeries( + queries, + graphWidth, + graphHeight, + graphHeightOffset, +) { + const allValues = queries.reduce( + (allQueryResults, query) => + allQueryResults.concat( + query.result.reduce( + (allResults, result) => allResults.concat(result.values), + [], + ), + ), + [], + ); const xDom = d3.extent(allValues, d => d.time); const yDom = [0, d3.max(allValues.map(d => d.value))]; @@ -108,7 +150,15 @@ export default function createTimeSeries(queries, graphWidth, graphHeight, graph return queries.reduce((series, query, index) => { const lineStyle = defaultStyleOrder[index % defaultStyleOrder.length]; return series.concat( - queryTimeSeries(query, graphWidth, graphHeight, graphHeightOffset, xDom, yDom, lineStyle), + queryTimeSeries( + query, + graphWidth, + graphHeight, + graphHeightOffset, + xDom, + yDom, + lineStyle, + ), ); }, []); } -- cgit v1.2.3