stackdriver: return values for services and metric types

This commit is contained in:
Erik Sundell
2018-10-26 14:03:05 +02:00
parent f0cba0b0d8
commit 7ccce76b80
9 changed files with 92 additions and 35 deletions

View File

@ -1,11 +1,7 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { TemplateQueryProps } from 'app/types/plugins';
interface Props { export default class DefaultTemplateQueryComponent extends PureComponent<TemplateQueryProps, any> {
query: string;
onChange: (c: string) => void;
}
export default class DefaultTemplateQueryComponent extends PureComponent<Props, any> {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { value: props.query }; this.state = { value: props.query };

View File

@ -72,6 +72,7 @@ export class VariableEditorCtrl {
if ( if (
$scope.current.type === 'query' && $scope.current.type === 'query' &&
_.isString($scope.current.query) &&
$scope.current.query.match(new RegExp('\\$' + $scope.current.name + '(/| |$)')) $scope.current.query.match(new RegExp('\\$' + $scope.current.name + '(/| |$)'))
) { ) {
appEvents.emit('alert-warning', [ appEvents.emit('alert-warning', [

View File

@ -0,0 +1,36 @@
import { extractServicesFromMetricDescriptors, getMetricTypesByService } from './functions';
export default class StackdriverMetricFindQuery {
constructor(private datasource) {}
async query(query: any) {
switch (query.type) {
case 'services':
return this.handleServiceQueryType();
case 'metricTypes':
return this.handleMetricTypesQueryType(query);
default:
return [];
}
}
async handleServiceQueryType() {
const metricDescriptors = await this.datasource.getMetricTypes(this.datasource.projectName);
const services = extractServicesFromMetricDescriptors(metricDescriptors);
return services.map(s => ({
text: s.name,
expandable: true,
}));
}
async handleMetricTypesQueryType({ service }) {
if (!service) {
return [];
}
const metricDescriptors = await this.datasource.getMetricTypes(this.datasource.projectName);
return getMetricTypesByService(metricDescriptors, service).map(s => ({
text: s.name,
expandable: true,
}));
}
}

View File

@ -1,4 +1,5 @@
import React, { SFC } from 'react'; import React, { SFC } from 'react';
import { getMetricTypesByService } from '../functions';
interface Props { interface Props {
onMetricTypeChange: any; onMetricTypeChange: any;
@ -12,7 +13,7 @@ const MetricTypeSelector: SFC<Props> = props => {
return []; return [];
} }
return props.metricDescriptors.filter(m => m.service === props.selectedService).map(m => ({ return getMetricTypesByService(props.metricDescriptors, props.selectedService).map(m => ({
value: m.service, value: m.service,
name: m.displayName, name: m.displayName,
})); }));

View File

@ -1,5 +1,5 @@
import React, { SFC } from 'react'; import React, { SFC } from 'react';
import uniqBy from 'lodash/uniqBy'; import { extractServicesFromMetricDescriptors } from '../functions';
interface Props { interface Props {
onServiceChange: any; onServiceChange: any;
@ -7,11 +7,12 @@ interface Props {
} }
const ServiceSelector: SFC<Props> = props => { const ServiceSelector: SFC<Props> = props => {
const extractServices = () => const extractServices = () => {
uniqBy(props.metricDescriptors, 'service').map(m => ({ return extractServicesFromMetricDescriptors(props.metricDescriptors).map(m => ({
value: m.service, value: m.service,
name: m.serviceShortName, name: m.serviceShortName,
})); }));
};
return ( return (
<div className="gf-form max-width-21"> <div className="gf-form max-width-21">

View File

@ -1,27 +1,24 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import StackdriverDatasource from '../datasource'; // import StackdriverDatasource from '../datasource';
import ServiceSelector from './ServiceSelector'; import ServiceSelector from './ServiceSelector';
import MetricTypeSelector from './MetricTypeSelector'; import MetricTypeSelector from './MetricTypeSelector';
import { TemplateQueryProps } from 'app/types/plugins';
import defaultsDeep from 'lodash/defaultsDeep';
interface Props { export class StackdriverTemplateQueryComponent extends PureComponent<TemplateQueryProps, any> {
datasource: StackdriverDatasource;
query: any;
onChange: (c: string) => void;
}
export class StackdriverTemplateQueryComponent extends PureComponent<Props, any> {
queryTypes: Array<{ value: string; name: string }> = [ queryTypes: Array<{ value: string; name: string }> = [
{ value: 'services', name: 'Services' }, { value: 'services', name: 'Services' },
{ value: 'metricTypes', name: 'Metric Types' }, { value: 'metricTypes', name: 'Metric Types' },
{ value: 'metricLabels', name: 'Metric labels For Metric Type' }, { value: 'metricLabels', name: 'Metric labels For Metric Type' },
]; ];
defaults = { type: undefined, metricDescriptors: [], service: undefined, metricType: undefined };
constructor(props) { constructor(props: TemplateQueryProps) {
super(props); super(props);
this.handleQueryTypeChange = this.handleQueryTypeChange.bind(this); this.handleQueryTypeChange = this.handleQueryTypeChange.bind(this);
this.onServiceChange = this.onServiceChange.bind(this); this.onServiceChange = this.onServiceChange.bind(this);
this.onMetricTypeChange = this.onMetricTypeChange.bind(this); this.onMetricTypeChange = this.onMetricTypeChange.bind(this);
this.state = { queryType: undefined, metricDescriptors: [], service: undefined, metricType: undefined }; this.state = defaultsDeep(this.props.query, this.defaults);
} }
async componentDidMount() { async componentDidMount() {
@ -30,7 +27,7 @@ export class StackdriverTemplateQueryComponent extends PureComponent<Props, any>
} }
handleQueryTypeChange(event) { handleQueryTypeChange(event) {
this.setState({ queryType: event.target.value }); this.setState({ type: event.target.value });
} }
onServiceChange(event) { onServiceChange(event) {
@ -41,6 +38,11 @@ export class StackdriverTemplateQueryComponent extends PureComponent<Props, any>
this.setState({ metricType: event.target.value }); this.setState({ metricType: event.target.value });
} }
componentDidUpdate() {
const { metricDescriptors, ...queryModel } = this.state;
this.props.onChange(queryModel);
}
renderSwitch(queryType) { renderSwitch(queryType) {
switch (queryType) { switch (queryType) {
case 'metricTypes': case 'metricTypes':
@ -78,7 +80,7 @@ export class StackdriverTemplateQueryComponent extends PureComponent<Props, any>
</select> </select>
</div> </div>
</div> </div>
{this.renderSwitch(this.state.queryType)} {this.renderSwitch(this.state.type)}
</React.Fragment> </React.Fragment>
); );
} }

View File

@ -1,6 +1,7 @@
import { stackdriverUnitMappings } from './constants'; import { stackdriverUnitMappings } from './constants';
import appEvents from 'app/core/app_events'; import appEvents from 'app/core/app_events';
import _ from 'lodash'; import _ from 'lodash';
import StackdriverMetricFindQuery from './StackdriverMetricFindQuery';
export default class StackdriverDatasource { export default class StackdriverDatasource {
id: number; id: number;
@ -9,6 +10,7 @@ export default class StackdriverDatasource {
projectName: string; projectName: string;
authenticationType: string; authenticationType: string;
queryPromise: Promise<any>; queryPromise: Promise<any>;
metricTypes: any[];
/** @ngInject */ /** @ngInject */
constructor(instanceSettings, private backendSrv, private templateSrv, private timeSrv) { constructor(instanceSettings, private backendSrv, private templateSrv, private timeSrv) {
@ -18,6 +20,7 @@ export default class StackdriverDatasource {
this.id = instanceSettings.id; this.id = instanceSettings.id;
this.projectName = instanceSettings.jsonData.defaultProject || ''; this.projectName = instanceSettings.jsonData.defaultProject || '';
this.authenticationType = instanceSettings.jsonData.authenticationType || 'jwt'; this.authenticationType = instanceSettings.jsonData.authenticationType || 'jwt';
this.metricTypes = [];
} }
async getTimeSeries(options) { async getTimeSeries(options) {
@ -177,8 +180,10 @@ export default class StackdriverDatasource {
return results; return results;
} }
metricFindQuery(query) { async metricFindQuery(query) {
throw new Error('Template variables support is not yet imlemented'); const stackdriverMetricFindQuery = new StackdriverMetricFindQuery(this);
return stackdriverMetricFindQuery.query(query);
// throw new Error('Template variables support is not yet imlemented');
} }
async testDatasource() { async testDatasource() {
@ -258,10 +263,11 @@ export default class StackdriverDatasource {
async getMetricTypes(projectName: string) { async getMetricTypes(projectName: string) {
try { try {
if (this.metricTypes.length === 0) {
const metricsApiPath = `v3/projects/${projectName}/metricDescriptors`; const metricsApiPath = `v3/projects/${projectName}/metricDescriptors`;
const { data } = await this.doRequest(`${this.baseUrl}${metricsApiPath}`); const { data } = await this.doRequest(`${this.baseUrl}${metricsApiPath}`);
const metrics = data.metricDescriptors.map(m => { this.metricTypes = data.metricDescriptors.map(m => {
const [service] = m.type.split('/'); const [service] = m.type.split('/');
const [serviceShortName] = service.split('.'); const [serviceShortName] = service.split('.');
m.service = service; m.service = service;
@ -269,8 +275,9 @@ export default class StackdriverDatasource {
m.displayName = m.displayName || m.type; m.displayName = m.displayName || m.type;
return m; return m;
}); });
}
return metrics; return this.metricTypes;
} catch (error) { } catch (error) {
appEvents.emit('ds-request-error', this.formatStackdriverError(error)); appEvents.emit('ds-request-error', this.formatStackdriverError(error));
return []; return [];

View File

@ -0,0 +1,6 @@
import uniqBy from 'lodash/uniqBy';
export const extractServicesFromMetricDescriptors = metricDescriptors => uniqBy(metricDescriptors, 'service');
export const getMetricTypesByService = (metricDescriptors, service) =>
metricDescriptors.filter(m => m.service === service);

View File

@ -99,3 +99,10 @@ export interface PluginsState {
hasFetched: boolean; hasFetched: boolean;
dashboards: PluginDashboard[]; dashboards: PluginDashboard[];
} }
export interface TemplateQueryProps {
query: any;
onChange: (c: any) => void;
datasource: any;
// datasource: StackdriverDatasource;
}