Commit f90206a9 authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch '195739' into 'master'

Update query labels dynamically for embedded charts

See merge request gitlab-org/gitlab!29034
parents 27b453cb 42eef06a
/**
* @param {String} queryLabel - Default query label for chart
* @param {Object} metricAttributes - Default metric attribute values (e.g. method, instance)
* @returns {String} The formatted query label
* @example
* singleAttributeLabel('app', {__name__: "up", app: "prometheus"}) -> "app: prometheus"
*/
const singleAttributeLabel = (queryLabel, metricAttributes) => {
if (!queryLabel) return '';
const relevantAttribute = queryLabel.toLowerCase().replace(' ', '_');
const value = metricAttributes[relevantAttribute];
if (!value) return '';
return `${queryLabel}: ${value}`;
};
/**
* @param {String} queryLabel - Default query label for chart
* @param {Object} metricAttributes - Default metric attribute values (e.g. method, instance)
* @returns {String} The formatted query label
* @example
* templatedLabel('__name__', {__name__: "up", app: "prometheus"}) -> "__name__"
*/
const templatedLabel = (queryLabel, metricAttributes) => {
if (!queryLabel) return '';
// eslint-disable-next-line array-callback-return
Object.entries(metricAttributes).map(([templateVar, label]) => {
const regex = new RegExp(`{{\\s*${templateVar}\\s*}}`, 'g');
// eslint-disable-next-line no-param-reassign
queryLabel = queryLabel.replace(regex, label);
});
return queryLabel;
};
/**
* @param {Object} metricAttributes - Default metric attribute values (e.g. method, instance)
* @returns {String} The formatted query label
* @example
* multiMetricLabel('', {__name__: "up", app: "prometheus"}) -> "__name__: up, app: prometheus"
*/
const multiMetricLabel = metricAttributes => {
return Object.entries(metricAttributes)
.map(([templateVar, label]) => `${templateVar}: ${label}`)
.join(', ');
};
/**
* @param {String} queryLabel - Default query label for chart
* @param {Object} metricAttributes - Default metric attribute values (e.g. method, instance)
* @returns {String} The formatted query label
*/
const getSeriesLabel = (queryLabel, metricAttributes) => {
return (
singleAttributeLabel(queryLabel, metricAttributes) ||
templatedLabel(queryLabel, metricAttributes) ||
multiMetricLabel(metricAttributes) ||
queryLabel
);
};
/**
* @param {Array} queryResults - Array of Result objects
* @param {Object} defaultConfig - Default chart config values (e.g. lineStyle, name)
......@@ -12,21 +72,11 @@ export const makeDataSeries = (queryResults, defaultConfig) =>
if (!data.length) {
return null;
}
const relevantMetric = defaultConfig.name.toLowerCase().replace(' ', '_');
const name = result.metric[relevantMetric];
const series = { data };
if (name) {
series.name = `${defaultConfig.name}: ${name}`;
} else {
series.name = defaultConfig.name;
Object.keys(result.metric).forEach(templateVar => {
const value = result.metric[templateVar];
const regex = new RegExp(`{{\\s*${templateVar}\\s*}}`, 'g');
series.name = series.name.replace(regex, value);
});
}
return { ...defaultConfig, ...series };
return {
...defaultConfig,
...series,
name: getSeriesLabel(defaultConfig.name, result.metric),
};
})
.filter(series => series !== null);
......@@ -58,7 +58,7 @@ export default {
},
methods: {
formatLegendLabel(query) {
return `${query.label}`;
return query.label;
},
onResize() {
if (!this.$refs.barChart) return;
......
......@@ -76,7 +76,7 @@ export default {
},
methods: {
formatLegendLabel(query) {
return `${query.label}`;
return query.label;
},
onResize() {
if (!this.$refs.columnChart) return;
......
......@@ -251,7 +251,7 @@ export default {
},
methods: {
formatLegendLabel(query) {
return `${query.label}`;
return query.label;
},
isTooltipOfType(tooltipType, defaultType) {
return tooltipType === defaultType;
......
......@@ -68,12 +68,11 @@ export const parseEnvironmentsResponse = (response = [], projectPath) =>
* https://gitlab.com/gitlab-org/gitlab/issues/207198
*
* @param {Array} metrics - Array of prometheus metrics
* @param {String} defaultLabel - Default label for metrics
* @returns {Object}
*/
const mapToMetricsViewModel = (metrics, defaultLabel) =>
const mapToMetricsViewModel = metrics =>
metrics.map(({ label, id, metric_id, query_range, prometheus_endpoint_path, ...metric }) => ({
label: label || defaultLabel,
label,
queryRange: query_range,
prometheusEndpointPath: prometheus_endpoint_path,
metricId: uniqMetricsId({ metric_id, id }),
......
---
title: Update query labels dynamically for embedded charts
merge_request: 29034
author:
type: other
......@@ -37,5 +37,8 @@ export function alertsValidator(value) {
// }
// ]
export function queriesValidator(value) {
return value.every(query => query.metricId && typeof query.metricId === 'string' && query.label);
return value.every(
query =>
query.metricId && typeof query.metricId === 'string' && typeof query.label === 'string',
);
}
......@@ -56,6 +56,32 @@ describe('monitor helper', () => {
expect(result.name).toEqual('brpop');
});
it('supports a multi metric label template expression', () => {
const config = {
...defaultConfig,
name: '',
};
const [result] = monitorHelper.makeDataSeries(
[
{
metric: {
backend: 'HA Server',
frontend: 'BA Server',
app: 'prometheus',
instance: 'k8 cluster 1',
},
values: series,
},
],
config,
);
expect(result.name).toBe(
'backend: HA Server, frontend: BA Server, app: prometheus, instance: k8 cluster 1',
);
});
it('supports space-padded template expressions', () => {
const config = {
...defaultConfig,
......
......@@ -251,7 +251,7 @@ describe('mapToDashboardViewModel', () => {
};
it('creates a metric', () => {
const dashboard = dashboardWithMetric({});
const dashboard = dashboardWithMetric({ label: 'Panel Label' });
expect(getMappedMetric(dashboard)).toEqual({
label: expect.any(String),
......@@ -268,11 +268,11 @@ describe('mapToDashboardViewModel', () => {
expect(getMappedMetric(dashboard).metricId).toEqual('1_http_responses');
});
it('creates a metric with a default label', () => {
it('creates a metric without a default label', () => {
const dashboard = dashboardWithMetric({});
expect(getMappedMetric(dashboard)).toMatchObject({
label: defaultLabel,
label: undefined,
});
});
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment