From 057e84d6e3997033584339c5c7df1d2278af8ebd Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Fri, 1 Sep 2017 16:28:23 -0500 Subject: Renamed some components --- .../javascripts/monitoring/components/graph.vue | 8 ++--- .../monitoring/components/graph_path.vue | 40 ++++++++++++++++++++++ .../monitoring/components/monitoring_paths.vue | 40 ---------------------- .../monitoring/utils/multiple_time_series.js | 31 +++-------------- .../unreleased/additional-time-series-charts.yml | 2 +- spec/javascripts/monitoring/graph_path_spec.js | 35 +++++++++++++++++++ .../monitoring/monitoring_paths_spec.js | 34 ------------------ .../monitoring/utils/multiple_time_series_spec.js | 13 +++---- 8 files changed, 92 insertions(+), 111 deletions(-) create mode 100644 app/assets/javascripts/monitoring/components/graph_path.vue delete mode 100644 app/assets/javascripts/monitoring/components/monitoring_paths.vue create mode 100644 spec/javascripts/monitoring/graph_path_spec.js delete mode 100644 spec/javascripts/monitoring/monitoring_paths_spec.js diff --git a/app/assets/javascripts/monitoring/components/graph.vue b/app/assets/javascripts/monitoring/components/graph.vue index cde2ff7ca2a..11bbeb9392b 100644 --- a/app/assets/javascripts/monitoring/components/graph.vue +++ b/app/assets/javascripts/monitoring/components/graph.vue @@ -3,7 +3,7 @@ import GraphLegend from './graph/legend.vue'; import GraphFlag from './graph/flag.vue'; import GraphDeployment from './graph/deployment.vue'; - import monitoringPaths from './monitoring_paths.vue'; + import GraphPath from './graph_path.vue'; import MonitoringMixin from '../mixins/monitoring_mixins'; import eventHub from '../event_hub'; import measurements from '../utils/measurements'; @@ -63,7 +63,7 @@ GraphLegend, GraphFlag, GraphDeployment, - monitoringPaths, + GraphPath, }, computed: { @@ -238,7 +238,7 @@ class="graph-data" :viewBox="innerViewBox" ref="graphData"> - - + export default { + props: { + generatedLinePath: { + type: String, + required: true, + }, + generatedAreaPath: { + type: String, + required: true, + }, + lineColor: { + type: String, + required: true, + }, + areaColor: { + type: String, + required: true, + }, + }, + }; + + diff --git a/app/assets/javascripts/monitoring/components/monitoring_paths.vue b/app/assets/javascripts/monitoring/components/monitoring_paths.vue deleted file mode 100644 index 043f1bf66bb..00000000000 --- a/app/assets/javascripts/monitoring/components/monitoring_paths.vue +++ /dev/null @@ -1,40 +0,0 @@ - - diff --git a/app/assets/javascripts/monitoring/utils/multiple_time_series.js b/app/assets/javascripts/monitoring/utils/multiple_time_series.js index 05d551e917c..c47da3daf80 100644 --- a/app/assets/javascripts/monitoring/utils/multiple_time_series.js +++ b/app/assets/javascripts/monitoring/utils/multiple_time_series.js @@ -15,6 +15,9 @@ export default function createTimeSeries(seriesData, graphWidth, graphHeight, gr let timeSeriesNumber = 1; let lineColor = '#1f78d1'; let areaColor = '#8fbce8'; + const lineColors = ['#1f78d1', '#fc9403', '#db3b21', '#1aaa55', '#6666c4']; + const areaColors = ['#8fbce8', '#feca81', '#ed9d90', '#8dd5aa', '#d1d1f0']; + return seriesData.map((timeSeries) => { const timeSeriesScaleX = d3.time.scale() .range([0, graphWidth - 70]); @@ -35,32 +38,8 @@ export default function createTimeSeries(seriesData, graphWidth, graphHeight, gr .y1(d => timeSeriesScaleY(d.value)) .interpolate('linear'); - switch (timeSeriesNumber) { - case 1: - lineColor = '#1f78d1'; - areaColor = '#8fbce8'; - break; - case 2: - lineColor = '#fc9403'; - areaColor = '#feca81'; - break; - case 3: - lineColor = '#db3b21'; - areaColor = '#ed9d90'; - break; - case 4: - lineColor = '#1aaa55'; - areaColor = '#8dd5aa'; - break; - case 5: - lineColor = '#6666c4'; - areaColor = '#d1d1f0'; - break; - default: - lineColor = '#1f78d1'; - areaColor = '#8fbce8'; - break; - } + lineColor = lineColors[timeSeriesNumber - 1]; + areaColor = areaColors[timeSeriesNumber - 1]; if (timeSeriesNumber <= 5) { timeSeriesNumber = timeSeriesNumber += 1; diff --git a/changelogs/unreleased/additional-time-series-charts.yml b/changelogs/unreleased/additional-time-series-charts.yml index 80c1af54881..d5fd24cf2e7 100644 --- a/changelogs/unreleased/additional-time-series-charts.yml +++ b/changelogs/unreleased/additional-time-series-charts.yml @@ -1,5 +1,5 @@ --- -title: Added support the multiple time series for prometheus monitoring +title: Added support for multiple time series merge_request: !36893 author: type: changed diff --git a/spec/javascripts/monitoring/graph_path_spec.js b/spec/javascripts/monitoring/graph_path_spec.js new file mode 100644 index 00000000000..105fb852e8e --- /dev/null +++ b/spec/javascripts/monitoring/graph_path_spec.js @@ -0,0 +1,35 @@ +import Vue from 'vue'; +import GraphPath from '~/monitoring/components/graph_path.vue'; +import createTimeSeries from '~/monitoring/utils/multiple_time_series'; +import { singleRowMetricsMultipleSeries, convertDatesMultipleSeries } from './mock_data'; + +const createComponent = (propsData) => { + const Component = Vue.extend(GraphPath); + + return new Component({ + propsData, + }).$mount(); +}; + +const convertedMetrics = convertDatesMultipleSeries(singleRowMetricsMultipleSeries); + +const timeSeries = createTimeSeries(convertedMetrics[0].queries[0].result, 428, 272, 120); +const firstTimeSeries = timeSeries[0]; + +describe('Monitoring Paths', () => { + it('renders two paths to represent a line and the area underneath it', () => { + const component = createComponent({ + generatedLinePath: firstTimeSeries.linePath, + generatedAreaPath: firstTimeSeries.areaPath, + lineColor: '#ccc', + areaColor: '#fff', + }); + const metricArea = component.$el.querySelector('.metric-area'); + const metricLine = component.$el.querySelector('.metric-line'); + + expect(metricArea.getAttribute('fill')).toBe('#fff'); + expect(metricArea.getAttribute('d')).toBe(firstTimeSeries.areaPath); + expect(metricLine.getAttribute('stroke')).toBe('#ccc'); + expect(metricLine.getAttribute('d')).toBe(firstTimeSeries.linePath); + }); +}); diff --git a/spec/javascripts/monitoring/monitoring_paths_spec.js b/spec/javascripts/monitoring/monitoring_paths_spec.js deleted file mode 100644 index d39db945e17..00000000000 --- a/spec/javascripts/monitoring/monitoring_paths_spec.js +++ /dev/null @@ -1,34 +0,0 @@ -import Vue from 'vue'; -import MonitoringPaths from '~/monitoring/components/monitoring_paths.vue'; -import createTimeSeries from '~/monitoring/utils/multiple_time_series'; -import { singleRowMetricsMultipleSeries, convertDatesMultipleSeries } from './mock_data'; - -const createComponent = (propsData) => { - const Component = Vue.extend(MonitoringPaths); - - return new Component({ - propsData, - }).$mount(); -}; - -const convertedMetrics = convertDatesMultipleSeries(singleRowMetricsMultipleSeries); - -const timeSeries = createTimeSeries(convertedMetrics[0].queries[0].result, 428, 272, 120); - -describe('Monitoring Paths', () => { - it('renders two paths to represent a line and the area underneath it', () => { - const component = createComponent({ - generatedLinePath: timeSeries[0].linePath, - generatedAreaPath: timeSeries[0].areaPath, - lineColor: '#ccc', - areaColor: '#fff', - }); - const metricArea = component.$el.querySelector('.metric-area'); - const metricLine = component.$el.querySelector('.metric-line'); - - expect(metricArea.getAttribute('fill')).toBe('#fff'); - expect(metricArea.getAttribute('d')).toBe(timeSeries[0].areaPath); - expect(metricLine.getAttribute('stroke')).toBe('#ccc'); - expect(metricLine.getAttribute('d')).toBe(timeSeries[0].linePath); - }); -}); diff --git a/spec/javascripts/monitoring/utils/multiple_time_series_spec.js b/spec/javascripts/monitoring/utils/multiple_time_series_spec.js index 3daf6bf82df..b78314accd0 100644 --- a/spec/javascripts/monitoring/utils/multiple_time_series_spec.js +++ b/spec/javascripts/monitoring/utils/multiple_time_series_spec.js @@ -3,15 +3,16 @@ import { convertDatesMultipleSeries, singleRowMetricsMultipleSeries } from '../m const convertedMetrics = convertDatesMultipleSeries(singleRowMetricsMultipleSeries); const timeSeries = createTimeSeries(convertedMetrics[0].queries[0].result, 428, 272, 120); +const firstTimeSeries = timeSeries[0]; describe('Multiple time series', () => { it('createTimeSeries returned array contains an object for each element', () => { - expect(typeof timeSeries[0].linePath).toEqual('string'); - expect(typeof timeSeries[0].areaPath).toEqual('string'); - expect(typeof timeSeries[0].timeSeriesScaleX).toEqual('function'); - expect(typeof timeSeries[0].areaColor).toEqual('string'); - expect(typeof timeSeries[0].lineColor).toEqual('string'); - expect(timeSeries[0].values instanceof Array).toEqual(true); + expect(typeof firstTimeSeries.linePath).toEqual('string'); + expect(typeof firstTimeSeries.areaPath).toEqual('string'); + expect(typeof firstTimeSeries.timeSeriesScaleX).toEqual('function'); + expect(typeof firstTimeSeries.areaColor).toEqual('string'); + expect(typeof firstTimeSeries.lineColor).toEqual('string'); + expect(firstTimeSeries.values instanceof Array).toEqual(true); }); it('createTimeSeries returns an array', () => { -- cgit v1.2.1 From 45900c3030606c1699c841c1b51abf589fdffbfe Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Thu, 31 Aug 2017 15:43:49 -0500 Subject: Added support for named colors, also added interpolations for the graphs --- app/assets/javascripts/lib/utils/number_utils.js | 2 +- .../javascripts/monitoring/components/graph.vue | 6 +- .../monitoring/components/graph/legend.vue | 9 ++- .../monitoring/utils/multiple_time_series.js | 85 +++++++++++++++++++--- 4 files changed, 85 insertions(+), 17 deletions(-) diff --git a/app/assets/javascripts/lib/utils/number_utils.js b/app/assets/javascripts/lib/utils/number_utils.js index 57394097944..917a45eb06b 100644 --- a/app/assets/javascripts/lib/utils/number_utils.js +++ b/app/assets/javascripts/lib/utils/number_utils.js @@ -13,7 +13,7 @@ export function formatRelevantDigits(number) { let relevantDigits = 0; let formattedNumber = ''; if (!isNaN(Number(number))) { - digitsLeft = number.split('.')[0]; + digitsLeft = number.toString().split('.')[0]; switch (digitsLeft.length) { case 1: relevantDigits = 3; diff --git a/app/assets/javascripts/monitoring/components/graph.vue b/app/assets/javascripts/monitoring/components/graph.vue index 11bbeb9392b..6b3e341f936 100644 --- a/app/assets/javascripts/monitoring/components/graph.vue +++ b/app/assets/javascripts/monitoring/components/graph.vue @@ -40,8 +40,6 @@ graphHeightOffset: 120, margin: {}, unitOfDisplay: '', - areaColorRgb: '#8fbce8', - lineColorRgb: '#1f78d1', yAxisLabel: '', legendTitle: '', reducedDeploymentData: [], @@ -143,7 +141,7 @@ }, renderAxesPaths() { - this.timeSeries = createTimeSeries(this.graphData.queries[0].result, + this.timeSeries = createTimeSeries(this.graphData.queries[0], this.graphWidth, this.graphHeight, this.graphHeightOffset); @@ -162,7 +160,7 @@ const xAxis = d3.svg.axis() .scale(axisXScale) - .ticks(measurements.xTicks) + .ticks(d3.time.minute, 60) .tickFormat(timeScaleFormat) .orient('bottom'); diff --git a/app/assets/javascripts/monitoring/components/graph/legend.vue b/app/assets/javascripts/monitoring/components/graph/legend.vue index a43dad8e601..27a9ddbc568 100644 --- a/app/assets/javascripts/monitoring/components/graph/legend.vue +++ b/app/assets/javascripts/monitoring/components/graph/legend.vue @@ -81,6 +81,13 @@ formatMetricUsage(series) { return `${formatRelevantDigits(series.values[this.currentDataIndex].value)} ${this.unitOfDisplay}`; }, + + createSeriesString(index, series) { + if (series.metricTag) { + return `${series.metricTag} ${this.formatMetricUsage(series)}`; + } + return `${this.legendTitle} series ${index + 1} ${this.formatMetricUsage(series)}`; + }, }, mounted() { this.$nextTick(() => { @@ -164,7 +171,7 @@ ref="legendTitleSvg" x="38" :y="graphHeight - 30"> - {{legendTitle}} Series {{index + 1}} {{formatMetricUsage(series)}} + {{createSeriesString(index, series)}} { +function pickColorFromNameNumber(colorName, colorNumber) { + let lineColor = '#1f78d1'; + let areaColor = '#8fbce8'; + const color = colorName != null ? colorName : colorNumber; + switch (color) { + case 'blue': + case 1: + lineColor = '#1f78d1'; + areaColor = '#8fbce8'; + break; + case 'orange': + case 2: + lineColor = '#fc9403'; + areaColor = '#feca81'; + break; + case 'red': + case 3: + lineColor = '#db3b21'; + areaColor = '#ed9d90'; + break; + case 'green': + case 4: + lineColor = '#1aaa55'; + areaColor = '#8dd5aa'; + break; + case 'purple': + case 5: + lineColor = '#6666c4'; + areaColor = '#d1d1f0'; + break; + default: + lineColor = '#1f78d1'; + areaColor = '#8fbce8'; + break; + } + + return { + lineColor, + areaColor, + }; +} + +export default function createTimeSeries(queryData, graphWidth, graphHeight, graphHeightOffset) { + const maxValues = queryData.result.map((timeSeries, index) => { const maxValue = d3.max(timeSeries.values.map(d => d.value)); return { maxValue, @@ -18,7 +60,9 @@ export default function createTimeSeries(seriesData, graphWidth, graphHeight, gr const lineColors = ['#1f78d1', '#fc9403', '#db3b21', '#1aaa55', '#6666c4']; const areaColors = ['#8fbce8', '#feca81', '#ed9d90', '#8dd5aa', '#d1d1f0']; - return seriesData.map((timeSeries) => { + return queryData.result.map((timeSeries, index) => { + let metricTag = 'series'; + let pathColors = null; const timeSeriesScaleX = d3.time.scale() .range([0, graphWidth - 70]); @@ -26,25 +70,43 @@ export default function createTimeSeries(seriesData, graphWidth, graphHeight, gr .range([graphHeight - graphHeightOffset, 0]); timeSeriesScaleX.domain(d3.extent(timeSeries.values, d => d.time)); + timeSeriesScaleX.ticks(d3.time.minute, 60); timeSeriesScaleY.domain([0, maxValueFromSeries.maxValue]); const lineFunction = d3.svg.line() + .interpolate('step-before') .x(d => timeSeriesScaleX(d.time)) .y(d => timeSeriesScaleY(d.value)); const areaFunction = d3.svg.area() + .interpolate('step-before') .x(d => timeSeriesScaleX(d.time)) .y0(graphHeight - graphHeightOffset) - .y1(d => timeSeriesScaleY(d.value)) - .interpolate('linear'); + .y1(d => timeSeriesScaleY(d.value)); lineColor = lineColors[timeSeriesNumber - 1]; areaColor = areaColors[timeSeriesNumber - 1]; - if (timeSeriesNumber <= 5) { - timeSeriesNumber = timeSeriesNumber += 1; - } else { - timeSeriesNumber = 1; + if (queryData.series != null) { + const seriesCustomizationData = queryData.series[index]; + metricTag = timeSeries.metric[Object.keys(timeSeries.metric)[0]] || ''; + if (seriesCustomizationData != null) { + if ( + seriesCustomizationData.value === metricTag && + seriesCustomizationData.color != null + ) { + pathColors = pickColorFromNameNumber(seriesCustomizationData.color.toLowerCase(), null); + } + } + } + + if (pathColors == null) { + pathColors = pickColorFromNameNumber(null, timeSeriesNumber); + if (timeSeriesNumber <= 5) { + timeSeriesNumber = timeSeriesNumber += 1; + } else { + timeSeriesNumber = 1; + } } return { @@ -52,8 +114,9 @@ export default function createTimeSeries(seriesData, graphWidth, graphHeight, gr areaPath: areaFunction(timeSeries.values), timeSeriesScaleX, values: timeSeries.values, - lineColor, - areaColor, + ...pathColors, + metricTag, }; }); } + -- cgit v1.2.1 From 75b8f64ac331ac344dd0b4afa49ca4ad9e3de977 Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Tue, 5 Sep 2017 15:28:38 -0500 Subject: Added specs for the additional color support --- config/prometheus/additional_metrics.yml | 17 +++++++++++++++++ spec/javascripts/monitoring/graph/legend_spec.js | 8 +++----- spec/javascripts/monitoring/graph_path_spec.js | 2 +- .../monitoring/utils/multiple_time_series_spec.js | 2 +- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/config/prometheus/additional_metrics.yml b/config/prometheus/additional_metrics.yml index 0642a0b2fe9..202bd9f0ab1 100644 --- a/config/prometheus/additional_metrics.yml +++ b/config/prometheus/additional_metrics.yml @@ -131,3 +131,20 @@ - query_range: 'sum(rate(container_cpu_usage_seconds_total{container_name!="POD",%{environment_filter}}[2m])) / count(container_cpu_usage_seconds_total{container_name!="POD",%{environment_filter}}) * 100' label: Average unit: "%" + - title: "CPU usage by CPU" + required_metrics: + - container_cpu_usage_seconds_total + weight: 1 + queries: + - query_range: 'avg(rate(container_cpu_usage_seconds_total{%{environment_filter}}[2m])) by (cpu) * 100' + unit: Average (%) + label: cpu + series: + - value: cpu00 + color: red + - value: cpu01 + color: blue + - value: cpu02 + color: purple + - value: cpu03 + color: orange diff --git a/spec/javascripts/monitoring/graph/legend_spec.js b/spec/javascripts/monitoring/graph/legend_spec.js index da2fbd26e23..2eda0fc4ab6 100644 --- a/spec/javascripts/monitoring/graph/legend_spec.js +++ b/spec/javascripts/monitoring/graph/legend_spec.js @@ -28,7 +28,7 @@ const defaultValuesComponent = { currentDataIndex: 0, }; -const timeSeries = createTimeSeries(convertedMetrics[0].queries[0].result, +const timeSeries = createTimeSeries(convertedMetrics[0].queries[0], defaultValuesComponent.graphWidth, defaultValuesComponent.graphHeight, defaultValuesComponent.graphHeightOffset); @@ -38,7 +38,7 @@ function getTextFromNode(component, selector) { return component.$el.querySelector(selector).firstChild.nodeValue.trim(); } -describe('GraphLegend', () => { +fdescribe('GraphLegend', () => { describe('Computed props', () => { it('textTransform', () => { const component = createComponent(defaultValuesComponent); @@ -93,9 +93,7 @@ describe('GraphLegend', () => { const component = createComponent(defaultValuesComponent); const titles = component.$el.querySelectorAll('.legend-metric-title'); - expect(getTextFromNode(component, '.legend-metric-title').indexOf(component.legendTitle)).not.toEqual(-1); - expect(titles[0].textContent.indexOf('Title')).not.toEqual(-1); - expect(titles[1].textContent.indexOf('Series')).not.toEqual(-1); + expect(titles[1].textContent.indexOf('series')).not.toEqual(-1); expect(getTextFromNode(component, '.y-label-text')).toEqual(component.yAxisLabel); }); diff --git a/spec/javascripts/monitoring/graph_path_spec.js b/spec/javascripts/monitoring/graph_path_spec.js index 105fb852e8e..41b3014baac 100644 --- a/spec/javascripts/monitoring/graph_path_spec.js +++ b/spec/javascripts/monitoring/graph_path_spec.js @@ -13,7 +13,7 @@ const createComponent = (propsData) => { const convertedMetrics = convertDatesMultipleSeries(singleRowMetricsMultipleSeries); -const timeSeries = createTimeSeries(convertedMetrics[0].queries[0].result, 428, 272, 120); +const timeSeries = createTimeSeries(convertedMetrics[0].queries[0], 428, 272, 120); const firstTimeSeries = timeSeries[0]; describe('Monitoring Paths', () => { diff --git a/spec/javascripts/monitoring/utils/multiple_time_series_spec.js b/spec/javascripts/monitoring/utils/multiple_time_series_spec.js index b78314accd0..7e44a9ade9e 100644 --- a/spec/javascripts/monitoring/utils/multiple_time_series_spec.js +++ b/spec/javascripts/monitoring/utils/multiple_time_series_spec.js @@ -2,7 +2,7 @@ import createTimeSeries from '~/monitoring/utils/multiple_time_series'; import { convertDatesMultipleSeries, singleRowMetricsMultipleSeries } from '../mock_data'; const convertedMetrics = convertDatesMultipleSeries(singleRowMetricsMultipleSeries); -const timeSeries = createTimeSeries(convertedMetrics[0].queries[0].result, 428, 272, 120); +const timeSeries = createTimeSeries(convertedMetrics[0].queries[0], 428, 272, 120); const firstTimeSeries = timeSeries[0]; describe('Multiple time series', () => { -- cgit v1.2.1 From 93ba3fdd1e756168ba9ca12e60a53a98969ccdec Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Tue, 5 Sep 2017 18:30:08 -0500 Subject: small fixes to code and specs --- .../monitoring/utils/multiple_time_series.js | 34 +++++++++------------- config/prometheus/additional_metrics.yml | 17 ----------- spec/javascripts/monitoring/graph/legend_spec.js | 7 +++-- spec/javascripts/monitoring/mock_data.js | 8 ++++- 4 files changed, 25 insertions(+), 41 deletions(-) diff --git a/app/assets/javascripts/monitoring/utils/multiple_time_series.js b/app/assets/javascripts/monitoring/utils/multiple_time_series.js index 164157a72b7..eca79587a49 100644 --- a/app/assets/javascripts/monitoring/utils/multiple_time_series.js +++ b/app/assets/javascripts/monitoring/utils/multiple_time_series.js @@ -2,8 +2,8 @@ import d3 from 'd3'; import _ from 'underscore'; function pickColorFromNameNumber(colorName, colorNumber) { - let lineColor = '#1f78d1'; - let areaColor = '#8fbce8'; + let lineColor = ''; + let areaColor = ''; const color = colorName != null ? colorName : colorNumber; switch (color) { case 'blue': @@ -55,13 +55,9 @@ export default function createTimeSeries(queryData, graphWidth, graphHeight, gra const maxValueFromSeries = _.max(maxValues, val => val.maxValue); let timeSeriesNumber = 1; - let lineColor = '#1f78d1'; - let areaColor = '#8fbce8'; - const lineColors = ['#1f78d1', '#fc9403', '#db3b21', '#1aaa55', '#6666c4']; - const areaColors = ['#8fbce8', '#feca81', '#ed9d90', '#8dd5aa', '#d1d1f0']; return queryData.result.map((timeSeries, index) => { - let metricTag = 'series'; + let metricTag = ''; let pathColors = null; const timeSeriesScaleX = d3.time.scale() .range([0, graphWidth - 70]); @@ -84,29 +80,27 @@ export default function createTimeSeries(queryData, graphWidth, graphHeight, gra .y0(graphHeight - graphHeightOffset) .y1(d => timeSeriesScaleY(d.value)); - lineColor = lineColors[timeSeriesNumber - 1]; - areaColor = areaColors[timeSeriesNumber - 1]; - if (queryData.series != null) { const seriesCustomizationData = queryData.series[index]; - metricTag = timeSeries.metric[Object.keys(timeSeries.metric)[0]] || ''; + const timeSeriesMetricLabel = timeSeries.metric[Object.keys(timeSeries.metric)[0]]; if (seriesCustomizationData != null) { - if ( - seriesCustomizationData.value === metricTag && - seriesCustomizationData.color != null - ) { + metricTag = seriesCustomizationData.value || timeSeriesMetricLabel; + if (seriesCustomizationData.color != null) { pathColors = pickColorFromNameNumber(seriesCustomizationData.color.toLowerCase(), null); } + } else { + metricTag = timeSeriesMetricLabel || `series ${timeSeriesNumber}`; } } if (pathColors == null) { pathColors = pickColorFromNameNumber(null, timeSeriesNumber); - if (timeSeriesNumber <= 5) { - timeSeriesNumber = timeSeriesNumber += 1; - } else { - timeSeriesNumber = 1; - } + } + + if (timeSeriesNumber <= 5) { + timeSeriesNumber = timeSeriesNumber += 1; + } else { + timeSeriesNumber = 1; } return { diff --git a/config/prometheus/additional_metrics.yml b/config/prometheus/additional_metrics.yml index 202bd9f0ab1..0642a0b2fe9 100644 --- a/config/prometheus/additional_metrics.yml +++ b/config/prometheus/additional_metrics.yml @@ -131,20 +131,3 @@ - query_range: 'sum(rate(container_cpu_usage_seconds_total{container_name!="POD",%{environment_filter}}[2m])) / count(container_cpu_usage_seconds_total{container_name!="POD",%{environment_filter}}) * 100' label: Average unit: "%" - - title: "CPU usage by CPU" - required_metrics: - - container_cpu_usage_seconds_total - weight: 1 - queries: - - query_range: 'avg(rate(container_cpu_usage_seconds_total{%{environment_filter}}[2m])) by (cpu) * 100' - unit: Average (%) - label: cpu - series: - - value: cpu00 - color: red - - value: cpu01 - color: blue - - value: cpu02 - color: purple - - value: cpu03 - color: orange diff --git a/spec/javascripts/monitoring/graph/legend_spec.js b/spec/javascripts/monitoring/graph/legend_spec.js index 2eda0fc4ab6..969b5bad730 100644 --- a/spec/javascripts/monitoring/graph/legend_spec.js +++ b/spec/javascripts/monitoring/graph/legend_spec.js @@ -38,7 +38,7 @@ function getTextFromNode(component, selector) { return component.$el.querySelector(selector).firstChild.nodeValue.trim(); } -fdescribe('GraphLegend', () => { +describe('GraphLegend', () => { describe('Computed props', () => { it('textTransform', () => { const component = createComponent(defaultValuesComponent); @@ -89,11 +89,12 @@ fdescribe('GraphLegend', () => { expect(component.$el.querySelectorAll('.rect-axis-text').length).toEqual(2); }); - it('contains text to signal the usage, title and time', () => { + it('contains text to signal the usage, title and time with multiple time series', () => { const component = createComponent(defaultValuesComponent); const titles = component.$el.querySelectorAll('.legend-metric-title'); - expect(titles[1].textContent.indexOf('series')).not.toEqual(-1); + expect(titles[0].textContent.indexOf('hundred(s)')).not.toEqual(-1); + expect(titles[1].textContent.indexOf('2xx')).not.toEqual(-1); expect(getTextFromNode(component, '.y-label-text')).toEqual(component.yAxisLabel); }); diff --git a/spec/javascripts/monitoring/mock_data.js b/spec/javascripts/monitoring/mock_data.js index 3d399f2bb95..4d0d565cf26 100644 --- a/spec/javascripts/monitoring/mock_data.js +++ b/spec/javascripts/monitoring/mock_data.js @@ -6346,7 +6346,13 @@ export const singleRowMetricsMultipleSeries = [ } ] }, - ] + ], + 'series': [ + { + 'value': 'hundred(s)', + 'color': 'green', + }, + ], } ] }, -- cgit v1.2.1 From b71eb1da5bd20c8c2ae53efe79af516da0aeeb03 Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Thu, 7 Sep 2017 09:45:30 -0500 Subject: Added minor details to specs --- changelogs/unreleased/additional-time-series-charts.yml | 2 +- config/prometheus/additional_metrics.yml | 17 +++++++++++++++++ spec/javascripts/monitoring/graph_path_spec.js | 8 ++++---- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/changelogs/unreleased/additional-time-series-charts.yml b/changelogs/unreleased/additional-time-series-charts.yml index d5fd24cf2e7..80c1af54881 100644 --- a/changelogs/unreleased/additional-time-series-charts.yml +++ b/changelogs/unreleased/additional-time-series-charts.yml @@ -1,5 +1,5 @@ --- -title: Added support for multiple time series +title: Added support the multiple time series for prometheus monitoring merge_request: !36893 author: type: changed diff --git a/config/prometheus/additional_metrics.yml b/config/prometheus/additional_metrics.yml index 0642a0b2fe9..202bd9f0ab1 100644 --- a/config/prometheus/additional_metrics.yml +++ b/config/prometheus/additional_metrics.yml @@ -131,3 +131,20 @@ - query_range: 'sum(rate(container_cpu_usage_seconds_total{container_name!="POD",%{environment_filter}}[2m])) / count(container_cpu_usage_seconds_total{container_name!="POD",%{environment_filter}}) * 100' label: Average unit: "%" + - title: "CPU usage by CPU" + required_metrics: + - container_cpu_usage_seconds_total + weight: 1 + queries: + - query_range: 'avg(rate(container_cpu_usage_seconds_total{%{environment_filter}}[2m])) by (cpu) * 100' + unit: Average (%) + label: cpu + series: + - value: cpu00 + color: red + - value: cpu01 + color: blue + - value: cpu02 + color: purple + - value: cpu03 + color: orange diff --git a/spec/javascripts/monitoring/graph_path_spec.js b/spec/javascripts/monitoring/graph_path_spec.js index 41b3014baac..e7348b03ba1 100644 --- a/spec/javascripts/monitoring/graph_path_spec.js +++ b/spec/javascripts/monitoring/graph_path_spec.js @@ -21,15 +21,15 @@ describe('Monitoring Paths', () => { const component = createComponent({ generatedLinePath: firstTimeSeries.linePath, generatedAreaPath: firstTimeSeries.areaPath, - lineColor: '#ccc', - areaColor: '#fff', + lineColor: firstTimeSeries.lineColor, + areaColor: firstTimeSeries.areaColor, }); const metricArea = component.$el.querySelector('.metric-area'); const metricLine = component.$el.querySelector('.metric-line'); - expect(metricArea.getAttribute('fill')).toBe('#fff'); + expect(metricArea.getAttribute('fill')).toBe('#8dd5aa'); expect(metricArea.getAttribute('d')).toBe(firstTimeSeries.areaPath); - expect(metricLine.getAttribute('stroke')).toBe('#ccc'); + expect(metricLine.getAttribute('stroke')).toBe('#1aaa55'); expect(metricLine.getAttribute('d')).toBe(firstTimeSeries.linePath); }); }); -- cgit v1.2.1 From ce27b99f800716cd5296c4324b855a14dd84c799 Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Thu, 7 Sep 2017 09:47:09 -0500 Subject: Added CHANGELOG --- changelogs/unreleased/support-additional-colors.yml | 5 +++++ config/prometheus/additional_metrics.yml | 17 ----------------- 2 files changed, 5 insertions(+), 17 deletions(-) create mode 100644 changelogs/unreleased/support-additional-colors.yml diff --git a/changelogs/unreleased/support-additional-colors.yml b/changelogs/unreleased/support-additional-colors.yml new file mode 100644 index 00000000000..5178e159dcf --- /dev/null +++ b/changelogs/unreleased/support-additional-colors.yml @@ -0,0 +1,5 @@ +--- +title: Added support for specific labels and colors +merge_request: +author: +type: changed diff --git a/config/prometheus/additional_metrics.yml b/config/prometheus/additional_metrics.yml index 202bd9f0ab1..0642a0b2fe9 100644 --- a/config/prometheus/additional_metrics.yml +++ b/config/prometheus/additional_metrics.yml @@ -131,20 +131,3 @@ - query_range: 'sum(rate(container_cpu_usage_seconds_total{container_name!="POD",%{environment_filter}}[2m])) / count(container_cpu_usage_seconds_total{container_name!="POD",%{environment_filter}}) * 100' label: Average unit: "%" - - title: "CPU usage by CPU" - required_metrics: - - container_cpu_usage_seconds_total - weight: 1 - queries: - - query_range: 'avg(rate(container_cpu_usage_seconds_total{%{environment_filter}}[2m])) by (cpu) * 100' - unit: Average (%) - label: cpu - series: - - value: cpu00 - color: red - - value: cpu01 - color: blue - - value: cpu02 - color: purple - - value: cpu03 - color: orange -- cgit v1.2.1 From 290217d51bd2489ad23e346a65fbc21b52e57724 Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Thu, 7 Sep 2017 14:09:52 -0500 Subject: Improved color selector and addressed observations --- .../monitoring/components/graph/legend.vue | 2 +- .../monitoring/utils/multiple_time_series.js | 87 +++++++++------------- 2 files changed, 38 insertions(+), 51 deletions(-) diff --git a/app/assets/javascripts/monitoring/components/graph/legend.vue b/app/assets/javascripts/monitoring/components/graph/legend.vue index 27a9ddbc568..dbc48c63747 100644 --- a/app/assets/javascripts/monitoring/components/graph/legend.vue +++ b/app/assets/javascripts/monitoring/components/graph/legend.vue @@ -171,7 +171,7 @@ ref="legendTitleSvg" x="38" :y="graphHeight - 30"> - {{createSeriesString(index, series)}} + {{createSeriesString(index, series)}} 0) { + pick = unusedColors[0]; + } else { + usedColors = []; + pick = defaultColorOrder[0]; + } + } + usedColors.push(pick); + return defaultColorPalette[pick]; } export default function createTimeSeries(queryData, graphWidth, graphHeight, graphHeightOffset) { @@ -56,9 +41,10 @@ export default function createTimeSeries(queryData, graphWidth, graphHeight, gra let timeSeriesNumber = 1; - return queryData.result.map((timeSeries, index) => { + return queryData.result.map((timeSeries) => { let metricTag = ''; - let pathColors = null; + let lineColor = '#1f78d1'; + let areaColor = '#8fbce8'; const timeSeriesScaleX = d3.time.scale() .range([0, graphWidth - 70]); @@ -70,33 +56,33 @@ export default function createTimeSeries(queryData, graphWidth, graphHeight, gra timeSeriesScaleY.domain([0, maxValueFromSeries.maxValue]); const lineFunction = d3.svg.line() - .interpolate('step-before') + .interpolate('linear') .x(d => timeSeriesScaleX(d.time)) .y(d => timeSeriesScaleY(d.value)); const areaFunction = d3.svg.area() - .interpolate('step-before') + .interpolate('linear') .x(d => timeSeriesScaleX(d.time)) .y0(graphHeight - graphHeightOffset) .y1(d => timeSeriesScaleY(d.value)); if (queryData.series != null) { - const seriesCustomizationData = queryData.series[index]; const timeSeriesMetricLabel = timeSeries.metric[Object.keys(timeSeries.metric)[0]]; + const seriesCustomizationData = _.findWhere(queryData.series[0].series, + { value: timeSeriesMetricLabel }); if (seriesCustomizationData != null) { metricTag = seriesCustomizationData.value || timeSeriesMetricLabel; if (seriesCustomizationData.color != null) { - pathColors = pickColorFromNameNumber(seriesCustomizationData.color.toLowerCase(), null); + [lineColor, areaColor] = pickColor(seriesCustomizationData.color); + } else { + [lineColor, areaColor] = pickColor(); } } else { metricTag = timeSeriesMetricLabel || `series ${timeSeriesNumber}`; + [lineColor, areaColor] = pickColor(); } } - if (pathColors == null) { - pathColors = pickColorFromNameNumber(null, timeSeriesNumber); - } - if (timeSeriesNumber <= 5) { timeSeriesNumber = timeSeriesNumber += 1; } else { @@ -108,7 +94,8 @@ export default function createTimeSeries(queryData, graphWidth, graphHeight, gra areaPath: areaFunction(timeSeries.values), timeSeriesScaleX, values: timeSeries.values, - ...pathColors, + lineColor, + areaColor, metricTag, }; }); -- cgit v1.2.1 From a2d10937d861b1d288786ba92de2306f4f2ab22b Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Thu, 7 Sep 2017 14:46:16 -0500 Subject: refactored the pickColors method --- .../monitoring/utils/multiple_time_series.js | 33 ++++++++++++---------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/app/assets/javascripts/monitoring/utils/multiple_time_series.js b/app/assets/javascripts/monitoring/utils/multiple_time_series.js index 9845fd53222..17e5eb79816 100644 --- a/app/assets/javascripts/monitoring/utils/multiple_time_series.js +++ b/app/assets/javascripts/monitoring/utils/multiple_time_series.js @@ -10,25 +10,27 @@ const defaultColorPalette = { }; const defaultColorOrder = ['blue', 'orange', 'red', 'green', 'purple']; -let usedColors = []; -function pickColor(name) { - let pick; - if (name && defaultColorPalette[name]) { - pick = name; - } else { - const unusedColors = _.difference(defaultColorOrder, usedColors); - if (unusedColors.length > 0) { - pick = unusedColors[0]; + +export default function createTimeSeries(queryData, graphWidth, graphHeight, graphHeightOffset) { + let usedColors = []; + + function pickColor(name) { + let pick; + if (name && defaultColorPalette[name]) { + pick = name; } else { - usedColors = []; - pick = defaultColorOrder[0]; + const unusedColors = _.difference(defaultColorOrder, usedColors); + if (unusedColors.length > 0) { + pick = unusedColors[0]; + } else { + usedColors = []; + pick = defaultColorOrder[0]; + } } + usedColors.push(pick); + return defaultColorPalette[pick]; } - usedColors.push(pick); - return defaultColorPalette[pick]; -} -export default function createTimeSeries(queryData, graphWidth, graphHeight, graphHeightOffset) { const maxValues = queryData.result.map((timeSeries, index) => { const maxValue = d3.max(timeSeries.values.map(d => d.value)); return { @@ -45,6 +47,7 @@ export default function createTimeSeries(queryData, graphWidth, graphHeight, gra let metricTag = ''; let lineColor = '#1f78d1'; let areaColor = '#8fbce8'; + const timeSeriesScaleX = d3.time.scale() .range([0, graphWidth - 70]); -- cgit v1.2.1 From 851ada82158fccce112665c420b60d1905317dba Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Thu, 7 Sep 2017 16:30:25 -0500 Subject: addressed code quality observations --- .../monitoring/utils/multiple_time_series.js | 37 +++++++--------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/app/assets/javascripts/monitoring/utils/multiple_time_series.js b/app/assets/javascripts/monitoring/utils/multiple_time_series.js index 17e5eb79816..955b963b451 100644 --- a/app/assets/javascripts/monitoring/utils/multiple_time_series.js +++ b/app/assets/javascripts/monitoring/utils/multiple_time_series.js @@ -41,12 +41,10 @@ export default function createTimeSeries(queryData, graphWidth, graphHeight, gra const maxValueFromSeries = _.max(maxValues, val => val.maxValue); - let timeSeriesNumber = 1; - - return queryData.result.map((timeSeries) => { + return queryData.result.map((timeSeries, timeSeriesNumber) => { let metricTag = ''; - let lineColor = '#1f78d1'; - let areaColor = '#8fbce8'; + let lineColor = ''; + let areaColor = ''; const timeSeriesScaleX = d3.time.scale() .range([0, graphWidth - 70]); @@ -69,27 +67,16 @@ export default function createTimeSeries(queryData, graphWidth, graphHeight, gra .y0(graphHeight - graphHeightOffset) .y1(d => timeSeriesScaleY(d.value)); - if (queryData.series != null) { - const timeSeriesMetricLabel = timeSeries.metric[Object.keys(timeSeries.metric)[0]]; - const seriesCustomizationData = _.findWhere(queryData.series[0].series, - { value: timeSeriesMetricLabel }); - if (seriesCustomizationData != null) { - metricTag = seriesCustomizationData.value || timeSeriesMetricLabel; - if (seriesCustomizationData.color != null) { - [lineColor, areaColor] = pickColor(seriesCustomizationData.color); - } else { - [lineColor, areaColor] = pickColor(); - } - } else { - metricTag = timeSeriesMetricLabel || `series ${timeSeriesNumber}`; - [lineColor, areaColor] = pickColor(); - } - } - - if (timeSeriesNumber <= 5) { - timeSeriesNumber = timeSeriesNumber += 1; + const timeSeriesMetricLabel = timeSeries.metric[Object.keys(timeSeries.metric)[0]]; + const seriesCustomizationData = queryData.series != null && + _.findWhere(queryData.series[0].series, + { value: timeSeriesMetricLabel }); + if (seriesCustomizationData != null) { + metricTag = seriesCustomizationData.value || timeSeriesMetricLabel; + [lineColor, areaColor] = pickColor(seriesCustomizationData.color); } else { - timeSeriesNumber = 1; + metricTag = timeSeriesMetricLabel || `series ${timeSeriesNumber + 1}`; + [lineColor, areaColor] = pickColor(); } return { -- cgit v1.2.1 From 7f5ae2e8b2a3e29ad128e28798b82c8b19d55100 Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Thu, 7 Sep 2017 17:16:31 -0500 Subject: Changed how the backend response is handled for when instead of series --- app/assets/javascripts/monitoring/utils/multiple_time_series.js | 5 ++--- spec/javascripts/monitoring/graph/legend_spec.js | 2 +- spec/javascripts/monitoring/graph_path_spec.js | 4 ++-- spec/javascripts/monitoring/mock_data.js | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/monitoring/utils/multiple_time_series.js b/app/assets/javascripts/monitoring/utils/multiple_time_series.js index 955b963b451..4e6a64fc47c 100644 --- a/app/assets/javascripts/monitoring/utils/multiple_time_series.js +++ b/app/assets/javascripts/monitoring/utils/multiple_time_series.js @@ -68,8 +68,8 @@ export default function createTimeSeries(queryData, graphWidth, graphHeight, gra .y1(d => timeSeriesScaleY(d.value)); const timeSeriesMetricLabel = timeSeries.metric[Object.keys(timeSeries.metric)[0]]; - const seriesCustomizationData = queryData.series != null && - _.findWhere(queryData.series[0].series, + const seriesCustomizationData = queryData.when != null && + _.findWhere(queryData.when[0].series, { value: timeSeriesMetricLabel }); if (seriesCustomizationData != null) { metricTag = seriesCustomizationData.value || timeSeriesMetricLabel; @@ -90,4 +90,3 @@ export default function createTimeSeries(queryData, graphWidth, graphHeight, gra }; }); } - diff --git a/spec/javascripts/monitoring/graph/legend_spec.js b/spec/javascripts/monitoring/graph/legend_spec.js index 969b5bad730..2571b7ef869 100644 --- a/spec/javascripts/monitoring/graph/legend_spec.js +++ b/spec/javascripts/monitoring/graph/legend_spec.js @@ -93,7 +93,7 @@ describe('GraphLegend', () => { const component = createComponent(defaultValuesComponent); const titles = component.$el.querySelectorAll('.legend-metric-title'); - expect(titles[0].textContent.indexOf('hundred(s)')).not.toEqual(-1); + expect(titles[0].textContent.indexOf('1xx')).not.toEqual(-1); expect(titles[1].textContent.indexOf('2xx')).not.toEqual(-1); expect(getTextFromNode(component, '.y-label-text')).toEqual(component.yAxisLabel); }); diff --git a/spec/javascripts/monitoring/graph_path_spec.js b/spec/javascripts/monitoring/graph_path_spec.js index e7348b03ba1..a4844636d09 100644 --- a/spec/javascripts/monitoring/graph_path_spec.js +++ b/spec/javascripts/monitoring/graph_path_spec.js @@ -27,9 +27,9 @@ describe('Monitoring Paths', () => { const metricArea = component.$el.querySelector('.metric-area'); const metricLine = component.$el.querySelector('.metric-line'); - expect(metricArea.getAttribute('fill')).toBe('#8dd5aa'); + expect(metricArea.getAttribute('fill')).toBe('#8fbce8'); expect(metricArea.getAttribute('d')).toBe(firstTimeSeries.areaPath); - expect(metricLine.getAttribute('stroke')).toBe('#1aaa55'); + expect(metricLine.getAttribute('stroke')).toBe('#1f78d1'); expect(metricLine.getAttribute('d')).toBe(firstTimeSeries.linePath); }); }); diff --git a/spec/javascripts/monitoring/mock_data.js b/spec/javascripts/monitoring/mock_data.js index 4d0d565cf26..7ceab657464 100644 --- a/spec/javascripts/monitoring/mock_data.js +++ b/spec/javascripts/monitoring/mock_data.js @@ -6347,7 +6347,7 @@ export const singleRowMetricsMultipleSeries = [ ] }, ], - 'series': [ + 'when': [ { 'value': 'hundred(s)', 'color': 'green', -- cgit v1.2.1 From 4bd5c062f03437c2359356a61ac84a7bbb141cf8 Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Thu, 7 Sep 2017 18:26:33 -0500 Subject: flipped series and when keys --- app/assets/javascripts/monitoring/utils/multiple_time_series.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/monitoring/utils/multiple_time_series.js b/app/assets/javascripts/monitoring/utils/multiple_time_series.js index 4e6a64fc47c..3cbe06d8fd6 100644 --- a/app/assets/javascripts/monitoring/utils/multiple_time_series.js +++ b/app/assets/javascripts/monitoring/utils/multiple_time_series.js @@ -68,8 +68,8 @@ export default function createTimeSeries(queryData, graphWidth, graphHeight, gra .y1(d => timeSeriesScaleY(d.value)); const timeSeriesMetricLabel = timeSeries.metric[Object.keys(timeSeries.metric)[0]]; - const seriesCustomizationData = queryData.when != null && - _.findWhere(queryData.when[0].series, + const seriesCustomizationData = queryData.series != null && + _.findWhere(queryData.series[0].when, { value: timeSeriesMetricLabel }); if (seriesCustomizationData != null) { metricTag = seriesCustomizationData.value || timeSeriesMetricLabel; -- cgit v1.2.1