mirror of https://github.com/grafana/grafana.git
stackdriver: tests for parsing api response
This commit is contained in:
parent
54f16d5558
commit
2683699ab4
|
|
@ -15,7 +15,6 @@ import (
|
|||
"golang.org/x/net/context/ctxhttp"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/pluginproxy"
|
||||
"github.com/grafana/grafana/pkg/cmd/grafana-cli/logger"
|
||||
"github.com/grafana/grafana/pkg/components/null"
|
||||
"github.com/grafana/grafana/pkg/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
|
|
@ -25,10 +24,14 @@ import (
|
|||
"github.com/opentracing/opentracing-go"
|
||||
)
|
||||
|
||||
var slog log.Logger
|
||||
|
||||
// StackdriverExecutor executes queries for the Stackdriver datasource
|
||||
type StackdriverExecutor struct {
|
||||
HTTPClient *http.Client
|
||||
}
|
||||
|
||||
// NewStackdriverExecutor initializes a http client
|
||||
func NewStackdriverExecutor(dsInfo *models.DataSource) (tsdb.TsdbQueryEndpoint, error) {
|
||||
httpClient, err := dsInfo.GetHttpClient()
|
||||
if err != nil {
|
||||
|
|
@ -40,9 +43,8 @@ func NewStackdriverExecutor(dsInfo *models.DataSource) (tsdb.TsdbQueryEndpoint,
|
|||
}, nil
|
||||
}
|
||||
|
||||
var glog = log.New("tsdb.stackdriver")
|
||||
|
||||
func init() {
|
||||
slog = log.New("tsdb.stackdriver")
|
||||
tsdb.RegisterTsdbQueryEndpoint("stackdriver", NewStackdriverExecutor)
|
||||
}
|
||||
|
||||
|
|
@ -66,7 +68,7 @@ func (e *StackdriverExecutor) Query(ctx context.Context, dsInfo *models.DataSour
|
|||
}
|
||||
|
||||
req.URL.RawQuery = query.Params.Encode()
|
||||
logger.Info("tsdbQuery", "req.URL.RawQuery", req.URL.RawQuery)
|
||||
slog.Info("tsdbQuery", "req.URL.RawQuery", req.URL.RawQuery)
|
||||
|
||||
httpClient, err := dsInfo.GetHttpClient()
|
||||
if err != nil {
|
||||
|
|
@ -138,7 +140,7 @@ func (e *StackdriverExecutor) parseQueries(tsdbQuery *tsdb.TsdbQuery) ([]*Stackd
|
|||
params.Add("filter", metricType)
|
||||
|
||||
if setting.Env == setting.DEV {
|
||||
glog.Debug("Stackdriver request", "params", params)
|
||||
slog.Debug("Stackdriver request", "params", params)
|
||||
}
|
||||
|
||||
stackdriverQueries = append(stackdriverQueries, &StackdriverQuery{
|
||||
|
|
@ -159,14 +161,14 @@ func (e *StackdriverExecutor) unmarshalResponse(res *http.Response) (StackDriver
|
|||
}
|
||||
|
||||
if res.StatusCode/100 != 2 {
|
||||
glog.Info("Request failed", "status", res.Status, "body", string(body))
|
||||
slog.Info("Request failed", "status", res.Status, "body", string(body))
|
||||
return StackDriverResponse{}, fmt.Errorf("Request failed status: %v", res.Status)
|
||||
}
|
||||
|
||||
var data StackDriverResponse
|
||||
err = json.Unmarshal(body, &data)
|
||||
if err != nil {
|
||||
glog.Info("Failed to unmarshal Stackdriver response", "error", err, "status", res.Status, "body", string(body))
|
||||
slog.Info("Failed to unmarshal Stackdriver response", "error", err, "status", res.Status, "body", string(body))
|
||||
return StackDriverResponse{}, err
|
||||
}
|
||||
|
||||
|
|
@ -182,8 +184,13 @@ func (e *StackdriverExecutor) parseResponse(data StackDriverResponse, queryRefID
|
|||
for _, point := range series.Points {
|
||||
points = append(points, tsdb.NewTimePoint(null.FloatFrom(point.Value.DoubleValue), float64((point.Interval.EndTime).Unix())*1000))
|
||||
}
|
||||
metricName := series.Metric.Type
|
||||
|
||||
for _, value := range series.Metric.Labels {
|
||||
metricName += " " + value
|
||||
}
|
||||
queryRes.Series = append(queryRes.Series, &tsdb.TimeSeries{
|
||||
Name: series.Metric.Type,
|
||||
Name: metricName,
|
||||
Points: points,
|
||||
})
|
||||
}
|
||||
|
|
@ -197,7 +204,7 @@ func (e *StackdriverExecutor) createRequest(ctx context.Context, dsInfo *models.
|
|||
|
||||
req, err := http.NewRequest(http.MethodGet, "https://monitoring.googleapis.com/", nil)
|
||||
if err != nil {
|
||||
glog.Info("Failed to create request", "error", err)
|
||||
slog.Info("Failed to create request", "error", err)
|
||||
return nil, fmt.Errorf("Failed to create request. error: %v", err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
package stackdriver
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
|
@ -13,8 +15,9 @@ import (
|
|||
|
||||
func TestStackdriver(t *testing.T) {
|
||||
Convey("Stackdriver", t, func() {
|
||||
executor := &StackdriverExecutor{}
|
||||
|
||||
Convey("Parse query from frontend", func() {
|
||||
executor := &StackdriverExecutor{}
|
||||
fromStart := time.Date(2018, 3, 15, 13, 0, 0, 0, time.UTC).In(time.Local)
|
||||
tsdbQuery := &tsdb.TsdbQuery{
|
||||
TimeRange: &tsdb.TimeRange{
|
||||
|
|
@ -43,5 +46,51 @@ func TestStackdriver(t *testing.T) {
|
|||
So(queries[0].Params["aggregation.perSeriesAligner"][0], ShouldEqual, "ALIGN_NONE")
|
||||
So(queries[0].Params["filter"][0], ShouldEqual, "time_series")
|
||||
})
|
||||
|
||||
Convey("Parse stackdriver response for data aggregated to one time series", func() {
|
||||
var data StackDriverResponse
|
||||
|
||||
jsonBody, err := ioutil.ReadFile("./test-data/1-series-response-agg-one-metric.json")
|
||||
So(err, ShouldBeNil)
|
||||
err = json.Unmarshal(jsonBody, &data)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(data.TimeSeries), ShouldEqual, 1)
|
||||
|
||||
res, err := executor.parseResponse(data, "A")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(len(res.Series), ShouldEqual, 1)
|
||||
So(res.Series[0].Name, ShouldEqual, "serviceruntime.googleapis.com/api/request_count")
|
||||
So(len(res.Series[0].Points), ShouldEqual, 3)
|
||||
|
||||
So(res.Series[0].Points[0][0].Float64, ShouldEqual, 1.0666666666667)
|
||||
So(res.Series[0].Points[1][0].Float64, ShouldEqual, 1.05)
|
||||
So(res.Series[0].Points[2][0].Float64, ShouldEqual, 0.05)
|
||||
})
|
||||
|
||||
Convey("Parse stackdriver response for data with no aggregation", func() {
|
||||
var data StackDriverResponse
|
||||
|
||||
jsonBody, err := ioutil.ReadFile("./test-data/2-series-response-no-agg.json")
|
||||
So(err, ShouldBeNil)
|
||||
err = json.Unmarshal(jsonBody, &data)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(data.TimeSeries), ShouldEqual, 3)
|
||||
|
||||
res, err := executor.parseResponse(data, "A")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Should add labels to metric name", func() {
|
||||
So(len(res.Series), ShouldEqual, 3)
|
||||
So(res.Series[0].Name, ShouldEqual, "compute.googleapis.com/instance/cpu/usage_time collector-asia-east-1")
|
||||
So(res.Series[1].Name, ShouldEqual, "compute.googleapis.com/instance/cpu/usage_time collector-europe-west-1")
|
||||
So(res.Series[2].Name, ShouldEqual, "compute.googleapis.com/instance/cpu/usage_time collector-us-east-1")
|
||||
|
||||
So(len(res.Series[0].Points), ShouldEqual, 3)
|
||||
So(res.Series[0].Points[0][0].Float64, ShouldEqual, 9.7730520330369)
|
||||
So(res.Series[0].Points[1][0].Float64, ShouldEqual, 9.7323568146676)
|
||||
So(res.Series[0].Points[2][0].Float64, ShouldEqual, 9.8566497180145)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"timeSeries": [
|
||||
{
|
||||
"metric": {
|
||||
"type": "serviceruntime.googleapis.com\/api\/request_count"
|
||||
},
|
||||
"resource": {
|
||||
"type": "consumed_api",
|
||||
"labels": {
|
||||
"project_id": "grafana-prod"
|
||||
}
|
||||
},
|
||||
"metricKind": "GAUGE",
|
||||
"valueType": "DOUBLE",
|
||||
"points": [
|
||||
{
|
||||
"interval": {
|
||||
"startTime": "2018-09-11T12:51:00Z",
|
||||
"endTime": "2018-09-11T12:51:00Z"
|
||||
},
|
||||
"value": {
|
||||
"doubleValue": 1.0666666666667
|
||||
}
|
||||
},
|
||||
{
|
||||
"interval": {
|
||||
"startTime": "2018-09-11T12:48:00Z",
|
||||
"endTime": "2018-09-11T12:48:00Z"
|
||||
},
|
||||
"value": {
|
||||
"doubleValue": 1.05
|
||||
}
|
||||
},
|
||||
{
|
||||
"interval": {
|
||||
"startTime": "2018-09-11T12:47:00Z",
|
||||
"endTime": "2018-09-11T12:47:00Z"
|
||||
},
|
||||
"value": {
|
||||
"doubleValue": 0.05
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
{
|
||||
"timeSeries": [
|
||||
{
|
||||
"metric": {
|
||||
"labels": {
|
||||
"instance_name": "collector-asia-east-1"
|
||||
},
|
||||
"type": "compute.googleapis.com\/instance\/cpu\/usage_time"
|
||||
},
|
||||
"resource": {
|
||||
"type": "gce_instance",
|
||||
"labels": {
|
||||
"instance_id": "1119268429530133111",
|
||||
"zone": "asia-east1-a",
|
||||
"project_id": "grafana-prod"
|
||||
}
|
||||
},
|
||||
"metricKind": "DELTA",
|
||||
"valueType": "DOUBLE",
|
||||
"points": [
|
||||
{
|
||||
"interval": {
|
||||
"startTime": "2018-09-11T12:30:00Z",
|
||||
"endTime": "2018-09-11T12:31:00Z"
|
||||
},
|
||||
"value": {
|
||||
"doubleValue": 9.7730520330369
|
||||
}
|
||||
},
|
||||
{
|
||||
"interval": {
|
||||
"startTime": "2018-09-11T12:29:00Z",
|
||||
"endTime": "2018-09-11T12:30:00Z"
|
||||
},
|
||||
"value": {
|
||||
"doubleValue": 9.7323568146676
|
||||
}
|
||||
},
|
||||
{
|
||||
"interval": {
|
||||
"startTime": "2018-09-11T12:28:00Z",
|
||||
"endTime": "2018-09-11T12:29:00Z"
|
||||
},
|
||||
"value": {
|
||||
"doubleValue": 9.8566497180145
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"metric": {
|
||||
"labels": {
|
||||
"instance_name": "collector-europe-west-1"
|
||||
},
|
||||
"type": "compute.googleapis.com\/instance\/cpu\/usage_time"
|
||||
},
|
||||
"resource": {
|
||||
"type": "gce_instance",
|
||||
"labels": {
|
||||
"instance_id": "22241654114540837222",
|
||||
"zone": "europe-west1-b",
|
||||
"project_id": "grafana-prod"
|
||||
}
|
||||
},
|
||||
"metricKind": "DELTA",
|
||||
"valueType": "DOUBLE",
|
||||
"points": [
|
||||
{
|
||||
"interval": {
|
||||
"startTime": "2018-09-11T12:30:00Z",
|
||||
"endTime": "2018-09-11T12:31:00Z"
|
||||
},
|
||||
"value": {
|
||||
"doubleValue": 8.8210971239023
|
||||
}
|
||||
},
|
||||
{
|
||||
"interval": {
|
||||
"startTime": "2018-09-11T12:29:00Z",
|
||||
"endTime": "2018-09-11T12:30:00Z"
|
||||
},
|
||||
"value": {
|
||||
"doubleValue": 8.9689492364414
|
||||
}
|
||||
},
|
||||
{
|
||||
"interval": {
|
||||
"startTime": "2018-09-11T12:28:00Z",
|
||||
"endTime": "2018-09-11T12:29:00Z"
|
||||
},
|
||||
"value": {
|
||||
"doubleValue": 9.0238475054502
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"metric": {
|
||||
"labels": {
|
||||
"instance_name": "collector-us-east-1"
|
||||
},
|
||||
"type": "compute.googleapis.com\/instance\/cpu\/usage_time"
|
||||
},
|
||||
"resource": {
|
||||
"type": "gce_instance",
|
||||
"labels": {
|
||||
"instance_id": "3332264424035095333",
|
||||
"zone": "us-east1-b",
|
||||
"project_id": "grafana-prod"
|
||||
}
|
||||
},
|
||||
"metricKind": "DELTA",
|
||||
"valueType": "DOUBLE",
|
||||
"points": [
|
||||
{
|
||||
"interval": {
|
||||
"startTime": "2018-09-11T12:30:00Z",
|
||||
"endTime": "2018-09-11T12:31:00Z"
|
||||
},
|
||||
"value": {
|
||||
"doubleValue": 30.807846801355
|
||||
}
|
||||
},
|
||||
{
|
||||
"interval": {
|
||||
"startTime": "2018-09-11T12:29:00Z",
|
||||
"endTime": "2018-09-11T12:30:00Z"
|
||||
},
|
||||
"value": {
|
||||
"doubleValue": 30.903974115849
|
||||
}
|
||||
},
|
||||
{
|
||||
"interval": {
|
||||
"startTime": "2018-09-11T12:28:00Z",
|
||||
"endTime": "2018-09-11T12:29:00Z"
|
||||
},
|
||||
"value": {
|
||||
"doubleValue": 30.829426143318
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -14,18 +14,12 @@ type StackdriverQuery struct {
|
|||
type StackDriverResponse struct {
|
||||
TimeSeries []struct {
|
||||
Metric struct {
|
||||
Labels struct {
|
||||
InstanceName string `json:"instance_name"`
|
||||
} `json:"labels"`
|
||||
Type string `json:"type"`
|
||||
Labels map[string]string `json:"labels"`
|
||||
Type string `json:"type"`
|
||||
} `json:"metric"`
|
||||
Resource struct {
|
||||
Type string `json:"type"`
|
||||
Labels struct {
|
||||
InstanceID string `json:"instance_id"`
|
||||
Zone string `json:"zone"`
|
||||
ProjectID string `json:"project_id"`
|
||||
} `json:"labels"`
|
||||
Type string `json:"type"`
|
||||
Labels map[string]string `json:"labels"`
|
||||
} `json:"resource"`
|
||||
MetricKind string `json:"metricKind"`
|
||||
ValueType string `json:"valueType"`
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ export default class StackdriverDatasource {
|
|||
datasourceId: this.id,
|
||||
metricType: `metric.type="${t.metricType}"`,
|
||||
}));
|
||||
|
||||
const result = [];
|
||||
|
||||
try {
|
||||
const { data } = await this.backendSrv.datasourceRequest({
|
||||
url: '/api/tsdb/query',
|
||||
|
|
@ -28,8 +31,6 @@ export default class StackdriverDatasource {
|
|||
},
|
||||
});
|
||||
|
||||
const result = [];
|
||||
|
||||
if (data.results) {
|
||||
Object['values'](data.results).forEach(queryRes => {
|
||||
queryRes.series.forEach(series => {
|
||||
|
|
@ -37,11 +38,11 @@ export default class StackdriverDatasource {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
return { data: result };
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
return { data: result };
|
||||
}
|
||||
|
||||
testDatasource() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue