diff options
author | Simon Knox <psimyn@gmail.com> | 2019-05-02 12:15:24 +1000 |
---|---|---|
committer | Simon Knox <psimyn@gmail.com> | 2019-05-02 12:16:55 +1000 |
commit | 3b8c905cf314d451dadcc68b0104dd1b2384c2af (patch) | |
tree | d3847e5d1e613ba9f61f7a572ce07e11ae83dcc0 | |
parent | 257805f1fee423be2a9ea46635ee956ae33e3def (diff) | |
download | gitlab-ce-psimyn-science.tar.gz |
Remove other chart types for now so area-chart displayspsimyn-science
When there is a v-if inside a v-for things do not go well
4 files changed, 111 insertions, 46 deletions
diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue index 0a33fab99e5..294df5dc311 100644 --- a/app/assets/javascripts/monitoring/components/dashboard.vue +++ b/app/assets/javascripts/monitoring/components/dashboard.vue @@ -198,7 +198,8 @@ export default { this.showEmptyState = false; }) - .catch(() => { + .catch((e) => { + console.error(e) this.state = 'unableToConnect'; }); }, @@ -279,7 +280,6 @@ export default { > <template v-for="(graphData, graphIndex) in groupData.metrics"> <monitor-area-chart - v-if="graphData.type === undefined || graphData.type === 'area'" :key="`area-${graphIndex}`" :graph-data="graphData" :deployment-data="store.deploymentData" @@ -295,24 +295,6 @@ export default { @setAlerts="setAlerts" /> </monitor-area-chart> - <single-stat-chart - v-else-if="graphData.type === 'single_stat'" - :key="`single-stat-${graphIndex}`" - value="100" - unit="ms" - title="latency" - /> - <line-chart - v-else-if="graphData.type === 'line_chart'" - :key="`line-${graphIndex}`" - :graph-data="graphData" - :container-width="elWidth" - /> - <heatmap-chart - v-else-if="graphData.type === 'heatmap_chart'" - :key="`heatmap-${graphIndex}`" - :graph-data="graphData" - /> </template> </graph-group> </div> diff --git a/app/assets/javascripts/monitoring/stores/actions.js b/app/assets/javascripts/monitoring/stores/actions.js index 29a7cbca669..32c86c32d5d 100644 --- a/app/assets/javascripts/monitoring/stores/actions.js +++ b/app/assets/javascripts/monitoring/stores/actions.js @@ -94,7 +94,7 @@ export const fetchPrometheusMetrics = ({ state, dispatch }) => { * * @param {metric} metric */ -export const fetchPrometheusMetric = ({ commit }, metric) => { +export const fetchPrometheusMetric = ({ commit, getters }, metric) => { const queryType = Object.keys(metric).find(key => ['query', 'query_range'].includes(key)); const query = metric[queryType]; // TODO don't hardcode @@ -116,6 +116,12 @@ export const fetchPrometheusMetric = ({ commit }, metric) => { step, }; + prom(prometheusEndpoint, params).then(result => { + commit(types.SET_QUERY_RESULT, { metricId: metric.metric_id, result }); + }) +} + +function prom(prometheusEndpoint, params) { return backOffRequest(() => axios.get(prometheusEndpoint, { params })) .then(res => res.data) .then(response => { @@ -124,18 +130,11 @@ export const fetchPrometheusMetric = ({ commit }, metric) => { } const { resultType, result } = response.data; - + if (resultType === 'matrix') { if (result.length > 0) { - // TODO: maybe use Object.freeze here since results don't need to be reactive - commit(types.SET_QUERY_RESULT, { metricId: metric.metric_id, result }); + return result } } - // .then(res => { - // if (res.resultType === 'matrix') { - // if (res.result.length > 0) { - // panel.queries[0].result = res.result; - // panel.queries[0].metricId = panel.queries[0].metric_id; - }); } diff --git a/app/assets/javascripts/monitoring/stores/getters.js b/app/assets/javascripts/monitoring/stores/getters.js index 045356adc44..c106d5fe6b3 100644 --- a/app/assets/javascripts/monitoring/stores/getters.js +++ b/app/assets/javascripts/monitoring/stores/getters.js @@ -1,20 +1,104 @@ +import _ from 'underscore'; + +function sortMetrics(metrics) { + return _.chain(metrics) + .sortBy('title') + .sortBy('weight') + .value(); +} + +function checkQueryEmptyData(query) { + return { + ...query, + result: query.result.filter(timeSeries => { + const newTimeSeries = timeSeries; + const hasValue = series => + !Number.isNaN(series[1]) && (series[1] !== null || series[1] !== undefined); + const hasNonNullValue = timeSeries.values.find(hasValue); + + newTimeSeries.values = hasNonNullValue ? newTimeSeries.values : []; + + return newTimeSeries.values.length > 0; + }), + }; +} + +function removeTimeSeriesNoData(queries) { + return queries.reduce((series, query) => series.concat(checkQueryEmptyData(query)), []); +} + +// Metrics and queries are currently stored 1:1, so `queries` is an array of length one. +// We want to group queries onto a single chart by title & y-axis label. +// This function will no longer be required when metrics:queries are 1:many, +// though there is no consequence if the function stays in use. +// @param metrics [Array<Object>] +// Ex) [ +// { id: 1, title: 'title', y_label: 'MB', queries: [{ ...query1Attrs }] }, +// { id: 2, title: 'title', y_label: 'MB', queries: [{ ...query2Attrs }] }, +// { id: 3, title: 'new title', y_label: 'MB', queries: [{ ...query3Attrs }] } +// ] +// @return [Array<Object>] +// Ex) [ +// { title: 'title', y_label: 'MB', queries: [{ metricId: 1, ...query1Attrs }, +// { metricId: 2, ...query2Attrs }] }, +// { title: 'new title', y_label: 'MB', queries: [{ metricId: 3, ...query3Attrs }]} +// ] +function groupQueriesByChartInfo(metrics) { + const metricsByChart = metrics.reduce((accumulator, metric) => { + const { queries, ...chart } = metric; + const metricId = chart.id ? chart.id.toString() : null; + + const chartKey = `${chart.title}|${chart.y_label}`; + accumulator[chartKey] = accumulator[chartKey] || { ...chart, queries: [] }; + + queries.forEach(queryAttrs => accumulator[chartKey].queries.push({ metricId, ...queryAttrs })); + + return accumulator; + }, {}); + + return Object.values(metricsByChart); +} + +function normalizeMetrics(metrics) { + const groupedMetrics = groupQueriesByChartInfo(metrics); + + return groupedMetrics.map(metric => { + const queries = metric.queries.map(query => ({ + ...query, + // custom metrics do not require a label, so we should ensure this attribute is defined + label: query.label || metric.y_label, + result: query.result.map(result => ({ + ...result, + values: result.values.map(([timestamp, value]) => [ + new Date(timestamp * 1000).toISOString(), + Number(value), + ]), + })), + })); + + return { + ...metric, + queries: removeTimeSeriesNoData(queries), + }; + }); +} + export const groups = state => { - return state.groups.map(group => { + return state.groups.reduce((acc, group) => { group.panels.forEach(panel => { panel.queries = panel.metrics; panel.queries.forEach(metric => { const metricId = metric.metric_id; const result = state.queryResults[metricId]; - metric.result = result; + metric.result = result || []; }); }); - return group; - }) - - // panel.queries[0].result - - // queryResults: { - // metricId - // result - // } + + const metrics = normalizeMetrics(sortMetrics(group.panels)); + + return acc.concat({ + ...group, + metrics, + }); + }, []); } diff --git a/app/assets/javascripts/monitoring/stores/mutations.js b/app/assets/javascripts/monitoring/stores/mutations.js index 05f273355f1..3cb370dda6a 100644 --- a/app/assets/javascripts/monitoring/stores/mutations.js +++ b/app/assets/javascripts/monitoring/stores/mutations.js @@ -110,12 +110,12 @@ export default { state.metricsEndpoint = endpoint; }, [types.SET_QUERY_RESULT](state, { metricId, result }) { - Vue.set(state.queryResults, metricId, result) + if (!metricId || !result) { + return; + } + Vue.set(state.queryResults, metricId, Object.freeze(result)); }, [types.SET_GROUPS](state, groups) { - state.groups = groups.map(group => ({ - ...group, - // metrics: normalizeMetrics(sortMetrics(group.metrics)), - })); + state.groups = groups; } }; |