Files
grafana/public/app/plugins/datasource/stackdriver/StackdriverMetricFindQuery.ts
Erik Sundell a111cc0d5c Stackdriver: Support for SLO queries (#22917)
* wip: add slo support

* Export DataSourcePlugin

* wip: break out metric query editor into its own component

* wip: refactor frontend - keep SLO and Metric query in differnt objects

* wip - load services and slos

* Fix broken test

* Add interactive slo expression builder

* Change order of dropdowns

* Refactoring backend model. slo unit testing in progress

* Unit test migration and SLOs

* Cleanup SLO editor

* Simplify alias by component

* Support alias by for slos

* Support slos in variable queries

* Fix broken last query error

* Update Help section to include SLO aliases

* streamline datasource resource cache

* Break out api specific stuff in datasource to its own file

* Move get projects call to frontend

* Refactor api caching

* Unit test api service

* Fix lint go issue

* Fix typescript strict errors

* Fix test datasource

* Use budget fraction selector instead of budget

* Reset SLO when service is changed

* Handle error in case resource call returned no data

* Show real SLI display name

* Use unsafe prefix on will mount hook

* Store goal in query model since it will be used as soon as graph panel supports adding a threshold

* Add comment to describe why componentWillMount is used

* Interpolate sloid

* Break out SLO aggregation into its own func

* Also test group bys for metricquery test

* Remove not used type fields

* Remove annoying stackdriver prefix from error message

* Default view param to FULL

* Add part about SLO query builder in docs

* Use new images

* Fixes after feedback

* Add one more group by test

* Make stackdriver types internal

* Update docs/sources/features/datasources/stackdriver.md

Co-Authored-By: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>

* Update docs/sources/features/datasources/stackdriver.md

Co-Authored-By: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>

* Update docs/sources/features/datasources/stackdriver.md

Co-Authored-By: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>

* Updates after PR feedback

* add test for when no alias by defined

* fix infinite loop when newVariables feature flag is on

onChange being called in componentDidUpdate produces an
infinite loop when using the new React template variable
implementation.

Also fixes a spelling mistake

* implements feedback for documentation changes

* more doc changes

Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>
Co-authored-by: Daniel Lee <dan.limerick@gmail.com>
2020-03-27 12:01:16 +01:00

162 lines
5.9 KiB
TypeScript

import isString from 'lodash/isString';
import { alignmentPeriods, ValueTypes, MetricKind, selectors } from './constants';
import StackdriverDatasource from './datasource';
import { MetricFindQueryTypes, VariableQueryData } from './types';
import { SelectableValue } from '@grafana/data';
import {
getMetricTypesByService,
getAlignmentOptionsByMetric,
getAggregationOptionsByMetric,
extractServicesFromMetricDescriptors,
getLabelKeys,
} from './functions';
export default class StackdriverMetricFindQuery {
constructor(private datasource: StackdriverDatasource) {}
async execute(query: VariableQueryData) {
try {
if (!query.projectName) {
query.projectName = this.datasource.getDefaultProject();
}
switch (query.selectedQueryType) {
case MetricFindQueryTypes.Projects:
return this.handleProjectsQuery();
case MetricFindQueryTypes.Services:
return this.handleServiceQuery(query);
case MetricFindQueryTypes.MetricTypes:
return this.handleMetricTypesQuery(query);
case MetricFindQueryTypes.LabelKeys:
return this.handleLabelKeysQuery(query);
case MetricFindQueryTypes.LabelValues:
return this.handleLabelValuesQuery(query);
case MetricFindQueryTypes.ResourceTypes:
return this.handleResourceTypeQuery(query);
case MetricFindQueryTypes.Aligners:
return this.handleAlignersQuery(query);
case MetricFindQueryTypes.AlignmentPeriods:
return this.handleAlignmentPeriodQuery();
case MetricFindQueryTypes.Aggregations:
return this.handleAggregationQuery(query);
case MetricFindQueryTypes.SLOServices:
return this.handleSLOServicesQuery(query);
case MetricFindQueryTypes.SLO:
return this.handleSLOQuery(query);
case MetricFindQueryTypes.Selectors:
return this.handleSelectorQuery();
default:
return [];
}
} catch (error) {
console.error(`Could not run StackdriverMetricFindQuery ${query}`, error);
return [];
}
}
async handleProjectsQuery() {
const projects = await this.datasource.getProjects();
return (projects as SelectableValue<string>).map((s: { label: string; value: string }) => ({
text: s.label,
value: s.value,
expandable: true,
}));
}
async handleServiceQuery({ projectName }: VariableQueryData) {
const metricDescriptors = await this.datasource.getMetricTypes(projectName);
const services: any[] = extractServicesFromMetricDescriptors(metricDescriptors);
return services.map(s => ({
text: s.serviceShortName,
value: s.service,
expandable: true,
}));
}
async handleMetricTypesQuery({ selectedService, projectName }: VariableQueryData) {
if (!selectedService) {
return [];
}
const metricDescriptors = await this.datasource.getMetricTypes(projectName);
return getMetricTypesByService(metricDescriptors, this.datasource.templateSrv.replace(selectedService)).map(
(s: any) => ({
text: s.displayName,
value: s.type,
expandable: true,
})
);
}
async handleLabelKeysQuery({ selectedMetricType, projectName }: VariableQueryData) {
if (!selectedMetricType) {
return [];
}
const labelKeys = await getLabelKeys(this.datasource, selectedMetricType, projectName);
return labelKeys.map(this.toFindQueryResult);
}
async handleLabelValuesQuery({ selectedMetricType, labelKey, projectName }: VariableQueryData) {
if (!selectedMetricType) {
return [];
}
const refId = 'handleLabelValuesQuery';
const labels = await this.datasource.getLabels(selectedMetricType, refId, projectName, [labelKey]);
const interpolatedKey = this.datasource.templateSrv.replace(labelKey);
const values = labels.hasOwnProperty(interpolatedKey) ? labels[interpolatedKey] : [];
return values.map(this.toFindQueryResult);
}
async handleResourceTypeQuery({ selectedMetricType, projectName }: VariableQueryData) {
if (!selectedMetricType) {
return [];
}
const refId = 'handleResourceTypeQueryQueryType';
const labels = await this.datasource.getLabels(selectedMetricType, refId, projectName);
return labels['resource.type'].map(this.toFindQueryResult);
}
async handleAlignersQuery({ selectedMetricType, projectName }: VariableQueryData) {
if (!selectedMetricType) {
return [];
}
const metricDescriptors = await this.datasource.getMetricTypes(projectName);
const { valueType, metricKind } = metricDescriptors.find(
(m: any) => m.type === this.datasource.templateSrv.replace(selectedMetricType)
);
return getAlignmentOptionsByMetric(valueType, metricKind).map(this.toFindQueryResult);
}
async handleAggregationQuery({ selectedMetricType, projectName }: VariableQueryData) {
if (!selectedMetricType) {
return [];
}
const metricDescriptors = await this.datasource.getMetricTypes(projectName);
const { valueType, metricKind } = metricDescriptors.find(
(m: any) => m.type === this.datasource.templateSrv.replace(selectedMetricType)
);
return getAggregationOptionsByMetric(valueType as ValueTypes, metricKind as MetricKind).map(this.toFindQueryResult);
}
async handleSLOServicesQuery({ projectName }: VariableQueryData) {
const services = await this.datasource.getSLOServices(projectName);
return services.map(this.toFindQueryResult);
}
async handleSLOQuery({ selectedSLOService, projectName }: VariableQueryData) {
const slos = await this.datasource.getServiceLevelObjectives(projectName, selectedSLOService);
return slos.map(this.toFindQueryResult);
}
async handleSelectorQuery() {
return selectors.map(this.toFindQueryResult);
}
handleAlignmentPeriodQuery() {
return alignmentPeriods.map(this.toFindQueryResult);
}
toFindQueryResult(x: any) {
return isString(x) ? { text: x, expandable: true } : { ...x, expandable: true };
}
}