grafana/public/app/plugins/datasource/cloud-monitoring/functions.ts
Erik Sundell 5042dc3b52
CloudMonitoring: Add support for preprocessing (#33011)
* add support for handling preprocessors in the backend

* add preprocessor tests

* use uppercase for constants

* add super label component

* remove error message from query editor since its not working (probably cause onDataError doesnt work anymore)

* use cheat sheet instead of help

* add return type annotation for projects

* add support for preprocessing. replace segment comp with select. change components names and refactoring

* cleanup

* more pr feedback

* fix annotations editor

* rename aggregation component

* fix broken test

* remove unnecessary cast

* fix strict errors

* fix more strict errors

* remove not used prop

* update docs

* use same inline label for annotation editor

* fix react prop warning

* disable preprocessing for distribution types

* using new default values for reducer

* auto select 'rate' if metric kind is not gauge

* fix create label format

* pr feedback

* more pr feedback

* update images
2021-05-19 08:16:05 +02:00

141 lines
4.7 KiB
TypeScript

import { chunk, flatten, initial, startCase, uniqBy } from 'lodash';
import { ALIGNMENTS, AGGREGATIONS, SYSTEM_LABELS } from './constants';
import { SelectableValue } from '@grafana/data';
import CloudMonitoringDatasource from './datasource';
import { TemplateSrv, getTemplateSrv } from '@grafana/runtime';
import { MetricDescriptor, ValueTypes, MetricKind, AlignmentTypes, PreprocessorType, Filter } from './types';
const templateSrv: TemplateSrv = getTemplateSrv();
export const extractServicesFromMetricDescriptors = (metricDescriptors: MetricDescriptor[]) =>
uniqBy(metricDescriptors, 'service');
export const getMetricTypesByService = (metricDescriptors: MetricDescriptor[], service: string) =>
metricDescriptors.filter((m: MetricDescriptor) => m.service === service);
export const getMetricTypes = (
metricDescriptors: MetricDescriptor[],
metricType: string,
interpolatedMetricType: string,
selectedService: string
) => {
const metricTypes = getMetricTypesByService(metricDescriptors, selectedService).map((m) => ({
value: m.type,
name: m.displayName,
}));
const metricTypeExistInArray = metricTypes.some(
(m: { value: string; name: string }) => m.value === interpolatedMetricType
);
const metricTypeByService = metricTypes.length ? metricTypes[0].value : '';
const selectedMetricType = metricTypeExistInArray ? metricType : metricTypeByService;
return {
metricTypes,
selectedMetricType,
};
};
export const getAlignmentOptionsByMetric = (
metricValueType: string,
metricKind: string,
preprocessor?: PreprocessorType
) => {
if (preprocessor && preprocessor === PreprocessorType.Rate) {
metricKind = MetricKind.GAUGE;
}
return !metricValueType
? []
: ALIGNMENTS.filter((i) => {
return (
i.valueTypes.indexOf(metricValueType as ValueTypes) !== -1 &&
i.metricKinds.indexOf(metricKind as MetricKind) !== -1
);
});
};
export const getAggregationOptionsByMetric = (valueType: ValueTypes, metricKind: MetricKind) => {
return !metricKind
? []
: AGGREGATIONS.filter((i) => {
return i.valueTypes.indexOf(valueType) !== -1 && i.metricKinds.indexOf(metricKind) !== -1;
});
};
export const getLabelKeys = async (
datasource: CloudMonitoringDatasource,
selectedMetricType: string,
projectName: string
) => {
const refId = 'handleLabelKeysQuery';
const labels = await datasource.getLabels(selectedMetricType, refId, projectName);
return [...Object.keys(labels), ...SYSTEM_LABELS];
};
export const getAlignmentPickerData = (
valueType: string | undefined = ValueTypes.DOUBLE,
metricKind: string | undefined = MetricKind.GAUGE,
perSeriesAligner: string | undefined = AlignmentTypes.ALIGN_MEAN,
preprocessor?: PreprocessorType
) => {
const alignOptions = getAlignmentOptionsByMetric(valueType!, metricKind!, preprocessor!).map((option) => ({
...option,
label: option.text,
}));
if (!alignOptions.some((o: { value: string }) => o.value === templateSrv.replace(perSeriesAligner))) {
perSeriesAligner = alignOptions.length > 0 ? alignOptions[0].value : AlignmentTypes.ALIGN_MEAN;
}
return { alignOptions, perSeriesAligner };
};
export const labelsToGroupedOptions = (groupBys: string[]) => {
const groups = groupBys.reduce((acc: any, curr: string) => {
const arr = curr.split('.').map(startCase);
const group = (arr.length === 2 ? arr : initial(arr)).join(' ');
const option = {
value: curr,
label: curr,
};
if (acc[group]) {
acc[group] = [...acc[group], option];
} else {
acc[group] = [option];
}
return acc;
}, {});
return Object.entries(groups).map(([label, options]) => ({ label, options, expanded: true }), []);
};
export const filtersToStringArray = (filters: Filter[]) => {
const strArr = flatten(filters.map(({ key, operator, value, condition }) => [key, operator, value, condition!]));
return strArr.filter((_, i) => i !== strArr.length - 1);
};
export const stringArrayToFilters = (filterArray: string[]) =>
chunk(filterArray, 4).map(([key, operator, value, condition = 'AND']) => ({
key,
operator,
value,
condition,
}));
export const toOption = (value: string) => ({ label: value, value } as SelectableValue<string>);
export const formatCloudMonitoringError = (error: any) => {
let message = error.statusText ?? '';
if (error.data && error.data.error) {
try {
const res = JSON.parse(error.data.error);
message += res.error.code + '. ' + res.error.message;
} catch (err) {
message += error.data.error;
}
} else if (error.data && error.data.message) {
try {
message = JSON.parse(error.data.message).error.message;
} catch (err) {
error.error = err;
}
}
return message;
};