You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by ke...@apache.org on 2020/03/07 10:24:25 UTC

[skywalking-cli] branch feature/thermodynamic updated (dd20523 -> 80d492d)

This is an automated email from the ASF dual-hosted git repository.

kezhenxu94 pushed a change to branch feature/thermodynamic
in repository https://gitbox.apache.org/repos/asf/skywalking-cli.git.


 discard dd20523  [Feature] Support top N entities and thermodynamic metrics
     new 80d492d  [Feature] Support top N entities and thermodynamic metrics

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (dd20523)
            \
             N -- N -- N   refs/heads/feature/thermodynamic (80d492d)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 README.md | 35 ++++++++++++++++++++++++++++++-----
 1 file changed, 30 insertions(+), 5 deletions(-)


[skywalking-cli] 01/01: [Feature] Support top N entities and thermodynamic metrics

Posted by ke...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kezhenxu94 pushed a commit to branch feature/thermodynamic
in repository https://gitbox.apache.org/repos/asf/skywalking-cli.git

commit 80d492dd34daa720302da88ac518f7f659df802b
Author: kezhenxu94 <ke...@163.com>
AuthorDate: Sat Mar 7 18:20:56 2020 +0800

    [Feature] Support top N entities and thermodynamic metrics
    
    ### Motivation
    
    Support top N entities and thermodynamic metrics commands
    
    ### Result
    
    - Commands `metrics top n` and `thermodynamic` are added
    
    - Closes https://github.com/apache/skywalking/issues/3898
    
    - Closes https://github.com/apache/skywalking/issues/3897
---
 .golangci.yml                                   |   4 +-
 README.md                                       |  78 +++++++++++-
 commands/metrics/aggregation/topn.go            | 112 +++++++++++++++++
 commands/metrics/metrics.go                     |   6 +
 commands/metrics/thermodynamic/thermodynamic.go |  67 ++++++++++
 commands/model/{step.go => order.go}            |  28 ++---
 commands/model/step.go                          |   2 +-
 graphql/aggregation/aggregation.go              | 155 ++++++++++++++++++++++++
 graphql/metrics/metrics.go                      |  18 +++
 9 files changed, 451 insertions(+), 19 deletions(-)

diff --git a/.golangci.yml b/.golangci.yml
index 26b94e2..433731a 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -24,7 +24,7 @@ linters-settings:
   maligned:
     suggest-new: true
   dupl:
-    threshold: 100
+    threshold: 200
   goconst:
     min-len: 2
     min-occurrences: 2
@@ -93,4 +93,4 @@ linters:
 service:
   golangci-lint-version: 1.20.x
   prepare:
-    - echo "here I can run custom commands, but no preparation needed for this repo"
\ No newline at end of file
+    - echo "here I can run custom commands, but no preparation needed for this repo"
diff --git a/README.md b/README.md
index 0467d09..dd1d050 100644
--- a/README.md
+++ b/README.md
@@ -197,6 +197,36 @@ This section covers all the available commands in SkyWalking CLI and their usage
 
 </details>
 
+#### `metrics top <n>`
+
+<details>
+
+<summary>metrics top 3 [--start=start-time] [--end=end-time] --name endpoint_sla [--service-id 3]</summary>
+
+| option | description | default |
+| :--- | :--- | :--- |
+| `--name` | Metrics name, defined in [OAL](https://github.com/apache/skywalking/blob/master/oap-server/server-bootstrap/src/main/resources/official_analysis.oal), such as `service_sla`, etc. |
+| `--service-id` | service ID that are required by the metric type, such as service IDs for `service_sla` |
+| `--start` | See [Common options](#common-options) | See [Common options](#common-options) |
+| `--end` | See [Common options](#common-options) | See [Common options](#common-options) |
+| arguments | the first argument is the number of top entities | `3` |
+
+</details>
+
+#### `metrics thermodynamic`
+
+<details>
+
+<summary>metrics thermodynamic --name=thermodynamic name</summary>
+
+| option | description | default |
+| :--- | :--- | :--- |
+| `--name` | Metrics name, defined in [OAL](https://github.com/apache/skywalking/blob/master/oap-server/server-bootstrap/src/main/resources/official_analysis.oal), such as `service_sla`, etc. |
+| `--start` | See [Common options](#common-options) | See [Common options](#common-options) |
+| `--end` | See [Common options](#common-options) | See [Common options](#common-options) |
+
+</details>
+
 # Use Cases
 
 <details>
@@ -244,7 +274,7 @@ $ ./bin/swctl endpoint ls --service-id=3
 otherwise,
 
 ```shell
-./bin/swctl service ls projectC | jq '.[].id' | xargs ./bin/swctl-latest-darwin-amd64 endpoint ls --service-id 
+./bin/swctl service ls projectC | jq '.[].id' | xargs ./bin/swctl endpoint ls --service-id 
 [{"id":"22","name":"/projectC/{value}"}]
 ```
 
@@ -331,7 +361,7 @@ $ ./bin/swctl service ls projectC | jq '.[0].id' | xargs ./bin/swctl endpoint ls
 <summary>Query multiple metrics values for all percentiles</summary>
 
 ```shell
-$ ./bin/swctl-latest-darwin-amd64 --display=graph --debug metrics multiple-linear --name all_percentile
+$ ./bin/swctl --display=graph --debug metrics multiple-linear --name all_percentile
 
 ┌PRESS Q TO QUIT───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
 │┌───────────────────────────────#0───────────────────────────────┐┌───────────────────────────────#1───────────────────────────────┐┌─────────────────────────────────#2─────────────────────────────────┐│
@@ -395,6 +425,50 @@ $ ./bin/swctl-latest-darwin-amd64 --display=graph --debug metrics multiple-linea
 
 <details>
 
+<summary>Query the top 5 services whose sla is largest</summary>
+
+```shell
+$ ./bin/swctl metrics top 5 --name service_sla        
+[{"name":"projectB","id":"2","value":10000},{"name":"projectC","id":"3","value":10000},{"name":"projectA","id":"4","value":10000},{"name":"projectD","id":"5","value":10000}]
+```
+
+</details>
+
+<details>
+
+<summary>Query the top 5 instances whose sla is largest, of service (id = 3)</summary>
+
+```shell
+$ ./bin/swctl metrics top 5 --name service_instance_sla --service-id 3        
+[{"name":"projectC-pid:30335@skywalking-server-0002","id":"13","value":10000},{"name":"projectC-pid:22037@skywalking-server-0001","id":"2","value":10000}]
+```
+
+</details>
+
+<details>
+
+<summary>Query the top 5 endpoints whose sla is largest, of service (id = 3)</summary>
+
+```shell
+$ ./bin/swctl metrics top 5 --name endpoint_sla --service-id 3        
+[{"name":"/projectC/{value}","id":"4","value":10000}]
+```
+
+</details>
+
+<details>
+
+<summary>Query the overall heatmap</summary>
+
+```shell
+$  ./bin/swctl-latest-darwin-amd64 metrics thermodynamic --name all_heatmap
+{"nodes":[[0,0,238],[0,1,1],[0,2,39],[0,3,31],[0,4,12],[0,5,13],[0,6,4],[0,7,3],[0,8,3],[0,9,0],[0,10,48],[0,11,3],[0,12,49],[0,13,54],[0,14,11],[0,15,9],[0,16,2],[0,17,4],[0,18,0],[0,19,1],[0,20,186],[1,0,264],[1,1,3],[1,2,51],[1,3,38],[1,4,16],[1,5,14],[1,6,3],[1,7,2],[1,8,1],[1,9,2],[1,10,51],[1,11,1],[1,12,41],[1,13,56],[1,14,16],[1,15,15],[1,16,7],[1,17,7],[1,18,3],[1,19,1],[1,20,174],[2,0,231],[2,1,3],[2,2,42],[2,3,41],[2,4,18],[2,5,4],[2,6,2],[2,7,1],[2,8,2],[2,9,0],[2,10,54],[2,1 [...]
+```
+
+</details>
+
+<details>
+
 <summary>Automatically convert to server side timezone</summary>
 
 if your backend nodes are deployed in docker and the timezone is UTC, you may not want to convert your timezone to UTC every time you type a command, `--timezone` comes to your rescue.
diff --git a/commands/metrics/aggregation/topn.go b/commands/metrics/aggregation/topn.go
new file mode 100644
index 0000000..77876f6
--- /dev/null
+++ b/commands/metrics/aggregation/topn.go
@@ -0,0 +1,112 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package aggregation
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+
+	"github.com/apache/skywalking-cli/commands/interceptor"
+
+	"github.com/urfave/cli"
+
+	"github.com/apache/skywalking-cli/commands/flags"
+	"github.com/apache/skywalking-cli/commands/model"
+	"github.com/apache/skywalking-cli/display"
+	"github.com/apache/skywalking-cli/graphql/aggregation"
+	"github.com/apache/skywalking-cli/graphql/schema"
+)
+
+var TopN = cli.Command{
+	Name:      "top",
+	Usage:     "query top `n` entities",
+	ArgsUsage: "<n>",
+	Flags: flags.Flags(
+		flags.DurationFlags,
+		[]cli.Flag{
+			cli.StringFlag{
+				Name:     "name",
+				Usage:    "`metrics name`, which should be defined in OAL script",
+				Required: true,
+			},
+			cli.GenericFlag{
+				Name:  "order",
+				Usage: "the `order` by which the top entities are sorted",
+				Value: &model.OrderEnumValue{
+					Enum:     schema.AllOrder,
+					Default:  schema.OrderDes,
+					Selected: schema.OrderDes,
+				},
+			},
+			cli.StringFlag{
+				Name:     "service-id",
+				Usage:    "the `service id` whose instances/endpoints are to be fetch, if applicable",
+				Required: false,
+			},
+		},
+	),
+	Before: interceptor.BeforeChain([]cli.BeforeFunc{
+		interceptor.TimezoneInterceptor,
+		interceptor.DurationInterceptor,
+	}),
+	Action: func(ctx *cli.Context) error {
+		name := ctx.String("name")
+		start := ctx.String("start")
+		end := ctx.String("end")
+		step := ctx.Generic("step").(*model.StepEnumValue).Selected
+		order := ctx.Generic("order").(*model.OrderEnumValue).Selected
+		serviceID := ctx.String("service-id")
+
+		topN := 5
+
+		if ctx.NArg() > 0 {
+			nn, err := strconv.Atoi(ctx.Args().First())
+			if err != nil {
+				return fmt.Errorf("the 1st argument must be a number")
+			}
+			topN = nn
+		}
+
+		duration := schema.Duration{
+			Start: start,
+			End:   end,
+			Step:  step,
+		}
+
+		var metricsValues []schema.TopNEntity
+
+		if strings.HasPrefix(name, "service_instance") {
+			if serviceID == "" {
+				metricsValues = aggregation.AllServiceInstanceTopN(ctx, name, topN, duration, order)
+			} else {
+				metricsValues = aggregation.ServiceInstanceTopN(ctx, serviceID, name, topN, duration, order)
+			}
+		} else if strings.HasPrefix(name, "endpoint_") {
+			if serviceID == "" {
+				metricsValues = aggregation.AllEndpointTopN(ctx, name, topN, duration, order)
+			} else {
+				metricsValues = aggregation.EndpointTopN(ctx, serviceID, name, topN, duration, order)
+			}
+		} else if strings.HasPrefix(name, "service_") {
+			metricsValues = aggregation.ServiceTopN(ctx, name, topN, duration, order)
+		}
+
+		return display.Display(ctx, metricsValues)
+	},
+}
diff --git a/commands/metrics/metrics.go b/commands/metrics/metrics.go
index 8f941b9..d1b4a8f 100644
--- a/commands/metrics/metrics.go
+++ b/commands/metrics/metrics.go
@@ -20,6 +20,10 @@ package metrics
 import (
 	"github.com/urfave/cli"
 
+	"github.com/apache/skywalking-cli/commands/metrics/aggregation"
+
+	"github.com/apache/skywalking-cli/commands/metrics/thermodynamic"
+
 	"github.com/apache/skywalking-cli/commands/metrics/linear"
 	"github.com/apache/skywalking-cli/commands/metrics/single"
 )
@@ -31,5 +35,7 @@ var Command = cli.Command{
 		single.Command,
 		linear.Single,
 		linear.Multiple,
+		thermodynamic.Command,
+		aggregation.TopN,
 	},
 }
diff --git a/commands/metrics/thermodynamic/thermodynamic.go b/commands/metrics/thermodynamic/thermodynamic.go
new file mode 100644
index 0000000..5eefb3a
--- /dev/null
+++ b/commands/metrics/thermodynamic/thermodynamic.go
@@ -0,0 +1,67 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package thermodynamic
+
+import (
+	"github.com/urfave/cli"
+
+	"github.com/apache/skywalking-cli/commands/flags"
+	"github.com/apache/skywalking-cli/commands/interceptor"
+	"github.com/apache/skywalking-cli/commands/model"
+	"github.com/apache/skywalking-cli/display"
+	"github.com/apache/skywalking-cli/graphql/metrics"
+	"github.com/apache/skywalking-cli/graphql/schema"
+)
+
+var Command = cli.Command{
+	Name:      "thermodynamic",
+	ShortName: "td",
+	Usage:     "Query thermodynamic metrics defined in backend OAL",
+	Flags: flags.Flags(
+		flags.DurationFlags,
+		[]cli.Flag{
+			cli.StringFlag{
+				Name:     "name",
+				Usage:    "metrics `NAME`, which should be defined in OAL script",
+				Required: true,
+			},
+		},
+	),
+	Before: interceptor.BeforeChain([]cli.BeforeFunc{
+		interceptor.TimezoneInterceptor,
+		interceptor.DurationInterceptor,
+	}),
+	Action: func(ctx *cli.Context) error {
+		end := ctx.String("end")
+		start := ctx.String("start")
+		step := ctx.Generic("step")
+		metricsName := ctx.String("name")
+
+		duration := schema.Duration{
+			Start: start,
+			End:   end,
+			Step:  step.(*model.StepEnumValue).Selected,
+		}
+
+		metricsValues := metrics.Thermodynamic(ctx, schema.MetricCondition{
+			Name: metricsName,
+		}, duration)
+
+		return display.Display(ctx, metricsValues)
+	},
+}
diff --git a/commands/model/step.go b/commands/model/order.go
similarity index 63%
copy from commands/model/step.go
copy to commands/model/order.go
index 719799d..77a20ba 100644
--- a/commands/model/step.go
+++ b/commands/model/order.go
@@ -24,29 +24,29 @@ import (
 	"github.com/apache/skywalking-cli/graphql/schema"
 )
 
-// StepEnumValue defines the values domain of --step option
-type StepEnumValue struct {
-	Enum     []schema.Step
-	Default  schema.Step
-	Selected schema.Step
+// OrderEnumValue defines the values domain of --order option
+type OrderEnumValue struct {
+	Enum     []schema.Order
+	Default  schema.Order
+	Selected schema.Order
 }
 
-// Set the --step value, from raw string to StepEnumValue
-func (s *StepEnumValue) Set(value string) error {
+// Set the --order value, from raw string to OrderEnumValue
+func (s *OrderEnumValue) Set(value string) error {
 	for _, enum := range s.Enum {
-		if enum.String() == value {
+		if strings.EqualFold(enum.String(), value) {
 			s.Selected = enum
 			return nil
 		}
 	}
-	steps := make([]string, len(schema.AllStep))
-	for i, step := range schema.AllStep {
-		steps[i] = step.String()
+	orders := make([]string, len(schema.AllOrder))
+	for i, order := range schema.AllOrder {
+		orders[i] = order.String()
 	}
-	return fmt.Errorf("allowed steps are %s", strings.Join(steps, ", "))
+	return fmt.Errorf("allowed orders are %s", strings.Join(orders, ", "))
 }
 
-// String representation of the step
-func (s StepEnumValue) String() string {
+// String representation of the order
+func (s OrderEnumValue) String() string {
 	return s.Selected.String()
 }
diff --git a/commands/model/step.go b/commands/model/step.go
index 719799d..8f363be 100644
--- a/commands/model/step.go
+++ b/commands/model/step.go
@@ -34,7 +34,7 @@ type StepEnumValue struct {
 // Set the --step value, from raw string to StepEnumValue
 func (s *StepEnumValue) Set(value string) error {
 	for _, enum := range s.Enum {
-		if enum.String() == value {
+		if strings.EqualFold(enum.String(), value) {
 			s.Selected = enum
 			return nil
 		}
diff --git a/graphql/aggregation/aggregation.go b/graphql/aggregation/aggregation.go
new file mode 100644
index 0000000..fc11392
--- /dev/null
+++ b/graphql/aggregation/aggregation.go
@@ -0,0 +1,155 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package aggregation
+
+import (
+	"github.com/machinebox/graphql"
+	"github.com/urfave/cli"
+
+	"github.com/apache/skywalking-cli/graphql/client"
+	"github.com/apache/skywalking-cli/graphql/schema"
+)
+
+func ServiceTopN(ctx *cli.Context, name string, topN int, duration schema.Duration, order schema.Order) []schema.TopNEntity {
+	var response map[string][]schema.TopNEntity
+
+	request := graphql.NewRequest(`
+		query ($name: String!, $topN: Int!, $duration: Duration!, $order: Order!) {
+			result: getServiceTopN(
+				duration: $duration,
+				name: $name,
+				topN: $topN,
+				order: $order
+			) {
+				id name value
+			}
+		}
+	`)
+	request.Var("name", name)
+	request.Var("topN", topN)
+	request.Var("duration", duration)
+	request.Var("order", order)
+
+	client.ExecuteQueryOrFail(ctx, request, &response)
+
+	return response["result"]
+}
+
+func AllServiceInstanceTopN(ctx *cli.Context, name string, topN int, duration schema.Duration, order schema.Order) []schema.TopNEntity {
+	var response map[string][]schema.TopNEntity
+
+	request := graphql.NewRequest(`
+		query ($name: String!, $topN: Int!, $duration: Duration!, $order: Order!) {
+			result: getAllServiceInstanceTopN(
+				duration: $duration,
+				name: $name,
+				topN: $topN,
+				order: $order
+			) {
+				id name value
+			}
+		}
+	`)
+	request.Var("name", name)
+	request.Var("topN", topN)
+	request.Var("duration", duration)
+	request.Var("order", order)
+
+	client.ExecuteQueryOrFail(ctx, request, &response)
+
+	return response["result"]
+}
+
+func ServiceInstanceTopN(ctx *cli.Context, serviceID, name string, topN int, duration schema.Duration, order schema.Order) []schema.TopNEntity {
+	var response map[string][]schema.TopNEntity
+
+	request := graphql.NewRequest(`
+		query ($serviceId: ID!, $name: String!, $topN: Int!, $duration: Duration!, $order: Order!) {
+			result: getServiceInstanceTopN(
+				serviceId: $serviceId,
+				duration: $duration,
+				name: $name,
+				topN: $topN,
+				order: $order
+			) {
+				id name value
+			}
+		}
+	`)
+	request.Var("serviceId", serviceID)
+	request.Var("name", name)
+	request.Var("topN", topN)
+	request.Var("duration", duration)
+	request.Var("order", order)
+
+	client.ExecuteQueryOrFail(ctx, request, &response)
+
+	return response["result"]
+}
+
+func AllEndpointTopN(ctx *cli.Context, name string, topN int, duration schema.Duration, order schema.Order) []schema.TopNEntity {
+	var response map[string][]schema.TopNEntity
+
+	request := graphql.NewRequest(`
+		query ($name: String!, $topN: Int!, $duration: Duration!, $order: Order!) {
+			result: getAllEndpointTopN(
+				duration: $duration,
+				name: $name,
+				topN: $topN,
+				order: $order
+			) {
+				id name value
+			}
+		}
+	`)
+	request.Var("name", name)
+	request.Var("topN", topN)
+	request.Var("duration", duration)
+	request.Var("order", order)
+
+	client.ExecuteQueryOrFail(ctx, request, &response)
+
+	return response["result"]
+}
+
+func EndpointTopN(ctx *cli.Context, serviceID, name string, topN int, duration schema.Duration, order schema.Order) []schema.TopNEntity {
+	var response map[string][]schema.TopNEntity
+
+	request := graphql.NewRequest(`
+		query ($serviceId: ID!, $name: String!, $topN: Int!, $duration: Duration!, $order: Order!) {
+			result: getEndpointTopN(
+				serviceId: $serviceId,
+				duration: $duration,
+				name: $name,
+				topN: $topN,
+				order: $order
+			) {
+				id name value
+			}
+		}
+	`)
+	request.Var("serviceId", serviceID)
+	request.Var("name", name)
+	request.Var("topN", topN)
+	request.Var("duration", duration)
+	request.Var("order", order)
+
+	client.ExecuteQueryOrFail(ctx, request, &response)
+
+	return response["result"]
+}
diff --git a/graphql/metrics/metrics.go b/graphql/metrics/metrics.go
index c086e51..68cf36d 100644
--- a/graphql/metrics/metrics.go
+++ b/graphql/metrics/metrics.go
@@ -80,3 +80,21 @@ func MultipleLinearIntValues(ctx *cli.Context, condition schema.MetricCondition,
 
 	return response["metrics"]
 }
+
+func Thermodynamic(ctx *cli.Context, condition schema.MetricCondition, duration schema.Duration) schema.Thermodynamic {
+	request := graphql.NewRequest(`
+		query ($metric: MetricCondition!, $duration: Duration!) {
+			metrics: getThermodynamic(metric: $metric, duration: $duration) {
+				nodes responseTimeStep: axisYStep
+			}
+		}
+	`)
+	request.Var("metric", condition)
+	request.Var("duration", duration)
+
+	var response map[string]schema.Thermodynamic
+
+	client.ExecuteQueryOrFail(ctx, request, &response)
+
+	return response["metrics"]
+}