mirror of
https://github.com/grafana/grafana.git
synced 2024-11-26 02:40:26 -06:00
Stackdriver: Rename Stackdriver to Google Cloud Monitoring (#25807)
* Update backend * Update frontend * Keep old plugin id * Update docs * Place doc images to a new directory * Legacy support for stackdriver-auto alignment * Consistent plugin name * Apply suggestions from code review Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com> Co-authored-by: Tobias Skarhed <1438972+tskarhed@users.noreply.github.com> * Update docs * Update public/app/plugins/datasource/cloud-monitoring/README.md Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com> * Add reference to the data source formerly being named Stackdriver * Update pkg/models/datasource.go Co-authored-by: Carl Bergquist <carl@grafana.com> * Fix gofmt Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com> Co-authored-by: Tobias Skarhed <1438972+tskarhed@users.noreply.github.com> Co-authored-by: Carl Bergquist <carl@grafana.com>
This commit is contained in:
parent
05bfd17b00
commit
4bb3f66569
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@ -56,5 +56,5 @@ lerna.json @grafana/grafana-frontend-platform
|
||||
/public/app/plugins/datasource/opentsdb @grafana/backend-platform
|
||||
/public/app/plugins/datasource/postgres @grafana/backend-platform
|
||||
/public/app/plugins/datasource/prometheus @grafana/observability-squad
|
||||
/public/app/plugins/datasource/stackdriver @grafana/backend-platform
|
||||
/public/app/plugins/datasource/cloud-monitoring @grafana/backend-platform
|
||||
/public/app/plugins/datasource/zipkin @grafana/observability-squad
|
||||
|
@ -91,9 +91,9 @@ aliases = ["/docs/grafana/v1.1", "/docs/grafana/latest/guides/reference/admin",
|
||||
<img src="/img/docs/logos/icon_prometheus.svg" >
|
||||
<h5>Prometheus</h5>
|
||||
</a>
|
||||
<a href="{{< relref "features/datasources/stackdriver.md" >}}" class="nav-cards__item nav-cards__item--ds">
|
||||
<img src="/img/docs/logos/icon_stackdriver.svg">
|
||||
<h5>Google Stackdriver</h5>
|
||||
<a href="{{< relref "features/datasources/cloudmonitoring.md" >}}" class="nav-cards__item nav-cards__item--ds">
|
||||
<img src="/img/docs/logos/icon_cloudmonitoring.svg">
|
||||
<h5>Google Cloud Monitoring</h5>
|
||||
</a>
|
||||
<a href="{{< relref "features/datasources/cloudwatch.md" >}}" class="nav-cards__item nav-cards__item--ds">
|
||||
<img src="/img/docs/logos/icon_cloudwatch.svg">
|
||||
|
@ -41,7 +41,7 @@ The actual notifications are configured and shared between multiple alerts.
|
||||
|
||||
Alert rules are evaluated in the Grafana backend in a scheduler and query execution engine that is part
|
||||
of core Grafana. Only some data sources are supported right now. They include `Graphite`, `Prometheus`, `InfluxDB`, `Elasticsearch`,
|
||||
`Stackdriver`, `Cloudwatch`, `Azure Monitor`, `MySQL`, `PostgreSQL`, `MSSQL`, `OpenTSDB`, `Oracle`, and `Azure Data Explorer`.
|
||||
`Google Cloud Monitoring`, `Cloudwatch`, `Azure Monitor`, `MySQL`, `PostgreSQL`, `MSSQL`, `OpenTSDB`, `Oracle`, and `Azure Data Explorer`.
|
||||
|
||||
## Metrics from the alert engine
|
||||
|
||||
|
@ -42,7 +42,7 @@ The actual notifications are configured and shared between multiple alerts.
|
||||
|
||||
Alert rules are evaluated in the Grafana backend in a scheduler and query execution engine that is part
|
||||
of core Grafana. Only some data sources are supported right now. They include `Graphite`, `Prometheus`, `InfluxDB`, `Elasticsearch`,
|
||||
`Stackdriver`, `Cloudwatch`, `Azure Monitor`, `MySQL`, `PostgreSQL`, `MSSQL`, `OpenTSDB`, `Oracle`, and `Azure Data Explorer`.
|
||||
`Google Cloud Monitoring`, `Cloudwatch`, `Azure Monitor`, `MySQL`, `PostgreSQL`, `MSSQL`, `OpenTSDB`, `Oracle`, and `Azure Data Explorer`.
|
||||
|
||||
## Metrics from the alert engine
|
||||
|
||||
|
@ -24,7 +24,7 @@ The following data sources are officially supported:
|
||||
* [AWS CloudWatch]({{< relref "cloudwatch.md" >}})
|
||||
* [Azure Monitor]({{< relref "azuremonitor.md" >}})
|
||||
* [Elasticsearch]({{< relref "elasticsearch.md" >}})
|
||||
* [Google Stackdriver]({{< relref "stackdriver.md" >}})
|
||||
* [Google Cloud Monitoring]({{< relref "cloudmonitoring.md" >}})
|
||||
* [Graphite]({{< relref "graphite.md" >}})
|
||||
* [InfluxDB]({{< relref "influxdb.md" >}})
|
||||
* [Loki]({{< relref "loki.md" >}})
|
||||
|
@ -1,28 +1,29 @@
|
||||
+++
|
||||
title = "Using Stackdriver in Grafana"
|
||||
description = "Guide for using Stackdriver in Grafana"
|
||||
keywords = ["grafana", "stackdriver", "google", "guide"]
|
||||
title = "Using Google Cloud Monitoring in Grafana"
|
||||
description = "Guide for using Google Cloud Monitoring in Grafana"
|
||||
keywords = ["grafana", "stackdriver", "google", "guide", "cloud", "monitoring"]
|
||||
type = "docs"
|
||||
aliases = ["/docs/grafana/latest/datasources/stackdriver"]
|
||||
aliases = ["/docs/grafana/latest/datasources/stackdriver", "/docs/grafana/latest/features/datasources/stackdriver/"]
|
||||
[menu.docs]
|
||||
name = "Google Stackdriver"
|
||||
name = "Google Cloud Monitoring"
|
||||
parent = "datasources"
|
||||
weight = 4
|
||||
+++
|
||||
|
||||
# Using Google Stackdriver in Grafana
|
||||
# Using Google Cloud Monitoring in Grafana
|
||||
|
||||
> Available as a beta feature in Grafana v5.3.x and v5.4.x.
|
||||
> Officially released in Grafana v6.0.0
|
||||
|
||||
Grafana ships with built-in support for Google Stackdriver. Just add it as a data source and you are ready to build dashboards for your Stackdriver metrics.
|
||||
> Before Grafana v7.1 this data source was named Google Stackdriver.
|
||||
|
||||
Grafana ships with built-in support for Google Cloud Monitoring. Just add it as a data source and you are ready to build dashboards for your Google Cloud Monitoring metrics.
|
||||
|
||||
## Adding the data source
|
||||
|
||||
1. Open the side menu by clicking the Grafana icon in the top header.
|
||||
2. In the side menu under the `Dashboards` link you should find a link named `Data Sources`.
|
||||
3. Click the `+ Add data source` button in the top header.
|
||||
4. Select `Stackdriver` from the _Type_ dropdown.
|
||||
4. Select `Google Cloud Monitoring` from the _Type_ dropdown.
|
||||
5. Upload or paste in the Service Account Key file. See below for steps on how to create a Service Account Key file.
|
||||
|
||||
> NOTE: If you're not seeing the `Data Sources` link in your side menu it means that your current user does not have the `Admin` role for the current organization.
|
||||
@ -35,11 +36,11 @@ Grafana ships with built-in support for Google Stackdriver. Just add it as a dat
|
||||
|
||||
## Authentication
|
||||
|
||||
There are two ways to authenticate the Stackdriver plugin - either by uploading a Google JWT file, or by automatically retrieving credentials from Google metadata server. The latter option is only available when running Grafana on GCE virtual machine.
|
||||
There are two ways to authenticate the Google Cloud Monitoring plugin - either by uploading a Google JWT file, or by automatically retrieving credentials from Google metadata server. The latter option is only available when running Grafana on GCE virtual machine.
|
||||
|
||||
### Using a Google Service Account Key File
|
||||
|
||||
To authenticate with the Stackdriver API, you need to create a Google Cloud Platform (GCP) Service Account for the Project you want to show data for. A Grafana data source integrates with one GCP Project. If you want to visualize data from multiple GCP Projects then you need to create one data source per GCP Project.
|
||||
To authenticate with the Google Cloud Monitoring API, you need to create a Google Cloud Platform (GCP) Service Account for the Project you want to show data for. A Grafana data source integrates with one GCP Project. If you want to visualize data from multiple GCP Projects then you need to create one data source per GCP Project.
|
||||
|
||||
#### Enable APIs
|
||||
|
||||
@ -50,31 +51,31 @@ The following APIs need to be enabled first:
|
||||
|
||||
Click on the links above and click the `Enable` button:
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v53/stackdriver_enable_api.png" class="docs-image--no-shadow" caption="Enable GCP APIs" >}}
|
||||
{{< docs-imagebox img="/img/docs/v71/cloudmonitoring_enable_api.png" class="docs-image--no-shadow" caption="Enable GCP APIs" >}}
|
||||
|
||||
#### Create a GCP Service Account for a Project
|
||||
|
||||
1. Navigate to the [APIs and Services Credentials page](https://console.cloud.google.com/apis/credentials).
|
||||
2. Click on the `Create credentials` dropdown/button and choose the `Service account key` option.
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v53/stackdriver_create_service_account_button.png" class="docs-image--no-shadow" caption="Create service account button" >}}
|
||||
{{< docs-imagebox img="/img/docs/v71/cloudmonitoring_create_service_account_button.png" class="docs-image--no-shadow" caption="Create service account button" >}}
|
||||
|
||||
3. On the `Create service account key` page, choose key type `JSON`. Then in the `Service Account` dropdown, choose the `New service account` option:
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v53/stackdriver_create_service_account_key.png" class="docs-image--no-shadow" caption="Create service account key" >}}
|
||||
{{< docs-imagebox img="/img/docs/v71/cloudmonitoring_create_service_account_key.png" class="docs-image--no-shadow" caption="Create service account key" >}}
|
||||
|
||||
4. Some new fields will appear. Fill in a name for the service account in the `Service account name` field and then choose the `Monitoring Viewer` role from the `Role` dropdown:
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v53/stackdriver_service_account_choose_role.png" class="docs-image--no-shadow" caption="Choose role" >}}
|
||||
{{< docs-imagebox img="/img/docs/v71/cloudmonitoring_service_account_choose_role.png" class="docs-image--no-shadow" caption="Choose role" >}}
|
||||
|
||||
5. Click the Create button. A JSON key file will be created and downloaded to your computer. Store this file in a secure place as it allows access to your Stackdriver data.
|
||||
5. Click the Create button. A JSON key file will be created and downloaded to your computer. Store this file in a secure place as it allows access to your Google Cloud Monitoring data.
|
||||
6. Upload it to Grafana on the data source Configuration page. You can either upload the file or paste in the contents of the file.
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v53/stackdriver_grafana_upload_key.png" class="docs-image--no-shadow" caption="Upload service key file to Grafana" >}}
|
||||
{{< docs-imagebox img="/img/docs/v71/cloudmonitoring_grafana_upload_key.png" class="docs-image--no-shadow" caption="Upload service key file to Grafana" >}}
|
||||
|
||||
7. The file contents will be encrypted and saved in the Grafana database. Don't forget to save after uploading the file!
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v53/stackdriver_grafana_key_uploaded.png" class="docs-image--no-shadow" caption="Service key file is uploaded to Grafana" >}}
|
||||
{{< docs-imagebox img="/img/docs/v71/cloudmonitoring_grafana_key_uploaded.png" class="docs-image--no-shadow" caption="Service key file is uploaded to Grafana" >}}
|
||||
|
||||
### Using GCE Default Service Account
|
||||
|
||||
@ -82,13 +83,13 @@ If Grafana is running on a Google Compute Engine (GCE) virtual machine, it is po
|
||||
|
||||
1. First of all, you need to create a Service Account that can be used by the GCE virtual machine. See detailed instructions on how to do that [here](https://cloud.google.com/compute/docs/access/create-enable-service-accounts-for-instances#createanewserviceaccount).
|
||||
2. Make sure the GCE virtual machine instance is being run as the service account that you just created. See instructions [here](https://cloud.google.com/compute/docs/access/create-enable-service-accounts-for-instances#using).
|
||||
3. Allow access to the `Stackdriver Monitoring API` scope. See instructions [here](changeserviceaccountandscopes).
|
||||
3. Allow access to the `Cloud Monitoring Monitoring API` scope.
|
||||
|
||||
Read more about creating and enabling service accounts for GCE VM instances [here](https://cloud.google.com/compute/docs/access/create-enable-service-accounts-for-instances).
|
||||
|
||||
## Using the Query Editor
|
||||
|
||||
The Stackdriver query editor allows you to build two types of queries - **Metric** and **Service Level Objective (SLO)**. Both types return time series data.
|
||||
The Google Cloud Monitoring query editor allows you to build two types of queries - **Metric** and **Service Level Objective (SLO)**. Both types return time series data.
|
||||
|
||||
### Metric Queries
|
||||
|
||||
@ -104,7 +105,7 @@ To create a metric query, follow these steps:
|
||||
4. Choose a metric from the **Metric** dropdown.
|
||||
5. Use the plus and minus icons in the filter and group by sections to add/remove filters or group by clauses. This step is optional.
|
||||
|
||||
Stackdriver metrics can be of different kinds (GAUGE, DELTA, CUMULATIVE) and these kinds have support for different aggregation options (reducers and aligners). The Grafana query editor shows the list of available aggregation methods for a selected metric and sets a default reducer and aligner when you select the metric. Units for the Y-axis are also automatically selected by the query editor.
|
||||
Google Cloud Monitoring metrics can be of different kinds (GAUGE, DELTA, CUMULATIVE) and these kinds have support for different aggregation options (reducers and aligners). The Grafana query editor shows the list of available aggregation methods for a selected metric and sets a default reducer and aligner when you select the metric. Units for the Y-axis are also automatically selected by the query editor.
|
||||
|
||||
#### Filter
|
||||
|
||||
@ -126,14 +127,14 @@ The `Aligner` field allows you to align multiple time series after the same grou
|
||||
|
||||
##### Alignment Period/Group by Time
|
||||
|
||||
The `Alignment Period` groups a metric by time if an aggregation is chosen. The default is to use the GCP Stackdriver default groupings (which allows you to compare graphs in Grafana with graphs in the Stackdriver UI).
|
||||
The option is called `Stackdriver auto` and the defaults are:
|
||||
The `Alignment Period` groups a metric by time if an aggregation is chosen. The default is to use the GCP Google Cloud Monitoring default groupings (which allows you to compare graphs in Grafana with graphs in the Google Cloud Monitoring UI).
|
||||
The option is called `cloud monitoring auto` and the defaults are:
|
||||
|
||||
- 1m for time ranges < 23 hours
|
||||
- 5m for time ranges >= 23 hours and < 6 days
|
||||
- 1h for time ranges >= 6 days
|
||||
|
||||
The other automatic option is `Grafana auto`. This will automatically set the group by time depending on the time range chosen and the width of the graph panel. Read more about the details [here](http://docs.grafana.org/variables/templates-and-variables/#the-interval-variable).
|
||||
The other automatic option is `grafana auto`. This will automatically set the group by time depending on the time range chosen and the width of the graph panel. Read more about the details [here](http://docs.grafana.org/variables/templates-and-variables/#the-interval-variable).
|
||||
|
||||
It is also possible to choose fixed time intervals to group by, like `1h` or `1d`.
|
||||
|
||||
@ -190,7 +191,7 @@ Example Result: `gce_instance - compute.googleapis.com/instance/cpu/usage_time`
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v70/slo-query-builder.png" max-width= "400px" class="docs-image--right" >}}
|
||||
|
||||
The SLO query builder in the Stackdriver data source allows you to display SLO data in time series format. To get an understanding of the basic concepts in service monitoring, please refer to Google Stackdriver's [official docs](https://cloud.google.com/monitoring/service-monitoring).
|
||||
The SLO query builder in the Google Cloud Monitoring data source allows you to display SLO data in time series format. To get an understanding of the basic concepts in service monitoring, please refer to Google Cloud Monitoring's [official docs](https://cloud.google.com/monitoring/service-monitoring).
|
||||
|
||||
#### How to create an SLO query
|
||||
|
||||
@ -236,20 +237,20 @@ types of template variables.
|
||||
|
||||
### Query Variable
|
||||
|
||||
Variable of the type _Query_ allows you to query Stackdriver for various types of data. The Stackdriver data source plugin provides the following `Query Types`.
|
||||
Variable of the type _Query_ allows you to query Google Cloud Monitoring for various types of data. The Google Cloud Monitoring data source plugin provides the following `Query Types`.
|
||||
|
||||
| Name | Description |
|
||||
| -------------------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| _Metric Types_ | Returns a list of metric type names that are available for the specified service. |
|
||||
| _Labels Keys_ | Returns a list of keys for `metric label` and `resource label` in the specified metric. |
|
||||
| _Labels Values_ | Returns a list of values for the label in the specified metric. |
|
||||
| _Resource Types_ | Returns a list of resource types for the specified metric. |
|
||||
| _Aggregations_ | Returns a list of aggregations (cross series reducers) for the specified metric. |
|
||||
| _Aligners_ | Returns a list of aligners (per series aligners) for the specified metric. |
|
||||
| _Alignment periods_ | Returns a list of all alignment periods that are available in Stackdriver query editor in Grafana |
|
||||
| _Selectors_ | Returns a list of selectors that can be used in SLO (Service Level Objectives) queries |
|
||||
| _SLO Services_ | Returns a list of Service Monitoring services that can be used in SLO queries |
|
||||
| _Service Level Objectives (SLO)_ | Returns a list of SLO's for the specified SLO service |
|
||||
| Name | Description |
|
||||
| -------------------------------- | ------------------------------------------------------------------------------------------------------------- |
|
||||
| _Metric Types_ | Returns a list of metric type names that are available for the specified service. |
|
||||
| _Labels Keys_ | Returns a list of keys for `metric label` and `resource label` in the specified metric. |
|
||||
| _Labels Values_ | Returns a list of values for the label in the specified metric. |
|
||||
| _Resource Types_ | Returns a list of resource types for the specified metric. |
|
||||
| _Aggregations_ | Returns a list of aggregations (cross series reducers) for the specified metric. |
|
||||
| _Aligners_ | Returns a list of aligners (per series aligners) for the specified metric. |
|
||||
| _Alignment periods_ | Returns a list of all alignment periods that are available in Google Cloud Monitoring query editor in Grafana |
|
||||
| _Selectors_ | Returns a list of selectors that can be used in SLO (Service Level Objectives) queries |
|
||||
| _SLO Services_ | Returns a list of Service Monitoring services that can be used in SLO queries |
|
||||
| _Service Level Objectives (SLO)_ | Returns a list of SLO's for the specified SLO service |
|
||||
|
||||
### Using variables in queries
|
||||
|
||||
@ -262,10 +263,10 @@ Why two ways? The first syntax is easier to read and write but does not allow yo
|
||||
|
||||
## Annotations
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v53/stackdriver_annotations_query_editor.png" max-width= "400px" class="docs-image--right" >}}
|
||||
{{< docs-imagebox img="/img/docs/v71/cloudmonitoring_annotations_query_editor.png" max-width= "400px" class="docs-image--right" >}}
|
||||
|
||||
[Annotations]({{< relref "../../reference/annotations.md" >}}) allow you to overlay rich event information on top of graphs. You add annotation
|
||||
queries via the Dashboard menu / Annotations view. Annotation rendering is expensive so it is important to limit the number of rows returned. There is no support for showing Stackdriver annotations and events yet but it works well with [custom metrics](https://cloud.google.com/monitoring/custom-metrics/) in Stackdriver.
|
||||
queries via the Dashboard menu / Annotations view. Annotation rendering is expensive so it is important to limit the number of rows returned. There is no support for showing Google Cloud Monitoring annotations and events yet but it works well with [custom metrics](https://cloud.google.com/monitoring/custom-metrics/) in Google Cloud Monitoring.
|
||||
|
||||
With the query editor for annotations, you can select a metric and filters. The `Title` and `Text` fields support templating and can use data returned from the query. For example, the Title field could have the following text:
|
||||
|
||||
@ -294,7 +295,7 @@ Here is a provisioning example using the JWT (Service Account key file) authenti
|
||||
apiVersion: 1
|
||||
|
||||
datasources:
|
||||
- name: Stackdriver
|
||||
- name: Google Cloud Monitoring
|
||||
type: stackdriver
|
||||
access: proxy
|
||||
jsonData:
|
||||
@ -317,7 +318,7 @@ Here is a provisioning example using GCE Default Service Account authentication.
|
||||
apiVersion: 1
|
||||
|
||||
datasources:
|
||||
- name: Stackdriver
|
||||
- name: Google Cloud Monitoring
|
||||
type: stackdriver
|
||||
access: proxy
|
||||
jsonData:
|
@ -181,7 +181,7 @@ It was released as a beta feature in Grafana 6.7. The feedback has been really p
|
||||
|
||||
## Stackdriver data source supports Service Monitoring
|
||||
|
||||
[Service monitoring](https://cloud.google.com/service-monitoring) in Google Cloud Platform (GCP) enables you to monitor based on Service Level Objectives (SLOs) for your GCP services. The new SLO query builder in the Stackdriver data source allows you to display SLO data in Grafana. Read more about it in the [Stackdriver data source documentation]({{< relref "../features/datasources/stackdriver/#slo-service-level-objective-queries" >}}).
|
||||
[Service monitoring](https://cloud.google.com/service-monitoring) in Google Cloud Platform (GCP) enables you to monitor based on Service Level Objectives (SLOs) for your GCP services. The new SLO query builder in the Stackdriver data source allows you to display SLO data in Grafana. Read more about it in the [Stackdriver data source documentation]({{< relref "../features/datasources/cloudmonitoring/#slo-service-level-objective-queries" >}}).
|
||||
|
||||
## Time zone support
|
||||
|
||||
|
@ -109,8 +109,8 @@
|
||||
name: Azure Monitor
|
||||
- link: /features/datasources/elasticsearch/
|
||||
name: Elasticsearch
|
||||
- link: /features/datasources/stackdriver/
|
||||
name: Google Stackdriver
|
||||
- link: /features/datasources/cloudmonitoring/
|
||||
name: Google Cloud Monitoring
|
||||
- link: /features/datasources/graphite/
|
||||
name: Graphite
|
||||
- link: /features/datasources/influxdb/
|
||||
|
@ -43,7 +43,7 @@ export interface QueryResultMeta {
|
||||
* Legacy data source specific, should be moved to custom
|
||||
* */
|
||||
gmdMeta?: any[]; // used by cloudwatch
|
||||
alignmentPeriod?: string; // used by stackdriver
|
||||
alignmentPeriod?: string; // used by cloud monitoring
|
||||
searchWords?: string[]; // used by log models and loki
|
||||
limit?: number; // used by log models and loki
|
||||
json?: boolean; // used to keep track of old json doc values
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
_ "github.com/grafana/grafana/pkg/services/alerting/notifiers"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
_ "github.com/grafana/grafana/pkg/tsdb/azuremonitor"
|
||||
_ "github.com/grafana/grafana/pkg/tsdb/cloudmonitoring"
|
||||
_ "github.com/grafana/grafana/pkg/tsdb/cloudwatch"
|
||||
_ "github.com/grafana/grafana/pkg/tsdb/elasticsearch"
|
||||
_ "github.com/grafana/grafana/pkg/tsdb/graphite"
|
||||
@ -28,7 +29,6 @@ import (
|
||||
_ "github.com/grafana/grafana/pkg/tsdb/opentsdb"
|
||||
_ "github.com/grafana/grafana/pkg/tsdb/postgres"
|
||||
_ "github.com/grafana/grafana/pkg/tsdb/prometheus"
|
||||
_ "github.com/grafana/grafana/pkg/tsdb/stackdriver"
|
||||
_ "github.com/grafana/grafana/pkg/tsdb/testdatasource"
|
||||
)
|
||||
|
||||
|
@ -22,9 +22,11 @@ const (
|
||||
DS_MSSQL = "mssql"
|
||||
DS_ACCESS_DIRECT = "direct"
|
||||
DS_ACCESS_PROXY = "proxy"
|
||||
DS_STACKDRIVER = "stackdriver"
|
||||
DS_AZURE_MONITOR = "grafana-azure-monitor-datasource"
|
||||
DS_LOKI = "loki"
|
||||
// Stackdriver was renamed Google Cloud monitoring 2020-05 but we keep
|
||||
// "stackdriver" to avoid breaking changes in reporting.
|
||||
DS_CLOUD_MONITORING = "stackdriver"
|
||||
DS_AZURE_MONITOR = "grafana-azure-monitor-datasource"
|
||||
DS_LOKI = "loki"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -97,7 +99,7 @@ var knownDatasourcePlugins = map[string]bool{
|
||||
DS_POSTGRES: true,
|
||||
DS_MYSQL: true,
|
||||
DS_MSSQL: true,
|
||||
DS_STACKDRIVER: true,
|
||||
DS_CLOUD_MONITORING: true,
|
||||
DS_AZURE_MONITOR: true,
|
||||
DS_LOKI: true,
|
||||
"opennms": true,
|
||||
|
@ -60,8 +60,12 @@ func (fp *FrontendPluginBase) handleModuleDefaults() {
|
||||
}
|
||||
|
||||
fp.IsCorePlugin = true
|
||||
fp.Module = path.Join("app/plugins", fp.Type, fp.Id, "module")
|
||||
fp.BaseUrl = path.Join("public/app/plugins", fp.Type, fp.Id)
|
||||
// Previously there was an assumption that the plugin directory
|
||||
// should be public/app/plugins/<plugin type>/<plugin id>
|
||||
// However this can be an issue if the plugin directory should be renamed to something else
|
||||
currentDir := path.Base(fp.PluginDir)
|
||||
fp.Module = path.Join("app/plugins", fp.Type, currentDir, "module")
|
||||
fp.BaseUrl = path.Join("public/app/plugins", fp.Type, currentDir)
|
||||
}
|
||||
|
||||
func isExternalPlugin(pluginDir string) bool {
|
||||
|
@ -1,4 +1,4 @@
|
||||
package stackdriver
|
||||
package cloudmonitoring
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -9,7 +9,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/tsdb"
|
||||
)
|
||||
|
||||
func (e *StackdriverExecutor) executeAnnotationQuery(ctx context.Context, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
|
||||
func (e *CloudMonitoringExecutor) executeAnnotationQuery(ctx context.Context, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
|
||||
result := &tsdb.Response{
|
||||
Results: make(map[string]*tsdb.QueryResult),
|
||||
}
|
||||
@ -34,7 +34,7 @@ func (e *StackdriverExecutor) executeAnnotationQuery(ctx context.Context, tsdbQu
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (e *StackdriverExecutor) parseToAnnotations(queryRes *tsdb.QueryResult, data stackdriverResponse, query *stackdriverQuery, title string, text string, tags string) error {
|
||||
func (e *CloudMonitoringExecutor) parseToAnnotations(queryRes *tsdb.QueryResult, data cloudMonitoringResponse, query *cloudMonitoringQuery, title string, text string, tags string) error {
|
||||
annotations := make([]map[string]string, 0)
|
||||
|
||||
for _, series := range data.TimeSeries {
|
@ -1,4 +1,4 @@
|
||||
package stackdriver
|
||||
package cloudmonitoring
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@ -9,16 +9,16 @@ import (
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestStackdriverAnnotationQuery(t *testing.T) {
|
||||
Convey("Stackdriver Annotation Query Executor", t, func() {
|
||||
executor := &StackdriverExecutor{}
|
||||
Convey("When parsing the stackdriver api response", func() {
|
||||
func TestCloudMonitoringAnnotationQuery(t *testing.T) {
|
||||
Convey("CloudMonitoring Annotation Query Executor", t, func() {
|
||||
executor := &CloudMonitoringExecutor{}
|
||||
Convey("When parsing the cloud monitoring api response", func() {
|
||||
data, err := loadTestFile("./test-data/2-series-response-no-agg.json")
|
||||
So(err, ShouldBeNil)
|
||||
So(len(data.TimeSeries), ShouldEqual, 3)
|
||||
|
||||
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "annotationQuery"}
|
||||
query := &stackdriverQuery{}
|
||||
query := &cloudMonitoringQuery{}
|
||||
err = executor.parseToAnnotations(res, data, query, "atitle {{metric.label.instance_name}} {{metric.value}}", "atext {{resource.label.zone}}", "atag")
|
||||
So(err, ShouldBeNil)
|
||||
|
@ -1,4 +1,4 @@
|
||||
package stackdriver
|
||||
package cloudmonitoring
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -48,34 +48,34 @@ const (
|
||||
sloQueryType string = "slo"
|
||||
)
|
||||
|
||||
// StackdriverExecutor executes queries for the Stackdriver datasource
|
||||
type StackdriverExecutor struct {
|
||||
// CloudMonitoringExecutor executes queries for the CloudMonitoring datasource
|
||||
type CloudMonitoringExecutor struct {
|
||||
httpClient *http.Client
|
||||
dsInfo *models.DataSource
|
||||
}
|
||||
|
||||
// NewStackdriverExecutor initializes a http client
|
||||
func NewStackdriverExecutor(dsInfo *models.DataSource) (tsdb.TsdbQueryEndpoint, error) {
|
||||
// NewCloudMonitoringExecutor initializes a http client
|
||||
func NewCloudMonitoringExecutor(dsInfo *models.DataSource) (tsdb.TsdbQueryEndpoint, error) {
|
||||
httpClient, err := dsInfo.GetHttpClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &StackdriverExecutor{
|
||||
return &CloudMonitoringExecutor{
|
||||
httpClient: httpClient,
|
||||
dsInfo: dsInfo,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
slog = log.New("tsdb.stackdriver")
|
||||
tsdb.RegisterTsdbQueryEndpoint("stackdriver", NewStackdriverExecutor)
|
||||
slog = log.New("tsdb.cloudMonitoring")
|
||||
tsdb.RegisterTsdbQueryEndpoint("stackdriver", NewCloudMonitoringExecutor)
|
||||
}
|
||||
|
||||
// Query takes in the frontend queries, parses them into the Stackdriver query format
|
||||
// executes the queries against the Stackdriver API and parses the response into
|
||||
// Query takes in the frontend queries, parses them into the CloudMonitoring query format
|
||||
// executes the queries against the CloudMonitoring API and parses the response into
|
||||
// the time series or table format
|
||||
func (e *StackdriverExecutor) Query(ctx context.Context, dsInfo *models.DataSource, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
|
||||
func (e *CloudMonitoringExecutor) Query(ctx context.Context, dsInfo *models.DataSource, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
|
||||
var result *tsdb.Response
|
||||
var err error
|
||||
queryType := tsdbQuery.Queries[0].Model.Get("type").MustString("")
|
||||
@ -94,7 +94,7 @@ func (e *StackdriverExecutor) Query(ctx context.Context, dsInfo *models.DataSour
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (e *StackdriverExecutor) getGCEDefaultProject(ctx context.Context, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
|
||||
func (e *CloudMonitoringExecutor) getGCEDefaultProject(ctx context.Context, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
|
||||
result := &tsdb.Response{
|
||||
Results: make(map[string]*tsdb.QueryResult),
|
||||
}
|
||||
@ -112,7 +112,7 @@ func (e *StackdriverExecutor) getGCEDefaultProject(ctx context.Context, tsdbQuer
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (e *StackdriverExecutor) executeTimeSeriesQuery(ctx context.Context, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
|
||||
func (e *CloudMonitoringExecutor) executeTimeSeriesQuery(ctx context.Context, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
|
||||
result := &tsdb.Response{
|
||||
Results: make(map[string]*tsdb.QueryResult),
|
||||
}
|
||||
@ -137,8 +137,8 @@ func (e *StackdriverExecutor) executeTimeSeriesQuery(ctx context.Context, tsdbQu
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (e *StackdriverExecutor) buildQueries(tsdbQuery *tsdb.TsdbQuery) ([]*stackdriverQuery, error) {
|
||||
stackdriverQueries := []*stackdriverQuery{}
|
||||
func (e *CloudMonitoringExecutor) buildQueries(tsdbQuery *tsdb.TsdbQuery) ([]*cloudMonitoringQuery, error) {
|
||||
cloudMonitoringQueries := []*cloudMonitoringQuery{}
|
||||
|
||||
startTime, err := tsdbQuery.TimeRange.ParseFrom()
|
||||
if err != nil {
|
||||
@ -157,14 +157,14 @@ func (e *StackdriverExecutor) buildQueries(tsdbQuery *tsdb.TsdbQuery) ([]*stackd
|
||||
q := grafanaQuery{}
|
||||
model, _ := query.Model.MarshalJSON()
|
||||
if err := json.Unmarshal(model, &q); err != nil {
|
||||
return nil, fmt.Errorf("could not unmarshal StackdriverQuery json: %w", err)
|
||||
return nil, fmt.Errorf("could not unmarshal CloudMonitoringQuery json: %w", err)
|
||||
}
|
||||
var target string
|
||||
params := url.Values{}
|
||||
params.Add("interval.startTime", startTime.UTC().Format(time.RFC3339))
|
||||
params.Add("interval.endTime", endTime.UTC().Format(time.RFC3339))
|
||||
|
||||
sq := &stackdriverQuery{
|
||||
sq := &cloudMonitoringQuery{
|
||||
RefID: query.RefId,
|
||||
GroupBys: []string{},
|
||||
}
|
||||
@ -194,13 +194,13 @@ func (e *StackdriverExecutor) buildQueries(tsdbQuery *tsdb.TsdbQuery) ([]*stackd
|
||||
sq.Params = params
|
||||
|
||||
if setting.Env == setting.DEV {
|
||||
slog.Debug("Stackdriver request", "params", params)
|
||||
slog.Debug("CloudMonitoring request", "params", params)
|
||||
}
|
||||
|
||||
stackdriverQueries = append(stackdriverQueries, sq)
|
||||
cloudMonitoringQueries = append(cloudMonitoringQueries, sq)
|
||||
}
|
||||
|
||||
return stackdriverQueries, nil
|
||||
return cloudMonitoringQueries, nil
|
||||
}
|
||||
|
||||
func migrateLegacyQueryModel(query *tsdb.Query) {
|
||||
@ -306,7 +306,7 @@ func calculateAlignmentPeriod(alignmentPeriod string, intervalMs int64, duration
|
||||
alignmentPeriod = "+" + strconv.Itoa(alignmentPeriodValue) + "s"
|
||||
}
|
||||
|
||||
if alignmentPeriod == "stackdriver-auto" {
|
||||
if alignmentPeriod == "cloud-monitoring-auto" || alignmentPeriod == "stackdriver-auto" { // legacy
|
||||
alignmentPeriodValue := int(math.Max(float64(durationSeconds), 60.0))
|
||||
if alignmentPeriodValue < 60*60*23 {
|
||||
alignmentPeriod = "+60s"
|
||||
@ -320,23 +320,23 @@ func calculateAlignmentPeriod(alignmentPeriod string, intervalMs int64, duration
|
||||
return alignmentPeriod
|
||||
}
|
||||
|
||||
func (e *StackdriverExecutor) executeQuery(ctx context.Context, query *stackdriverQuery, tsdbQuery *tsdb.TsdbQuery) (*tsdb.QueryResult, stackdriverResponse, error) {
|
||||
func (e *CloudMonitoringExecutor) executeQuery(ctx context.Context, query *cloudMonitoringQuery, tsdbQuery *tsdb.TsdbQuery) (*tsdb.QueryResult, cloudMonitoringResponse, error) {
|
||||
queryResult := &tsdb.QueryResult{Meta: simplejson.New(), RefId: query.RefID}
|
||||
projectName := query.ProjectName
|
||||
if projectName == "" {
|
||||
defaultProject, err := e.getDefaultProject(ctx)
|
||||
if err != nil {
|
||||
queryResult.Error = err
|
||||
return queryResult, stackdriverResponse{}, nil
|
||||
return queryResult, cloudMonitoringResponse{}, nil
|
||||
}
|
||||
projectName = defaultProject
|
||||
slog.Info("No project name set on query, using project name from datasource", "projectName", projectName)
|
||||
}
|
||||
|
||||
req, err := e.createRequest(ctx, e.dsInfo, query, fmt.Sprintf("stackdriver%s", "v3/projects/"+projectName+"/timeSeries"))
|
||||
req, err := e.createRequest(ctx, e.dsInfo, query, fmt.Sprintf("cloudmonitoring%s", "v3/projects/"+projectName+"/timeSeries"))
|
||||
if err != nil {
|
||||
queryResult.Error = err
|
||||
return queryResult, stackdriverResponse{}, nil
|
||||
return queryResult, cloudMonitoringResponse{}, nil
|
||||
}
|
||||
|
||||
req.URL.RawQuery = query.Params.Encode()
|
||||
@ -350,7 +350,7 @@ func (e *StackdriverExecutor) executeQuery(ctx context.Context, query *stackdriv
|
||||
}
|
||||
}
|
||||
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "stackdriver query")
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "cloudMonitoring query")
|
||||
span.SetTag("target", query.Target)
|
||||
span.SetTag("from", tsdbQuery.TimeRange.From)
|
||||
span.SetTag("until", tsdbQuery.TimeRange.To)
|
||||
@ -364,47 +364,47 @@ func (e *StackdriverExecutor) executeQuery(ctx context.Context, query *stackdriv
|
||||
opentracing.HTTPHeaders,
|
||||
opentracing.HTTPHeadersCarrier(req.Header)); err != nil {
|
||||
queryResult.Error = err
|
||||
return queryResult, stackdriverResponse{}, nil
|
||||
return queryResult, cloudMonitoringResponse{}, nil
|
||||
}
|
||||
|
||||
res, err := ctxhttp.Do(ctx, e.httpClient, req)
|
||||
if err != nil {
|
||||
queryResult.Error = err
|
||||
return queryResult, stackdriverResponse{}, nil
|
||||
return queryResult, cloudMonitoringResponse{}, nil
|
||||
}
|
||||
|
||||
data, err := e.unmarshalResponse(res)
|
||||
if err != nil {
|
||||
queryResult.Error = err
|
||||
return queryResult, stackdriverResponse{}, nil
|
||||
return queryResult, cloudMonitoringResponse{}, nil
|
||||
}
|
||||
|
||||
return queryResult, data, nil
|
||||
}
|
||||
|
||||
func (e *StackdriverExecutor) unmarshalResponse(res *http.Response) (stackdriverResponse, error) {
|
||||
func (e *CloudMonitoringExecutor) unmarshalResponse(res *http.Response) (cloudMonitoringResponse, error) {
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
defer res.Body.Close()
|
||||
if err != nil {
|
||||
return stackdriverResponse{}, err
|
||||
return cloudMonitoringResponse{}, err
|
||||
}
|
||||
|
||||
if res.StatusCode/100 != 2 {
|
||||
slog.Error("Request failed", "status", res.Status, "body", string(body))
|
||||
return stackdriverResponse{}, fmt.Errorf(string(body))
|
||||
return cloudMonitoringResponse{}, fmt.Errorf(string(body))
|
||||
}
|
||||
|
||||
var data stackdriverResponse
|
||||
var data cloudMonitoringResponse
|
||||
err = json.Unmarshal(body, &data)
|
||||
if err != nil {
|
||||
slog.Error("Failed to unmarshal Stackdriver response", "error", err, "status", res.Status, "body", string(body))
|
||||
return stackdriverResponse{}, err
|
||||
slog.Error("Failed to unmarshal CloudMonitoring response", "error", err, "status", res.Status, "body", string(body))
|
||||
return cloudMonitoringResponse{}, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (e *StackdriverExecutor) parseResponse(queryRes *tsdb.QueryResult, data stackdriverResponse, query *stackdriverQuery) error {
|
||||
func (e *CloudMonitoringExecutor) parseResponse(queryRes *tsdb.QueryResult, data cloudMonitoringResponse, query *cloudMonitoringQuery) error {
|
||||
labels := make(map[string]map[string]bool)
|
||||
|
||||
for _, series := range data.TimeSeries {
|
||||
@ -570,7 +570,7 @@ func containsLabel(labels []string, newLabel string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func formatLegendKeys(metricType string, defaultMetricName string, labels map[string]string, additionalLabels map[string]string, query *stackdriverQuery) string {
|
||||
func formatLegendKeys(metricType string, defaultMetricName string, labels map[string]string, additionalLabels map[string]string, query *cloudMonitoringQuery) string {
|
||||
if query.AliasBy == "" {
|
||||
return defaultMetricName
|
||||
}
|
||||
@ -639,7 +639,7 @@ func replaceWithMetricPart(metaPartName string, metricType string) []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
func calcBucketBound(bucketOptions stackdriverBucketOptions, n int) string {
|
||||
func calcBucketBound(bucketOptions cloudMonitoringBucketOptions, n int) string {
|
||||
bucketBound := "0"
|
||||
if n == 0 {
|
||||
return bucketBound
|
||||
@ -655,7 +655,7 @@ func calcBucketBound(bucketOptions stackdriverBucketOptions, n int) string {
|
||||
return bucketBound
|
||||
}
|
||||
|
||||
func (e *StackdriverExecutor) createRequest(ctx context.Context, dsInfo *models.DataSource, query *stackdriverQuery, proxyPass string) (*http.Request, error) {
|
||||
func (e *CloudMonitoringExecutor) createRequest(ctx context.Context, dsInfo *models.DataSource, query *cloudMonitoringQuery, proxyPass string) (*http.Request, error) {
|
||||
u, err := url.Parse(dsInfo.Url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -674,23 +674,23 @@ func (e *StackdriverExecutor) createRequest(ctx context.Context, dsInfo *models.
|
||||
// find plugin
|
||||
plugin, ok := plugins.DataSources[dsInfo.Type]
|
||||
if !ok {
|
||||
return nil, errors.New("Unable to find datasource plugin Stackdriver")
|
||||
return nil, errors.New("Unable to find datasource plugin CloudMonitoring")
|
||||
}
|
||||
|
||||
var stackdriverRoute *plugins.AppPluginRoute
|
||||
var cloudMonitoringRoute *plugins.AppPluginRoute
|
||||
for _, route := range plugin.Routes {
|
||||
if route.Path == "stackdriver" {
|
||||
stackdriverRoute = route
|
||||
if route.Path == "cloudmonitoring" {
|
||||
cloudMonitoringRoute = route
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
pluginproxy.ApplyRoute(ctx, req, proxyPass, stackdriverRoute, dsInfo)
|
||||
pluginproxy.ApplyRoute(ctx, req, proxyPass, cloudMonitoringRoute, dsInfo)
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func (e *StackdriverExecutor) getDefaultProject(ctx context.Context) (string, error) {
|
||||
func (e *CloudMonitoringExecutor) getDefaultProject(ctx context.Context) (string, error) {
|
||||
authenticationType := e.dsInfo.JsonData.Get("authenticationType").MustString(jwtAuthentication)
|
||||
if authenticationType == gceAuthentication {
|
||||
defaultCredentials, err := google.FindDefaultCredentials(ctx, "https://www.googleapis.com/auth/monitoring.read")
|
@ -1,4 +1,4 @@
|
||||
package stackdriver
|
||||
package cloudmonitoring
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@ -15,11 +15,11 @@ import (
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestStackdriver(t *testing.T) {
|
||||
Convey("Stackdriver", t, func() {
|
||||
executor := &StackdriverExecutor{}
|
||||
func TestCloudMonitoring(t *testing.T) {
|
||||
Convey("Google Cloud Monitoring", t, func() {
|
||||
executor := &CloudMonitoringExecutor{}
|
||||
|
||||
Convey("Parse migrated queries from frontend and build Stackdriver API queries", func() {
|
||||
Convey("Parse migrated queries from frontend and build Google Cloud Monitoring API queries", func() {
|
||||
fromStart := time.Date(2018, 3, 15, 13, 0, 0, 0, time.UTC).In(time.Local)
|
||||
tsdbQuery := &tsdb.TsdbQuery{
|
||||
TimeRange: &tsdb.TimeRange{
|
||||
@ -92,7 +92,61 @@ func TestStackdriver(t *testing.T) {
|
||||
})
|
||||
})
|
||||
|
||||
Convey("and alignmentPeriod is set to stackdriver-auto", func() {
|
||||
Convey("and alignmentPeriod is set to cloud-monitoring-auto", func() { // legacy
|
||||
Convey("and range is two hours", func() {
|
||||
tsdbQuery.TimeRange.From = "1538033322461"
|
||||
tsdbQuery.TimeRange.To = "1538040522461"
|
||||
tsdbQuery.Queries[0].Model = simplejson.NewFromAny(map[string]interface{}{
|
||||
"target": "target",
|
||||
"alignmentPeriod": "cloud-monitoring-auto",
|
||||
})
|
||||
|
||||
queries, err := executor.buildQueries(tsdbQuery)
|
||||
So(err, ShouldBeNil)
|
||||
So(queries[0].Params["aggregation.alignmentPeriod"][0], ShouldEqual, `+60s`)
|
||||
})
|
||||
|
||||
Convey("and range is 22 hours", func() {
|
||||
tsdbQuery.TimeRange.From = "1538034524922"
|
||||
tsdbQuery.TimeRange.To = "1538113724922"
|
||||
tsdbQuery.Queries[0].Model = simplejson.NewFromAny(map[string]interface{}{
|
||||
"target": "target",
|
||||
"alignmentPeriod": "cloud-monitoring-auto",
|
||||
})
|
||||
|
||||
queries, err := executor.buildQueries(tsdbQuery)
|
||||
So(err, ShouldBeNil)
|
||||
So(queries[0].Params["aggregation.alignmentPeriod"][0], ShouldEqual, `+60s`)
|
||||
})
|
||||
|
||||
Convey("and range is 23 hours", func() {
|
||||
tsdbQuery.TimeRange.From = "1538034567985"
|
||||
tsdbQuery.TimeRange.To = "1538117367985"
|
||||
tsdbQuery.Queries[0].Model = simplejson.NewFromAny(map[string]interface{}{
|
||||
"target": "target",
|
||||
"alignmentPeriod": "cloud-monitoring-auto",
|
||||
})
|
||||
|
||||
queries, err := executor.buildQueries(tsdbQuery)
|
||||
So(err, ShouldBeNil)
|
||||
So(queries[0].Params["aggregation.alignmentPeriod"][0], ShouldEqual, `+300s`)
|
||||
})
|
||||
|
||||
Convey("and range is 7 days", func() {
|
||||
tsdbQuery.TimeRange.From = "1538036324073"
|
||||
tsdbQuery.TimeRange.To = "1538641124073"
|
||||
tsdbQuery.Queries[0].Model = simplejson.NewFromAny(map[string]interface{}{
|
||||
"target": "target",
|
||||
"alignmentPeriod": "cloud-monitoring-auto",
|
||||
})
|
||||
|
||||
queries, err := executor.buildQueries(tsdbQuery)
|
||||
So(err, ShouldBeNil)
|
||||
So(queries[0].Params["aggregation.alignmentPeriod"][0], ShouldEqual, `+3600s`)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("and alignmentPeriod is set to stackdriver-auto", func() { // legacy
|
||||
Convey("and range is two hours", func() {
|
||||
tsdbQuery.TimeRange.From = "1538033322461"
|
||||
tsdbQuery.TimeRange.To = "1538040522461"
|
||||
@ -208,7 +262,7 @@ func TestStackdriver(t *testing.T) {
|
||||
|
||||
})
|
||||
|
||||
Convey("Parse queries from frontend and build Stackdriver API queries", func() {
|
||||
Convey("Parse queries from frontend and build Google Cloud Monitoring API queries", func() {
|
||||
fromStart := time.Date(2018, 3, 15, 13, 0, 0, 0, time.UTC).In(time.Local)
|
||||
tsdbQuery := &tsdb.TsdbQuery{
|
||||
TimeRange: &tsdb.TimeRange{
|
||||
@ -301,14 +355,14 @@ func TestStackdriver(t *testing.T) {
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Parse stackdriver response in the time series format", func() {
|
||||
Convey("Parse cloud monitoring response in the time series format", func() {
|
||||
Convey("when data from query aggregated to one time series", func() {
|
||||
data, err := loadTestFile("./test-data/1-series-response-agg-one-metric.json")
|
||||
So(err, ShouldBeNil)
|
||||
So(len(data.TimeSeries), ShouldEqual, 1)
|
||||
|
||||
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
|
||||
query := &stackdriverQuery{}
|
||||
query := &cloudMonitoringQuery{}
|
||||
err = executor.parseResponse(res, data, query)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
@ -334,7 +388,7 @@ func TestStackdriver(t *testing.T) {
|
||||
So(len(data.TimeSeries), ShouldEqual, 3)
|
||||
|
||||
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
|
||||
query := &stackdriverQuery{}
|
||||
query := &cloudMonitoringQuery{}
|
||||
err = executor.parseResponse(res, data, query)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
@ -376,7 +430,7 @@ func TestStackdriver(t *testing.T) {
|
||||
So(len(data.TimeSeries), ShouldEqual, 3)
|
||||
|
||||
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
|
||||
query := &stackdriverQuery{GroupBys: []string{"metric.label.instance_name", "resource.label.zone"}}
|
||||
query := &cloudMonitoringQuery{GroupBys: []string{"metric.label.instance_name", "resource.label.zone"}}
|
||||
err = executor.parseResponse(res, data, query)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
@ -397,7 +451,7 @@ func TestStackdriver(t *testing.T) {
|
||||
|
||||
Convey("and the alias pattern is for metric type, a metric label and a resource label", func() {
|
||||
|
||||
query := &stackdriverQuery{AliasBy: "{{metric.type}} - {{metric.label.instance_name}} - {{resource.label.zone}}", GroupBys: []string{"metric.label.instance_name", "resource.label.zone"}}
|
||||
query := &cloudMonitoringQuery{AliasBy: "{{metric.type}} - {{metric.label.instance_name}} - {{resource.label.zone}}", GroupBys: []string{"metric.label.instance_name", "resource.label.zone"}}
|
||||
err = executor.parseResponse(res, data, query)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
@ -411,7 +465,7 @@ func TestStackdriver(t *testing.T) {
|
||||
|
||||
Convey("and the alias pattern is for metric name", func() {
|
||||
|
||||
query := &stackdriverQuery{AliasBy: "metric {{metric.name}} service {{metric.service}}", GroupBys: []string{"metric.label.instance_name", "resource.label.zone"}}
|
||||
query := &cloudMonitoringQuery{AliasBy: "metric {{metric.name}} service {{metric.service}}", GroupBys: []string{"metric.label.instance_name", "resource.label.zone"}}
|
||||
err = executor.parseResponse(res, data, query)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
@ -430,7 +484,7 @@ func TestStackdriver(t *testing.T) {
|
||||
So(len(data.TimeSeries), ShouldEqual, 1)
|
||||
|
||||
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
|
||||
query := &stackdriverQuery{AliasBy: "{{bucket}}"}
|
||||
query := &cloudMonitoringQuery{AliasBy: "{{bucket}}"}
|
||||
err = executor.parseResponse(res, data, query)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
@ -477,7 +531,7 @@ func TestStackdriver(t *testing.T) {
|
||||
So(len(data.TimeSeries), ShouldEqual, 1)
|
||||
|
||||
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
|
||||
query := &stackdriverQuery{AliasBy: "{{bucket}}"}
|
||||
query := &cloudMonitoringQuery{AliasBy: "{{bucket}}"}
|
||||
err = executor.parseResponse(res, data, query)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
@ -517,7 +571,7 @@ func TestStackdriver(t *testing.T) {
|
||||
So(len(data.TimeSeries), ShouldEqual, 3)
|
||||
|
||||
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
|
||||
query := &stackdriverQuery{AliasBy: "{{bucket}}"}
|
||||
query := &cloudMonitoringQuery{AliasBy: "{{bucket}}"}
|
||||
err = executor.parseResponse(res, data, query)
|
||||
labels := res.Meta.Get("labels").Interface().(map[string][]string)
|
||||
So(err, ShouldBeNil)
|
||||
@ -556,7 +610,7 @@ func TestStackdriver(t *testing.T) {
|
||||
|
||||
Convey("and systemlabel contains key with array of string", func() {
|
||||
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
|
||||
query := &stackdriverQuery{AliasBy: "{{metadata.system_labels.test}}"}
|
||||
query := &cloudMonitoringQuery{AliasBy: "{{metadata.system_labels.test}}"}
|
||||
err = executor.parseResponse(res, data, query)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(res.Series), ShouldEqual, 3)
|
||||
@ -568,7 +622,7 @@ func TestStackdriver(t *testing.T) {
|
||||
|
||||
Convey("and systemlabel contains key with array of string2", func() {
|
||||
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
|
||||
query := &stackdriverQuery{AliasBy: "{{metadata.system_labels.test2}}"}
|
||||
query := &cloudMonitoringQuery{AliasBy: "{{metadata.system_labels.test2}}"}
|
||||
err = executor.parseResponse(res, data, query)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(res.Series), ShouldEqual, 3)
|
||||
@ -584,7 +638,7 @@ func TestStackdriver(t *testing.T) {
|
||||
|
||||
Convey("and alias by is expanded", func() {
|
||||
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
|
||||
query := &stackdriverQuery{
|
||||
query := &cloudMonitoringQuery{
|
||||
ProjectName: "test-proj",
|
||||
Selector: "select_slo_compliance",
|
||||
Service: "test-service",
|
||||
@ -604,7 +658,7 @@ func TestStackdriver(t *testing.T) {
|
||||
|
||||
Convey("and alias by is expanded", func() {
|
||||
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
|
||||
query := &stackdriverQuery{
|
||||
query := &cloudMonitoringQuery{
|
||||
ProjectName: "test-proj",
|
||||
Selector: "select_slo_compliance",
|
||||
Service: "test-service",
|
||||
@ -710,8 +764,8 @@ func TestStackdriver(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func loadTestFile(path string) (stackdriverResponse, error) {
|
||||
var data stackdriverResponse
|
||||
func loadTestFile(path string) (cloudMonitoringResponse, error) {
|
||||
var data cloudMonitoringResponse
|
||||
|
||||
jsonBody, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
@ -1,4 +1,4 @@
|
||||
package stackdriver
|
||||
package cloudmonitoring
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
stackdriverQuery struct {
|
||||
cloudMonitoringQuery struct {
|
||||
Target string
|
||||
Params url.Values
|
||||
RefID string
|
||||
@ -48,7 +48,7 @@ type (
|
||||
SloQuery sloQuery
|
||||
}
|
||||
|
||||
stackdriverBucketOptions struct {
|
||||
cloudMonitoringBucketOptions struct {
|
||||
LinearBuckets *struct {
|
||||
NumFiniteBuckets int64 `json:"numFiniteBuckets"`
|
||||
Width int64 `json:"width"`
|
||||
@ -64,7 +64,7 @@ type (
|
||||
} `json:"explicitBuckets"`
|
||||
}
|
||||
|
||||
stackdriverResponse struct {
|
||||
cloudMonitoringResponse struct {
|
||||
TimeSeries []struct {
|
||||
Metric struct {
|
||||
Labels map[string]string `json:"labels"`
|
||||
@ -95,8 +95,8 @@ type (
|
||||
Min int `json:"min"`
|
||||
Max int `json:"max"`
|
||||
} `json:"range"`
|
||||
BucketOptions stackdriverBucketOptions `json:"bucketOptions"`
|
||||
BucketCounts []string `json:"bucketCounts"`
|
||||
BucketOptions cloudMonitoringBucketOptions `json:"bucketOptions"`
|
||||
BucketCounts []string `json:"bucketCounts"`
|
||||
Examplars []struct {
|
||||
Value float64 `json:"value"`
|
||||
Timestamp string `json:"timestamp"`
|
@ -1,6 +1,6 @@
|
||||
import { react2AngularDirective } from 'app/core/utils/react2angular';
|
||||
import { QueryEditor as StackdriverQueryEditor } from 'app/plugins/datasource/stackdriver/components/QueryEditor';
|
||||
import { AnnotationQueryEditor as StackdriverAnnotationQueryEditor } from 'app/plugins/datasource/stackdriver/components/AnnotationQueryEditor';
|
||||
import { QueryEditor as CloudMonitoringQueryEditor } from 'app/plugins/datasource/cloud-monitoring/components/QueryEditor';
|
||||
import { AnnotationQueryEditor as CloudMonitoringAnnotationQueryEditor } from 'app/plugins/datasource/cloud-monitoring/components/AnnotationQueryEditor';
|
||||
import { AnnotationQueryEditor as CloudWatchAnnotationQueryEditor } from 'app/plugins/datasource/cloudwatch/components/AnnotationQueryEditor';
|
||||
import PageHeader from './components/PageHeader/PageHeader';
|
||||
import EmptyListCTA from './components/EmptyListCTA/EmptyListCTA';
|
||||
@ -118,7 +118,7 @@ export function registerAngularDirectives() {
|
||||
'placeholder',
|
||||
['variables', { watchDepth: 'reference' }],
|
||||
]);
|
||||
react2AngularDirective('stackdriverQueryEditor', StackdriverQueryEditor, [
|
||||
react2AngularDirective('cloudMonitoringQueryEditor', CloudMonitoringQueryEditor, [
|
||||
'target',
|
||||
'onQueryChange',
|
||||
'onExecuteQuery',
|
||||
@ -126,7 +126,7 @@ export function registerAngularDirectives() {
|
||||
['datasource', { watchDepth: 'reference' }],
|
||||
['templateSrv', { watchDepth: 'reference' }],
|
||||
]);
|
||||
react2AngularDirective('stackdriverAnnotationQueryEditor', StackdriverAnnotationQueryEditor, [
|
||||
react2AngularDirective('cloudMonitoringAnnotationQueryEditor', CloudMonitoringAnnotationQueryEditor, [
|
||||
'target',
|
||||
'onQueryChange',
|
||||
['datasource', { watchDepth: 'reference' }],
|
||||
|
@ -29,8 +29,8 @@ const mssqlPlugin = async () =>
|
||||
await import(/* webpackChunkName: "mssqlPlugin" */ 'app/plugins/datasource/mssql/module');
|
||||
const testDataDSPlugin = async () =>
|
||||
await import(/* webpackChunkName: "testDataDSPlugin" */ 'app/plugins/datasource/testdata/module');
|
||||
const stackdriverPlugin = async () =>
|
||||
await import(/* webpackChunkName: "stackdriverPlugin" */ 'app/plugins/datasource/stackdriver/module');
|
||||
const cloudMonitoringPlugin = async () =>
|
||||
await import(/* webpackChunkName: "cloudMonitoringPlugin" */ 'app/plugins/datasource/cloud-monitoring/module');
|
||||
const azureMonitorPlugin = async () =>
|
||||
await import(
|
||||
/* webpackChunkName: "azureMonitorPlugin" */ 'app/plugins/datasource/grafana-azure-monitor-datasource/module'
|
||||
@ -74,7 +74,7 @@ const builtInPlugins: any = {
|
||||
'app/plugins/datasource/mssql/module': mssqlPlugin,
|
||||
'app/plugins/datasource/prometheus/module': prometheusPlugin,
|
||||
'app/plugins/datasource/testdata/module': testDataDSPlugin,
|
||||
'app/plugins/datasource/stackdriver/module': stackdriverPlugin,
|
||||
'app/plugins/datasource/cloud-monitoring/module': cloudMonitoringPlugin,
|
||||
'app/plugins/datasource/grafana-azure-monitor-datasource/module': azureMonitorPlugin,
|
||||
|
||||
'app/plugins/panel/text/module': textPanel,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import isString from 'lodash/isString';
|
||||
import { alignmentPeriods, ValueTypes, MetricKind, selectors } from './constants';
|
||||
import StackdriverDatasource from './datasource';
|
||||
import CloudMonitoringDatasource from './datasource';
|
||||
import { MetricFindQueryTypes, VariableQueryData } from './types';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import {
|
||||
@ -11,8 +11,8 @@ import {
|
||||
getLabelKeys,
|
||||
} from './functions';
|
||||
|
||||
export default class StackdriverMetricFindQuery {
|
||||
constructor(private datasource: StackdriverDatasource) {}
|
||||
export default class CloudMonitoringMetricFindQuery {
|
||||
constructor(private datasource: CloudMonitoringDatasource) {}
|
||||
|
||||
async execute(query: VariableQueryData) {
|
||||
try {
|
||||
@ -49,7 +49,7 @@ export default class StackdriverMetricFindQuery {
|
||||
return [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Could not run StackdriverMetricFindQuery ${query}`, error);
|
||||
console.error(`Could not run CloudMonitoringMetricFindQuery ${query}`, error);
|
||||
return [];
|
||||
}
|
||||
}
|
7
public/app/plugins/datasource/cloud-monitoring/README.md
Normal file
7
public/app/plugins/datasource/cloud-monitoring/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Google Cloud Monitoring Data Source - Native Plugin (formerly named Stackdriver)
|
||||
|
||||
Grafana ships with built-in support for Google Cloud Monitoring. You just have to add it as a data source and you will be ready to build dashboards for your Cloud Monitoring metrics.
|
||||
|
||||
Read more about it here:
|
||||
|
||||
[https://grafana.com/docs/grafana/latest/features/datasources/cloudmonitoring/](https://grafana.com/docs/grafana/latest/features/datasources/cloudmonitoring/)
|
@ -1,7 +1,7 @@
|
||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||
import { AnnotationTarget } from './types';
|
||||
|
||||
export class StackdriverAnnotationsQueryCtrl {
|
||||
export class CloudMonitoringAnnotationsQueryCtrl {
|
||||
static templateUrl = 'partials/annotations.editor.html';
|
||||
annotation: any;
|
||||
templateSrv: TemplateSrv;
|
@ -25,7 +25,7 @@ describe('api', () => {
|
||||
let api: Api;
|
||||
let res: Array<SelectableValue<string>>;
|
||||
beforeEach(async () => {
|
||||
api = new Api('/stackdriver/');
|
||||
api = new Api('/cloudmonitoring/');
|
||||
api.cache['some-resource'] = response;
|
||||
res = await api.get('some-resource');
|
||||
});
|
||||
@ -41,7 +41,7 @@ describe('api', () => {
|
||||
let api: Api;
|
||||
let res: Array<SelectableValue<string>>;
|
||||
beforeEach(async () => {
|
||||
api = new Api('/stackdriver/');
|
||||
api = new Api('/cloudmonitoring/');
|
||||
res = await api.get('some-resource');
|
||||
});
|
||||
|
||||
@ -56,7 +56,7 @@ describe('api', () => {
|
||||
let api: Api;
|
||||
let res: Array<SelectableValue<string>>;
|
||||
beforeEach(async () => {
|
||||
api = new Api('/stackdriver/');
|
||||
api = new Api('/cloudmonitoring/');
|
||||
api.cache['some-resource'] = response;
|
||||
res = await api.get('some-resource', { useCache: false });
|
||||
});
|
@ -3,7 +3,7 @@ import { CoreEvents } from 'app/types';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { getBackendSrv } from '@grafana/runtime';
|
||||
|
||||
import { formatStackdriverError } from './functions';
|
||||
import { formatCloudMonitoringError } from './functions';
|
||||
import { MetricDescriptor } from './types';
|
||||
|
||||
interface Options {
|
||||
@ -50,7 +50,7 @@ export default class Api {
|
||||
|
||||
return res;
|
||||
} catch (error) {
|
||||
appEvents.emit(CoreEvents.dsRequestError, { error: { data: { error: formatStackdriverError(error) } } });
|
||||
appEvents.emit(CoreEvents.dsRequestError, { error: { data: { error: formatCloudMonitoringError(error) } } });
|
||||
return [];
|
||||
}
|
||||
}
|
@ -30,6 +30,7 @@ export const AlignmentPeriods: FC<Props> = ({
|
||||
...ap,
|
||||
label: ap.text,
|
||||
}));
|
||||
const visibleOptions = options.filter(ap => !ap.hidden);
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -46,7 +47,7 @@ export const AlignmentPeriods: FC<Props> = ({
|
||||
{
|
||||
label: 'Aggregations',
|
||||
expanded: true,
|
||||
options: options,
|
||||
options: visibleOptions,
|
||||
},
|
||||
]}
|
||||
placeholder="Select Alignment"
|
@ -5,7 +5,7 @@ const { Input } = LegacyForms;
|
||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
|
||||
import StackdriverDatasource from '../datasource';
|
||||
import CloudMonitoringDatasource from '../datasource';
|
||||
import { Metrics, LabelFilter, AnnotationsHelp, Project } from './';
|
||||
import { toOption } from '../functions';
|
||||
import { AnnotationTarget, MetricDescriptor } from '../types';
|
||||
@ -13,7 +13,7 @@ import { AnnotationTarget, MetricDescriptor } from '../types';
|
||||
export interface Props {
|
||||
onQueryChange: (target: AnnotationTarget) => void;
|
||||
target: AnnotationTarget;
|
||||
datasource: StackdriverDatasource;
|
||||
datasource: CloudMonitoringDatasource;
|
||||
templateSrv: TemplateSrv;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
|
||||
import { Project, Aggregations, Metrics, LabelFilter, GroupBys, Alignments, AlignmentPeriods, AliasBy } from '.';
|
||||
import { MetricQuery, MetricDescriptor } from '../types';
|
||||
import { getAlignmentPickerData } from '../functions';
|
||||
import StackdriverDatasource from '../datasource';
|
||||
import CloudMonitoringDatasource from '../datasource';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
|
||||
export interface Props {
|
||||
@ -12,7 +12,7 @@ export interface Props {
|
||||
onChange: (query: MetricQuery) => void;
|
||||
onRunQuery: () => void;
|
||||
query: MetricQuery;
|
||||
datasource: StackdriverDatasource;
|
||||
datasource: CloudMonitoringDatasource;
|
||||
}
|
||||
|
||||
interface State {
|
||||
@ -31,7 +31,7 @@ export const defaultQuery: MetricQuery = {
|
||||
valueType: '',
|
||||
unit: '',
|
||||
crossSeriesReducer: 'REDUCE_MEAN',
|
||||
alignmentPeriod: 'stackdriver-auto',
|
||||
alignmentPeriod: 'cloud-monitoring-auto',
|
||||
perSeriesAligner: 'ALIGN_MEAN',
|
||||
groupBys: [],
|
||||
filters: [],
|
@ -3,7 +3,7 @@ import _ from 'lodash';
|
||||
|
||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import StackdriverDatasource from '../datasource';
|
||||
import CloudMonitoringDatasource from '../datasource';
|
||||
import { Segment } from '@grafana/ui';
|
||||
import { MetricDescriptor } from '../types';
|
||||
|
||||
@ -11,7 +11,7 @@ export interface Props {
|
||||
onChange: (metricDescriptor: MetricDescriptor) => void;
|
||||
templateSrv: TemplateSrv;
|
||||
templateVariableOptions: Array<SelectableValue<string>>;
|
||||
datasource: StackdriverDatasource;
|
||||
datasource: CloudMonitoringDatasource;
|
||||
projectName: string;
|
||||
metricType: string;
|
||||
children?: (renderProps: any) => JSX.Element;
|
@ -1,10 +1,10 @@
|
||||
import React from 'react';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { SegmentAsync } from '@grafana/ui';
|
||||
import StackdriverDatasource from '../datasource';
|
||||
import CloudMonitoringDatasource from '../datasource';
|
||||
|
||||
export interface Props {
|
||||
datasource: StackdriverDatasource;
|
||||
datasource: CloudMonitoringDatasource;
|
||||
onChange: (projectName: string) => void;
|
||||
templateVariableOptions: Array<SelectableValue<string>>;
|
||||
projectName: string;
|
@ -2,14 +2,14 @@ import React, { PureComponent } from 'react';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { CoreEvents } from 'app/types';
|
||||
import { MetricQueryEditor, QueryTypeSelector, SLOQueryEditor, Help } from './';
|
||||
import { StackdriverQuery, MetricQuery, QueryType, SLOQuery } from '../types';
|
||||
import { CloudMonitoringQuery, MetricQuery, QueryType, SLOQuery } from '../types';
|
||||
import { defaultQuery } from './MetricQueryEditor';
|
||||
import { defaultQuery as defaultSLOQuery } from './SLOQueryEditor';
|
||||
import { toOption, formatStackdriverError } from '../functions';
|
||||
import StackdriverDatasource from '../datasource';
|
||||
import { toOption, formatCloudMonitoringError } from '../functions';
|
||||
import CloudMonitoringDatasource from '../datasource';
|
||||
import { ExploreQueryFieldProps } from '@grafana/data';
|
||||
|
||||
export type Props = ExploreQueryFieldProps<StackdriverDatasource, StackdriverQuery>;
|
||||
export type Props = ExploreQueryFieldProps<CloudMonitoringDatasource, CloudMonitoringQuery>;
|
||||
|
||||
interface State {
|
||||
lastQueryError: string;
|
||||
@ -53,7 +53,7 @@ export class QueryEditor extends PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
onDataError(error: any) {
|
||||
this.setState({ lastQueryError: formatStackdriverError(error) });
|
||||
this.setState({ lastQueryError: formatCloudMonitoringError(error) });
|
||||
}
|
||||
|
||||
onQueryChange(prop: string, value: any) {
|
@ -4,7 +4,7 @@ import { SelectableValue } from '@grafana/data';
|
||||
import { selectors } from '../constants';
|
||||
import { Project, AlignmentPeriods, AliasBy, QueryInlineField } from '.';
|
||||
import { SLOQuery } from '../types';
|
||||
import StackdriverDatasource from '../datasource';
|
||||
import CloudMonitoringDatasource from '../datasource';
|
||||
|
||||
export interface Props {
|
||||
usedAlignmentPeriod: string;
|
||||
@ -12,12 +12,12 @@ export interface Props {
|
||||
onChange: (query: SLOQuery) => void;
|
||||
onRunQuery: () => void;
|
||||
query: SLOQuery;
|
||||
datasource: StackdriverDatasource;
|
||||
datasource: CloudMonitoringDatasource;
|
||||
}
|
||||
|
||||
export const defaultQuery: SLOQuery = {
|
||||
projectName: '',
|
||||
alignmentPeriod: 'stackdriver-auto',
|
||||
alignmentPeriod: 'cloud-monitoring-auto',
|
||||
aliasBy: '',
|
||||
selectorName: 'select_slo_health',
|
||||
serviceId: '',
|
@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
// @ts-ignore
|
||||
import renderer from 'react-test-renderer';
|
||||
import { StackdriverVariableQueryEditor } from './VariableQueryEditor';
|
||||
import { CloudMonitoringVariableQueryEditor } from './VariableQueryEditor';
|
||||
import { VariableQueryProps } from 'app/types/plugins';
|
||||
import { MetricFindQueryTypes } from '../types';
|
||||
import { VariableModel } from 'app/features/variables/types';
|
||||
@ -41,7 +41,7 @@ const props: VariableQueryProps = {
|
||||
|
||||
describe('VariableQueryEditor', () => {
|
||||
it('renders correctly', () => {
|
||||
const tree = renderer.create(<StackdriverVariableQueryEditor {...props} />).toJSON();
|
||||
const tree = renderer.create(<CloudMonitoringVariableQueryEditor {...props} />).toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
@ -49,10 +49,10 @@ describe('VariableQueryEditor', () => {
|
||||
// these test need to be updated to reflect the changes from old variables system to new
|
||||
it('should trigger a query using the first query type in the array', done => {
|
||||
props.onChange = (query, definition) => {
|
||||
expect(definition).toBe('Stackdriver - Projects');
|
||||
expect(definition).toBe('Google Cloud Monitoring - Projects');
|
||||
done();
|
||||
};
|
||||
renderer.create(<StackdriverVariableQueryEditor {...props} />).toJSON();
|
||||
renderer.create(<CloudMonitoringVariableQueryEditor {...props} />).toJSON();
|
||||
});
|
||||
});
|
||||
|
||||
@ -61,10 +61,10 @@ describe('VariableQueryEditor', () => {
|
||||
it('should trigger new query using the saved query type', done => {
|
||||
props.query = { selectedQueryType: MetricFindQueryTypes.LabelKeys };
|
||||
props.onChange = (query, definition) => {
|
||||
expect(definition).toBe('Stackdriver - Label Keys');
|
||||
expect(definition).toBe('Google Cloud Monitoring - Label Keys');
|
||||
done();
|
||||
};
|
||||
renderer.create(<StackdriverVariableQueryEditor {...props} />).toJSON();
|
||||
renderer.create(<CloudMonitoringVariableQueryEditor {...props} />).toJSON();
|
||||
});
|
||||
});
|
||||
});
|
@ -4,7 +4,7 @@ import { SimpleSelect } from './';
|
||||
import { extractServicesFromMetricDescriptors, getLabelKeys, getMetricTypes } from '../functions';
|
||||
import { MetricFindQueryTypes, VariableQueryData } from '../types';
|
||||
|
||||
export class StackdriverVariableQueryEditor extends PureComponent<VariableQueryProps, VariableQueryData> {
|
||||
export class CloudMonitoringVariableQueryEditor extends PureComponent<VariableQueryProps, VariableQueryData> {
|
||||
queryTypes: Array<{ value: string; name: string }> = [
|
||||
{ value: MetricFindQueryTypes.Projects, name: 'Projects' },
|
||||
{ value: MetricFindQueryTypes.Services, name: 'Services' },
|
||||
@ -88,7 +88,7 @@ export class StackdriverVariableQueryEditor extends PureComponent<VariableQueryP
|
||||
onPropsChange = () => {
|
||||
const { metricDescriptors, labels, metricTypes, services, ...queryModel } = this.state;
|
||||
const query = this.queryTypes.find(q => q.value === this.state.selectedQueryType);
|
||||
this.props.onChange(queryModel, `Stackdriver - ${query.name}`);
|
||||
this.props.onChange(queryModel, `Google Cloud Monitoring - ${query.name}`);
|
||||
};
|
||||
|
||||
async onQueryTypeChange(queryType: string) {
|
@ -8,8 +8,8 @@ export interface JWT {
|
||||
project_id: string;
|
||||
}
|
||||
|
||||
export class StackdriverConfigCtrl {
|
||||
static templateUrl = 'public/app/plugins/datasource/stackdriver/partials/config.html';
|
||||
export class CloudMonitoringConfigCtrl {
|
||||
static templateUrl = 'public/app/plugins/datasource/cloud-monitoring/partials/config.html';
|
||||
datasourceSrv: DatasourceSrv;
|
||||
current: any;
|
||||
meta: any;
|
@ -231,7 +231,8 @@ export const aggOptions = [
|
||||
|
||||
export const alignmentPeriods = [
|
||||
{ text: 'grafana auto', value: 'grafana-auto' },
|
||||
{ text: 'stackdriver auto', value: 'stackdriver-auto' },
|
||||
{ text: 'stackdriver auto', value: 'stackdriver-auto', hidden: true },
|
||||
{ text: 'cloud monitoring auto', value: 'cloud-monitoring-auto' },
|
||||
{ text: '1m', value: '+60s' },
|
||||
{ text: '2m', value: '+120s' },
|
||||
{ text: '5m', value: '+300s' },
|
||||
@ -245,7 +246,7 @@ export const alignmentPeriods = [
|
||||
{ text: '1w', value: '+604800s' },
|
||||
];
|
||||
|
||||
export const stackdriverUnitMappings = {
|
||||
export const cloudMonitoringUnitMappings = {
|
||||
bit: 'bits',
|
||||
By: 'bytes',
|
||||
s: 's',
|
@ -11,31 +11,38 @@ import {
|
||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||
import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
||||
|
||||
import { StackdriverQuery, MetricDescriptor, StackdriverOptions, Filter, VariableQueryData, QueryType } from './types';
|
||||
import { stackdriverUnitMappings } from './constants';
|
||||
import {
|
||||
CloudMonitoringQuery,
|
||||
MetricDescriptor,
|
||||
CloudMonitoringOptions,
|
||||
Filter,
|
||||
VariableQueryData,
|
||||
QueryType,
|
||||
} from './types';
|
||||
import { cloudMonitoringUnitMappings } from './constants';
|
||||
import API from './api';
|
||||
import StackdriverMetricFindQuery from './StackdriverMetricFindQuery';
|
||||
import CloudMonitoringMetricFindQuery from './CloudMonitoringMetricFindQuery';
|
||||
|
||||
export default class StackdriverDatasource extends DataSourceApi<StackdriverQuery, StackdriverOptions> {
|
||||
export default class CloudMonitoringDatasource extends DataSourceApi<CloudMonitoringQuery, CloudMonitoringOptions> {
|
||||
api: API;
|
||||
authenticationType: string;
|
||||
|
||||
/** @ngInject */
|
||||
constructor(
|
||||
private instanceSettings: DataSourceInstanceSettings<StackdriverOptions>,
|
||||
private instanceSettings: DataSourceInstanceSettings<CloudMonitoringOptions>,
|
||||
public templateSrv: TemplateSrv,
|
||||
private timeSrv: TimeSrv
|
||||
) {
|
||||
super(instanceSettings);
|
||||
this.authenticationType = instanceSettings.jsonData.authenticationType || 'jwt';
|
||||
this.api = new API(`${instanceSettings.url!}/stackdriver/v3/projects/`);
|
||||
this.api = new API(`${instanceSettings.url!}/cloudmonitoring/v3/projects/`);
|
||||
}
|
||||
|
||||
get variables() {
|
||||
return this.templateSrv.getVariables().map(v => `$${v.name}`);
|
||||
}
|
||||
|
||||
async query(options: DataQueryRequest<StackdriverQuery>): Promise<DataQueryResponse> {
|
||||
async query(options: DataQueryRequest<CloudMonitoringQuery>): Promise<DataQueryResponse> {
|
||||
const result: DataQueryResponse[] = [];
|
||||
const data = await this.getTimeSeries(options);
|
||||
if (data.results) {
|
||||
@ -107,11 +114,11 @@ export default class StackdriverDatasource extends DataSourceApi<StackdriverQuer
|
||||
|
||||
async metricFindQuery(query: VariableQueryData) {
|
||||
await this.ensureGCEDefaultProject();
|
||||
const stackdriverMetricFindQuery = new StackdriverMetricFindQuery(this);
|
||||
return stackdriverMetricFindQuery.execute(query);
|
||||
const cloudMonitoringMetricFindQuery = new CloudMonitoringMetricFindQuery(this);
|
||||
return cloudMonitoringMetricFindQuery.execute(query);
|
||||
}
|
||||
|
||||
async getTimeSeries(options: DataQueryRequest<StackdriverQuery>) {
|
||||
async getTimeSeries(options: DataQueryRequest<CloudMonitoringQuery>) {
|
||||
await this.ensureGCEDefaultProject();
|
||||
const queries = options.targets
|
||||
.map(this.migrateQuery)
|
||||
@ -147,20 +154,20 @@ export default class StackdriverDatasource extends DataSourceApi<StackdriverQuer
|
||||
},
|
||||
],
|
||||
range: this.timeSrv.timeRange(),
|
||||
} as DataQueryRequest<StackdriverQuery>);
|
||||
} as DataQueryRequest<CloudMonitoringQuery>);
|
||||
const result = response.results[refId];
|
||||
return result && result.meta ? result.meta.labels : {};
|
||||
}
|
||||
|
||||
async testDatasource() {
|
||||
let status, message;
|
||||
const defaultErrorMessage = 'Cannot connect to Stackdriver API';
|
||||
const defaultErrorMessage = 'Cannot connect to Google Cloud Monitoring API';
|
||||
try {
|
||||
await this.ensureGCEDefaultProject();
|
||||
const response = await this.api.test(this.getDefaultProject());
|
||||
if (response.status === 200) {
|
||||
status = 'success';
|
||||
message = 'Successfully queried the Stackdriver API.';
|
||||
message = 'Successfully queried the Google Cloud Monitoring API.';
|
||||
} else {
|
||||
status = 'error';
|
||||
message = response.statusText ? response.statusText : defaultErrorMessage;
|
||||
@ -170,7 +177,7 @@ export default class StackdriverDatasource extends DataSourceApi<StackdriverQuer
|
||||
if (_.isString(error)) {
|
||||
message = error;
|
||||
} else {
|
||||
message = 'Stackdriver: ';
|
||||
message = 'Google Cloud Monitoring: ';
|
||||
message += error.statusText ? error.statusText : defaultErrorMessage;
|
||||
if (error.data && error.data.error && error.data.error.code) {
|
||||
message += ': ' + error.data.error.code + '. ' + error.data.error.message;
|
||||
@ -272,7 +279,7 @@ export default class StackdriverDatasource extends DataSourceApi<StackdriverQuer
|
||||
});
|
||||
}
|
||||
|
||||
migrateQuery(query: StackdriverQuery): StackdriverQuery {
|
||||
migrateQuery(query: CloudMonitoringQuery): CloudMonitoringQuery {
|
||||
if (!query.hasOwnProperty('metricQuery')) {
|
||||
const { hide, refId, datasource, key, queryType, maxLines, metric, ...rest } = query as any;
|
||||
return {
|
||||
@ -297,7 +304,7 @@ export default class StackdriverDatasource extends DataSourceApi<StackdriverQuer
|
||||
}, {});
|
||||
}
|
||||
|
||||
shouldRunQuery(query: StackdriverQuery): boolean {
|
||||
shouldRunQuery(query: CloudMonitoringQuery): boolean {
|
||||
if (query.hide) {
|
||||
return false;
|
||||
}
|
||||
@ -313,8 +320,8 @@ export default class StackdriverDatasource extends DataSourceApi<StackdriverQuer
|
||||
}
|
||||
|
||||
prepareTimeSeriesQuery(
|
||||
{ metricQuery, refId, queryType, sloQuery }: StackdriverQuery,
|
||||
{ scopedVars, intervalMs }: DataQueryRequest<StackdriverQuery>
|
||||
{ metricQuery, refId, queryType, sloQuery }: CloudMonitoringQuery,
|
||||
{ scopedVars, intervalMs }: DataQueryRequest<CloudMonitoringQuery>
|
||||
) {
|
||||
return {
|
||||
datasourceId: this.id,
|
||||
@ -373,9 +380,9 @@ export default class StackdriverDatasource extends DataSourceApi<StackdriverQuer
|
||||
resolvePanelUnitFromTargets(targets: any) {
|
||||
let unit;
|
||||
if (targets.length > 0 && targets.every((t: any) => t.unit === targets[0].unit)) {
|
||||
if (stackdriverUnitMappings.hasOwnProperty(targets[0].unit!)) {
|
||||
if (cloudMonitoringUnitMappings.hasOwnProperty(targets[0].unit!)) {
|
||||
// @ts-ignore
|
||||
unit = stackdriverUnitMappings[targets[0].unit];
|
||||
unit = cloudMonitoringUnitMappings[targets[0].unit];
|
||||
}
|
||||
}
|
||||
return unit;
|
@ -1,7 +1,7 @@
|
||||
import _ from 'lodash';
|
||||
import { alignOptions, aggOptions, ValueTypes, MetricKind, systemLabels } from './constants';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import StackdriverDatasource from './datasource';
|
||||
import CloudMonitoringDatasource from './datasource';
|
||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||
import { MetricDescriptor, Filter, MetricQuery } from './types';
|
||||
|
||||
@ -51,7 +51,7 @@ export const getAggregationOptionsByMetric = (valueType: ValueTypes, metricKind:
|
||||
};
|
||||
|
||||
export const getLabelKeys = async (
|
||||
datasource: StackdriverDatasource,
|
||||
datasource: CloudMonitoringDatasource,
|
||||
selectedMetricType: string,
|
||||
projectName: string
|
||||
) => {
|
||||
@ -107,7 +107,7 @@ export const stringArrayToFilters = (filterArray: string[]) =>
|
||||
|
||||
export const toOption = (value: string) => ({ label: value, value } as SelectableValue<string>);
|
||||
|
||||
export const formatStackdriverError = (error: any) => {
|
||||
export const formatCloudMonitoringError = (error: any) => {
|
||||
let message = error.statusText ?? '';
|
||||
if (error.data && error.data.error) {
|
||||
try {
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
13
public/app/plugins/datasource/cloud-monitoring/module.ts
Normal file
13
public/app/plugins/datasource/cloud-monitoring/module.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { DataSourcePlugin } from '@grafana/data';
|
||||
import CloudMonitoringDatasource from './datasource';
|
||||
import { QueryEditor } from './components/QueryEditor';
|
||||
import { CloudMonitoringConfigCtrl } from './config_ctrl';
|
||||
import { CloudMonitoringAnnotationsQueryCtrl } from './annotations_query_ctrl';
|
||||
import { CloudMonitoringVariableQueryEditor } from './components/VariableQueryEditor';
|
||||
import { CloudMonitoringQuery } from './types';
|
||||
|
||||
export const plugin = new DataSourcePlugin<CloudMonitoringDatasource, CloudMonitoringQuery>(CloudMonitoringDatasource)
|
||||
.setQueryEditor(QueryEditor)
|
||||
.setConfigCtrl(CloudMonitoringConfigCtrl)
|
||||
.setAnnotationQueryCtrl(CloudMonitoringAnnotationsQueryCtrl)
|
||||
.setVariableQueryEditor(CloudMonitoringVariableQueryEditor);
|
@ -1,6 +1,6 @@
|
||||
<stackdriver-annotation-query-editor
|
||||
<cloud-monitoring-annotation-query-editor
|
||||
target="ctrl.annotation.target"
|
||||
on-query-change="(ctrl.onQueryChange)"
|
||||
datasource="ctrl.datasource"
|
||||
template-srv="ctrl.templateSrv"
|
||||
></stackdriver-annotation-query-editor>
|
||||
></cloud-monitoring-annotation-query-editor>
|
@ -1,8 +1,8 @@
|
||||
<div class="gf-form-group">
|
||||
<div class="grafana-info-box">
|
||||
<h4>Stackdriver Authentication</h4>
|
||||
<h4>Google Cloud Monitoring Authentication</h4>
|
||||
<p>
|
||||
There are two ways to authenticate the Stackdriver plugin - either by uploading a Service Account key file, or by
|
||||
There are two ways to authenticate the Google Cloud Monitoring plugin - either by uploading a Service Account key file, or by
|
||||
automatically retrieving credentials from the Google metadata server. The latter option is only available when
|
||||
running Grafana on a GCE virtual machine.
|
||||
</p>
|
||||
@ -29,12 +29,12 @@
|
||||
If Grafana is running on a Google Compute Engine (GCE) virtual machine, it is possible for Grafana to
|
||||
automatically retrieve the default project id and authentication token from the metadata server. In order for this
|
||||
to work, you need to make sure that you have a service account that is setup as the default account for the
|
||||
virtual machine and that the service account has been given read access to the Stackdriver Monitoring API.
|
||||
virtual machine and that the service account has been given read access to the Google Cloud Monitoring Monitoring API.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Detailed instructions on how to create a Service Account can be found
|
||||
<a class="external-link" target="_blank" href="http://docs.grafana.org/datasources/stackdriver/"
|
||||
<a class="external-link" target="_blank" href="http://docs.grafana.org/datasources/cloudmonitoring/"
|
||||
>in the documentation.</a
|
||||
>
|
||||
</p>
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "Stackdriver",
|
||||
"name": "Google Cloud Monitoring",
|
||||
"type": "datasource",
|
||||
"id": "stackdriver",
|
||||
"category": "cloud",
|
||||
@ -13,11 +13,11 @@
|
||||
},
|
||||
|
||||
"info": {
|
||||
"description": "Data source for Google's monitoring service",
|
||||
"description": "Data source for Google's monitoring service (formerly named Stackdriver)",
|
||||
"version": "1.0.0",
|
||||
"logos": {
|
||||
"small": "img/stackdriver_logo.svg",
|
||||
"large": "img/stackdriver_logo.svg"
|
||||
"small": "img/cloud_monitoring_logo.svg",
|
||||
"large": "img/cloud_monitoring_logo.svg"
|
||||
},
|
||||
"author": {
|
||||
"name": "Grafana Labs",
|
||||
@ -26,7 +26,7 @@
|
||||
},
|
||||
"routes": [
|
||||
{
|
||||
"path": "stackdriver",
|
||||
"path": "cloudmonitoring",
|
||||
"method": "GET",
|
||||
"url": "https://content-monitoring.googleapis.com",
|
||||
"jwtTokenAuth": {
|
@ -1,8 +1,8 @@
|
||||
import StackdriverDataSource from '../datasource';
|
||||
import CloudMonitoringDataSource from '../datasource';
|
||||
import { metricDescriptors } from './testData';
|
||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||
import { DataSourceInstanceSettings, toUtc } from '@grafana/data';
|
||||
import { StackdriverOptions } from '../types';
|
||||
import { CloudMonitoringOptions } from '../types';
|
||||
import { backendSrv } from 'app/core/services/backend_srv'; // will use the version in __mocks__
|
||||
import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
||||
import { CustomVariableModel } from '../../../../features/variables/types';
|
||||
@ -18,12 +18,12 @@ interface Result {
|
||||
message?: any;
|
||||
}
|
||||
|
||||
describe('StackdriverDataSource', () => {
|
||||
describe('CloudMonitoringDataSource', () => {
|
||||
const instanceSettings = ({
|
||||
jsonData: {
|
||||
defaultProject: 'testproject',
|
||||
},
|
||||
} as unknown) as DataSourceInstanceSettings<StackdriverOptions>;
|
||||
} as unknown) as DataSourceInstanceSettings<CloudMonitoringOptions>;
|
||||
const templateSrv = new TemplateSrv();
|
||||
const timeSrv = {} as TimeSrv;
|
||||
const datasourceRequestMock = jest.spyOn(backendSrv, 'datasourceRequest');
|
||||
@ -34,12 +34,12 @@ describe('StackdriverDataSource', () => {
|
||||
});
|
||||
|
||||
describe('when performing testDataSource', () => {
|
||||
describe('and call to stackdriver api succeeds', () => {
|
||||
describe('and call to cloud monitoring api succeeds', () => {
|
||||
let ds;
|
||||
let result: Result;
|
||||
beforeEach(async () => {
|
||||
datasourceRequestMock.mockImplementation(() => Promise.resolve({ status: 200 }));
|
||||
ds = new StackdriverDataSource(instanceSettings, templateSrv, timeSrv);
|
||||
ds = new CloudMonitoringDataSource(instanceSettings, templateSrv, timeSrv);
|
||||
result = await ds.testDatasource();
|
||||
});
|
||||
|
||||
@ -54,7 +54,7 @@ describe('StackdriverDataSource', () => {
|
||||
beforeEach(async () => {
|
||||
datasourceRequestMock.mockImplementation(() => Promise.resolve({ status: 200, data: metricDescriptors }));
|
||||
|
||||
ds = new StackdriverDataSource(instanceSettings, templateSrv, timeSrv);
|
||||
ds = new CloudMonitoringDataSource(instanceSettings, templateSrv, timeSrv);
|
||||
result = await ds.testDatasource();
|
||||
});
|
||||
|
||||
@ -63,7 +63,7 @@ describe('StackdriverDataSource', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('and call to stackdriver api fails with 400 error', () => {
|
||||
describe('and call to cloud monitoring api fails with 400 error', () => {
|
||||
let ds;
|
||||
let result: Result;
|
||||
beforeEach(async () => {
|
||||
@ -76,13 +76,15 @@ describe('StackdriverDataSource', () => {
|
||||
})
|
||||
);
|
||||
|
||||
ds = new StackdriverDataSource(instanceSettings, templateSrv, timeSrv);
|
||||
ds = new CloudMonitoringDataSource(instanceSettings, templateSrv, timeSrv);
|
||||
result = await ds.testDatasource();
|
||||
});
|
||||
|
||||
it('should return error status and a detailed error message', () => {
|
||||
expect(result.status).toEqual('error');
|
||||
expect(result.message).toBe('Stackdriver: Bad Request: 400. Field interval.endTime had an invalid value');
|
||||
expect(result.message).toBe(
|
||||
'Google Cloud Monitoring: Bad Request: 400. Field interval.endTime had an invalid value'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -105,7 +107,7 @@ describe('StackdriverDataSource', () => {
|
||||
};
|
||||
|
||||
describe('and no time series data is returned', () => {
|
||||
let ds: StackdriverDataSource;
|
||||
let ds: CloudMonitoringDataSource;
|
||||
const response: any = {
|
||||
results: {
|
||||
A: {
|
||||
@ -121,7 +123,7 @@ describe('StackdriverDataSource', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
datasourceRequestMock.mockImplementation(() => Promise.resolve({ status: 200, data: response }));
|
||||
ds = new StackdriverDataSource(instanceSettings, templateSrv, timeSrv);
|
||||
ds = new CloudMonitoringDataSource(instanceSettings, templateSrv, timeSrv);
|
||||
});
|
||||
|
||||
it('should return a list of datapoints', () => {
|
||||
@ -133,7 +135,7 @@ describe('StackdriverDataSource', () => {
|
||||
});
|
||||
|
||||
describe('when performing getMetricTypes', () => {
|
||||
describe('and call to stackdriver api succeeds', () => {});
|
||||
describe('and call to cloud monitoring api succeeds', () => {});
|
||||
let ds;
|
||||
let result: any;
|
||||
beforeEach(async () => {
|
||||
@ -154,7 +156,7 @@ describe('StackdriverDataSource', () => {
|
||||
})
|
||||
);
|
||||
|
||||
ds = new StackdriverDataSource(instanceSettings, templateSrv, timeSrv);
|
||||
ds = new CloudMonitoringDataSource(instanceSettings, templateSrv, timeSrv);
|
||||
// @ts-ignore
|
||||
result = await ds.getMetricTypes('proj');
|
||||
});
|
||||
@ -176,7 +178,7 @@ describe('StackdriverDataSource', () => {
|
||||
describe('and is single value variable', () => {
|
||||
beforeEach(() => {
|
||||
const filterTemplateSrv = initTemplateSrv('filtervalue1');
|
||||
const ds = new StackdriverDataSource(instanceSettings, filterTemplateSrv, timeSrv);
|
||||
const ds = new CloudMonitoringDataSource(instanceSettings, filterTemplateSrv, timeSrv);
|
||||
interpolated = ds.interpolateFilters(['resource.label.zone', '=~', '${test}'], {});
|
||||
});
|
||||
|
||||
@ -189,7 +191,7 @@ describe('StackdriverDataSource', () => {
|
||||
describe('and is single value variable for the label part', () => {
|
||||
beforeEach(() => {
|
||||
const filterTemplateSrv = initTemplateSrv('resource.label.zone');
|
||||
const ds = new StackdriverDataSource(instanceSettings, filterTemplateSrv, timeSrv);
|
||||
const ds = new CloudMonitoringDataSource(instanceSettings, filterTemplateSrv, timeSrv);
|
||||
interpolated = ds.interpolateFilters(['${test}', '=~', 'europe-north-1a'], {});
|
||||
});
|
||||
|
||||
@ -202,7 +204,7 @@ describe('StackdriverDataSource', () => {
|
||||
describe('and is multi value variable', () => {
|
||||
beforeEach(() => {
|
||||
const filterTemplateSrv = initTemplateSrv(['filtervalue1', 'filtervalue2'], true);
|
||||
const ds = new StackdriverDataSource(instanceSettings, filterTemplateSrv, timeSrv);
|
||||
const ds = new CloudMonitoringDataSource(instanceSettings, filterTemplateSrv, timeSrv);
|
||||
interpolated = ds.interpolateFilters(['resource.label.zone', '=~', '[[test]]'], {});
|
||||
});
|
||||
|
||||
@ -218,7 +220,7 @@ describe('StackdriverDataSource', () => {
|
||||
describe('and is single value variable', () => {
|
||||
beforeEach(() => {
|
||||
const groupByTemplateSrv = initTemplateSrv('groupby1');
|
||||
const ds = new StackdriverDataSource(instanceSettings, groupByTemplateSrv, timeSrv);
|
||||
const ds = new CloudMonitoringDataSource(instanceSettings, groupByTemplateSrv, timeSrv);
|
||||
interpolated = ds.interpolateGroupBys(['[[test]]'], {});
|
||||
});
|
||||
|
||||
@ -231,7 +233,7 @@ describe('StackdriverDataSource', () => {
|
||||
describe('and is multi value variable', () => {
|
||||
beforeEach(() => {
|
||||
const groupByTemplateSrv = initTemplateSrv(['groupby1', 'groupby2'], true);
|
||||
const ds = new StackdriverDataSource(instanceSettings, groupByTemplateSrv, timeSrv);
|
||||
const ds = new CloudMonitoringDataSource(instanceSettings, groupByTemplateSrv, timeSrv);
|
||||
interpolated = ds.interpolateGroupBys(['[[test]]'], {});
|
||||
});
|
||||
|
||||
@ -244,12 +246,12 @@ describe('StackdriverDataSource', () => {
|
||||
});
|
||||
|
||||
describe('unit parsing', () => {
|
||||
let ds: StackdriverDataSource, res: any;
|
||||
let ds: CloudMonitoringDataSource, res: any;
|
||||
beforeEach(() => {
|
||||
ds = new StackdriverDataSource(instanceSettings, templateSrv, timeSrv);
|
||||
ds = new CloudMonitoringDataSource(instanceSettings, templateSrv, timeSrv);
|
||||
});
|
||||
describe('when theres only one target', () => {
|
||||
describe('and the stackdriver unit doesnt have a corresponding grafana unit', () => {
|
||||
describe('and the cloud monitoring unit doesnt have a corresponding grafana unit', () => {
|
||||
beforeEach(() => {
|
||||
res = ds.resolvePanelUnitFromTargets([{ unit: 'megaseconds' }]);
|
||||
});
|
||||
@ -257,7 +259,7 @@ describe('StackdriverDataSource', () => {
|
||||
expect(res).toBeUndefined();
|
||||
});
|
||||
});
|
||||
describe('and the stackdriver unit has a corresponding grafana unit', () => {
|
||||
describe('and the cloud monitoring unit has a corresponding grafana unit', () => {
|
||||
beforeEach(() => {
|
||||
res = ds.resolvePanelUnitFromTargets([{ unit: 'bit' }]);
|
||||
});
|
@ -78,14 +78,14 @@ export interface SLOQuery {
|
||||
goal?: number;
|
||||
}
|
||||
|
||||
export interface StackdriverQuery extends DataQuery {
|
||||
export interface CloudMonitoringQuery extends DataQuery {
|
||||
datasourceId?: number; // Should not be necessary anymore
|
||||
queryType: QueryType;
|
||||
metricQuery: MetricQuery;
|
||||
sloQuery?: SLOQuery;
|
||||
}
|
||||
|
||||
export interface StackdriverOptions extends DataSourceJsonData {
|
||||
export interface CloudMonitoringOptions extends DataSourceJsonData {
|
||||
defaultProject?: string;
|
||||
gceDefaultProject?: string;
|
||||
authenticationType?: string;
|
@ -1,7 +0,0 @@
|
||||
# Stackdriver Data Source - Native Plugin
|
||||
|
||||
Grafana ships with built-in support for Google Stackdriver. You just have to add it as a data source and you will be ready to build dashboards for your Stackdriver metrics.
|
||||
|
||||
Read more about it here:
|
||||
|
||||
[http://docs.grafana.org/datasources/stackdriver/](http://docs.grafana.org/datasources/stackdriver/)
|
@ -1,13 +0,0 @@
|
||||
import { DataSourcePlugin } from '@grafana/data';
|
||||
import StackdriverDatasource from './datasource';
|
||||
import { QueryEditor } from './components/QueryEditor';
|
||||
import { StackdriverConfigCtrl } from './config_ctrl';
|
||||
import { StackdriverAnnotationsQueryCtrl } from './annotations_query_ctrl';
|
||||
import { StackdriverVariableQueryEditor } from './components/VariableQueryEditor';
|
||||
import { StackdriverQuery } from './types';
|
||||
|
||||
export const plugin = new DataSourcePlugin<StackdriverDatasource, StackdriverQuery>(StackdriverDatasource)
|
||||
.setQueryEditor(QueryEditor)
|
||||
.setConfigCtrl(StackdriverConfigCtrl)
|
||||
.setAnnotationQueryCtrl(StackdriverAnnotationsQueryCtrl)
|
||||
.setVariableQueryEditor(StackdriverVariableQueryEditor);
|
Loading…
Reference in New Issue
Block a user