diff --git a/docs/sources/features/datasources/stackdriver.md b/docs/sources/features/datasources/stackdriver.md index 3ae2ed3df40..d19dbe4ea50 100644 --- a/docs/sources/features/datasources/stackdriver.md +++ b/docs/sources/features/datasources/stackdriver.md @@ -156,6 +156,16 @@ Example Alias By: `{{metric.type}} - {{metric.labels.instance_name}}` Example Result: `compute.googleapis.com/instance/cpu/usage_time - server1-prod` +It is also possible to resolve the name of the Monitored Resource Type. + +| Alias Pattern Format | Description | Example Result | +| ------------------------ | ------------------------------------------------| ---------------- | +| `{{resource.type}}` | returns the name of the monitored resource type | `gce_instance` | + +Example Alias By: `{{resource.type}} - {{metric.type}}` + +Example Result: `gce_instance - compute.googleapis.com/instance/cpu/usage_time` + ## Templating Instead of hard-coding things like server, application and sensor name in you metric queries you can use variables in their place. diff --git a/pkg/tsdb/stackdriver/stackdriver.go b/pkg/tsdb/stackdriver/stackdriver.go index 8b903ba0113..b33d33fb41c 100644 --- a/pkg/tsdb/stackdriver/stackdriver.go +++ b/pkg/tsdb/stackdriver/stackdriver.go @@ -355,11 +355,21 @@ func (e *StackdriverExecutor) unmarshalResponse(res *http.Response) (Stackdriver func (e *StackdriverExecutor) parseResponse(queryRes *tsdb.QueryResult, data StackdriverResponse, query *StackdriverQuery) error { metricLabels := make(map[string][]string) resourceLabels := make(map[string][]string) + var resourceTypes []string + + for _, series := range data.TimeSeries { + if !containsLabel(resourceTypes, series.Resource.Type) { + resourceTypes = append(resourceTypes, series.Resource.Type) + } + } for _, series := range data.TimeSeries { points := make([]tsdb.TimePoint, 0) defaultMetricName := series.Metric.Type + if len(resourceTypes) > 1 { + defaultMetricName += " " + series.Resource.Type + } for key, value := range series.Metric.Labels { if !containsLabel(metricLabels[key], value) { @@ -403,7 +413,7 @@ func (e *StackdriverExecutor) parseResponse(queryRes *tsdb.QueryResult, data Sta points = append(points, tsdb.NewTimePoint(null.FloatFrom(value), float64((point.Interval.EndTime).Unix())*1000)) } - metricName := formatLegendKeys(series.Metric.Type, defaultMetricName, series.Metric.Labels, series.Resource.Labels, make(map[string]string), query) + metricName := formatLegendKeys(series.Metric.Type, defaultMetricName, series.Resource.Type, series.Metric.Labels, series.Resource.Labels, make(map[string]string), query) queryRes.Series = append(queryRes.Series, &tsdb.TimeSeries{ Name: metricName, @@ -429,7 +439,7 @@ func (e *StackdriverExecutor) parseResponse(queryRes *tsdb.QueryResult, data Sta bucketBound := calcBucketBound(point.Value.DistributionValue.BucketOptions, i) additionalLabels := map[string]string{"bucket": bucketBound} buckets[i] = &tsdb.TimeSeries{ - Name: formatLegendKeys(series.Metric.Type, defaultMetricName, series.Metric.Labels, series.Resource.Labels, additionalLabels, query), + Name: formatLegendKeys(series.Metric.Type, defaultMetricName, series.Resource.Type, series.Metric.Labels, series.Resource.Labels, additionalLabels, query), Points: make([]tsdb.TimePoint, 0), } if maxKey < i { @@ -445,7 +455,7 @@ func (e *StackdriverExecutor) parseResponse(queryRes *tsdb.QueryResult, data Sta bucketBound := calcBucketBound(point.Value.DistributionValue.BucketOptions, i) additionalLabels := map[string]string{"bucket": bucketBound} buckets[i] = &tsdb.TimeSeries{ - Name: formatLegendKeys(series.Metric.Type, defaultMetricName, series.Metric.Labels, series.Resource.Labels, additionalLabels, query), + Name: formatLegendKeys(series.Metric.Type, defaultMetricName, series.Resource.Type, series.Metric.Labels, series.Resource.Labels, additionalLabels, query), Points: make([]tsdb.TimePoint, 0), } } @@ -460,6 +470,7 @@ func (e *StackdriverExecutor) parseResponse(queryRes *tsdb.QueryResult, data Sta queryRes.Meta.Set("resourceLabels", resourceLabels) queryRes.Meta.Set("metricLabels", metricLabels) queryRes.Meta.Set("groupBys", query.GroupBys) + queryRes.Meta.Set("resourceTypes", resourceTypes) return nil } @@ -473,7 +484,7 @@ func containsLabel(labels []string, newLabel string) bool { return false } -func formatLegendKeys(metricType string, defaultMetricName string, metricLabels map[string]string, resourceLabels map[string]string, additionalLabels map[string]string, query *StackdriverQuery) string { +func formatLegendKeys(metricType string, defaultMetricName string, resourceType string, metricLabels map[string]string, resourceLabels map[string]string, additionalLabels map[string]string, query *StackdriverQuery) string { if query.AliasBy == "" { return defaultMetricName } @@ -487,6 +498,10 @@ func formatLegendKeys(metricType string, defaultMetricName string, metricLabels return []byte(metricType) } + if metaPartName == "resource.type" && resourceType != "" { + return []byte(resourceType) + } + metricPart := replaceWithMetricPart(metaPartName, metricType) if metricPart != nil { diff --git a/public/app/plugins/datasource/stackdriver/datasource.ts b/public/app/plugins/datasource/stackdriver/datasource.ts index cda952c23b9..4a81eb8a619 100644 --- a/public/app/plugins/datasource/stackdriver/datasource.ts +++ b/public/app/plugins/datasource/stackdriver/datasource.ts @@ -107,34 +107,32 @@ export default class StackdriverDatasource { } async query(options) { - this.queryPromise = new Promise(async resolve => { - const result = []; - const data = await this.getTimeSeries(options); - if (data.results) { - Object['values'](data.results).forEach(queryRes => { - if (!queryRes.series) { - return; + const result = []; + const data = await this.getTimeSeries(options); + if (data.results) { + Object['values'](data.results).forEach(queryRes => { + if (!queryRes.series) { + return; + } + this.projectName = queryRes.meta.defaultProject; + const unit = this.resolvePanelUnitFromTargets(options.targets); + queryRes.series.forEach(series => { + let timeSerie: any = { + target: series.name, + datapoints: series.points, + refId: queryRes.refId, + meta: queryRes.meta, + }; + if (unit) { + timeSerie = { ...timeSerie, unit }; } - this.projectName = queryRes.meta.defaultProject; - const unit = this.resolvePanelUnitFromTargets(options.targets); - queryRes.series.forEach(series => { - let timeSerie: any = { - target: series.name, - datapoints: series.points, - refId: queryRes.refId, - meta: queryRes.meta, - }; - if (unit) { - timeSerie = { ...timeSerie, unit }; - } - result.push(timeSerie); - }); + result.push(timeSerie); }); - } - - resolve({ data: result }); - }); - return this.queryPromise; + }); + return { data: result }; + } else { + return { data: [] }; + } } async annotationQuery(options) { diff --git a/public/app/plugins/datasource/stackdriver/filter_segments.ts b/public/app/plugins/datasource/stackdriver/filter_segments.ts index 9eb27f31975..5adb56e2fcf 100644 --- a/public/app/plugins/datasource/stackdriver/filter_segments.ts +++ b/public/app/plugins/datasource/stackdriver/filter_segments.ts @@ -44,7 +44,7 @@ export class FilterSegments { this.removeSegment.value = DefaultRemoveFilterValue; return Promise.resolve([this.removeSegment]); } else { - return this.getFilterKeysFunc(); + return this.getFilterKeysFunc(segment, DefaultRemoveFilterValue); } } diff --git a/public/app/plugins/datasource/stackdriver/partials/query.filter.html b/public/app/plugins/datasource/stackdriver/partials/query.filter.html index 9ec59005a0b..5043161c492 100644 --- a/public/app/plugins/datasource/stackdriver/partials/query.filter.html +++ b/public/app/plugins/datasource/stackdriver/partials/query.filter.html @@ -28,7 +28,7 @@