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/06 10:01:10 UTC
[skywalking-cli] 01/01: [Feature] Support multiple linear metrics
and enhance Ascii Graph Display
This is an automated email from the ASF dual-hosted git repository.
kezhenxu94 pushed a commit to branch feature/linear-metrics
in repository https://gitbox.apache.org/repos/asf/skywalking-cli.git
commit e697a78653eb8b2d83ffdb015839de9662e0ad03
Author: kezhenxu94 <ke...@163.com>
AuthorDate: Fri Mar 6 18:00:53 2020 +0800
[Feature] Support multiple linear metrics and enhance Ascii Graph Display
### Motivation
Adopt the new API of multiple linear metrics, https://github.com/apache/skywalking/pull/4214
### Modification
- Rewrite the pxx metrics with the new API
- Slightly refactor the GraphQL client into individual package, according to the query protocol
- Enhance the Ascii Graph display style
### Result
- CLI is compatible with the latest backend
- Ascii Graph can display multiple charts in one screen
---
.golangci.yml | 2 +-
commands/endpoint/list.go | 5 +-
commands/instance/instance.go | 5 +-
commands/instance/list.go | 5 +-
commands/instance/search.go | 5 +-
commands/interceptor/duration.go | 12 +-
commands/metrics/linear/linear-metrics.go | 51 +++++--
commands/metrics/single/single-metrics.go | 7 +-
commands/service/list.go | 7 +-
display/display.go | 8 +-
display/graph/graph.go | 14 +-
display/graph/linear/linear.go | 82 +++++++----
graphql/client/client.go | 150 +--------------------
graphql/metadata/metadata.go | 93 ++++++++++++-
graphql/metrics/metrics.go | 64 +++++++++
graphql/{schema => utils}/constants.go | 32 +++--
display/graph/graph.go => graphql/utils/strings.go | 22 +--
17 files changed, 329 insertions(+), 235 deletions(-)
diff --git a/.golangci.yml b/.golangci.yml
index cebf66b..26b94e2 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -38,7 +38,7 @@ linters-settings:
misspell:
locale: US
lll:
- line-length: 120
+ line-length: 150
goimports:
local-prefixes: github.com/apache/skywalking-cli
gocritic:
diff --git a/commands/endpoint/list.go b/commands/endpoint/list.go
index 51ea320..034c6a5 100644
--- a/commands/endpoint/list.go
+++ b/commands/endpoint/list.go
@@ -20,8 +20,9 @@ package endpoint
import (
"github.com/urfave/cli"
+ "github.com/apache/skywalking-cli/graphql/metadata"
+
"github.com/apache/skywalking-cli/display"
- "github.com/apache/skywalking-cli/graphql/client"
)
var ListCommand = cli.Command{
@@ -53,7 +54,7 @@ var ListCommand = cli.Command{
limit := ctx.Int("limit")
keyword := ctx.String("keyword")
- endpoints := client.SearchEndpoints(ctx, serviceID, keyword, limit)
+ endpoints := metadata.SearchEndpoints(ctx, serviceID, keyword, limit)
return display.Display(ctx, endpoints)
},
diff --git a/commands/instance/instance.go b/commands/instance/instance.go
index da83c80..29c86a7 100644
--- a/commands/instance/instance.go
+++ b/commands/instance/instance.go
@@ -20,7 +20,8 @@ package instance
import (
"github.com/urfave/cli"
- "github.com/apache/skywalking-cli/graphql/client"
+ "github.com/apache/skywalking-cli/graphql/metadata"
+
"github.com/apache/skywalking-cli/logger"
)
@@ -43,7 +44,7 @@ func verifyAndSwitchServiceParameter(ctx *cli.Context) string {
}
if serviceID == "" && serviceName != "" {
- service, err := client.SearchService(ctx, serviceName)
+ service, err := metadata.SearchService(ctx, serviceName)
if err != nil {
logger.Log.Fatalln(err)
}
diff --git a/commands/instance/list.go b/commands/instance/list.go
index c20ccb4..eda72c1 100644
--- a/commands/instance/list.go
+++ b/commands/instance/list.go
@@ -20,11 +20,12 @@ package instance
import (
"github.com/urfave/cli"
+ "github.com/apache/skywalking-cli/graphql/metadata"
+
"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/client"
"github.com/apache/skywalking-cli/graphql/schema"
)
@@ -44,7 +45,7 @@ var ListCommand = cli.Command{
start := ctx.String("start")
step := ctx.Generic("step")
- instances := client.Instances(ctx, serviceID, schema.Duration{
+ instances := metadata.Instances(ctx, serviceID, schema.Duration{
Start: start,
End: end,
Step: step.(*model.StepEnumValue).Selected,
diff --git a/commands/instance/search.go b/commands/instance/search.go
index b9e2ac9..b97adae 100644
--- a/commands/instance/search.go
+++ b/commands/instance/search.go
@@ -20,13 +20,14 @@ package instance
import (
"regexp"
+ "github.com/apache/skywalking-cli/graphql/metadata"
+
"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/client"
"github.com/apache/skywalking-cli/graphql/schema"
)
@@ -47,7 +48,7 @@ var SearchCommand = cli.Command{
regex := ctx.String("regex")
- instances := client.Instances(ctx, serviceID, schema.Duration{
+ instances := metadata.Instances(ctx, serviceID, schema.Duration{
Start: start,
End: end,
Step: step.(*model.StepEnumValue).Selected,
diff --git a/commands/interceptor/duration.go b/commands/interceptor/duration.go
index 3eb355a..c52ae69 100644
--- a/commands/interceptor/duration.go
+++ b/commands/interceptor/duration.go
@@ -21,6 +21,8 @@ import (
"strconv"
"time"
+ "github.com/apache/skywalking-cli/graphql/utils"
+
"github.com/urfave/cli"
"github.com/apache/skywalking-cli/graphql/schema"
@@ -29,7 +31,7 @@ import (
func tryParseTime(unparsed string) (schema.Step, time.Time, error) {
var possibleError error = nil
- for step, layout := range schema.StepFormats {
+ for step, layout := range utils.StepFormats {
t, err := time.Parse(layout, unparsed)
if err == nil {
return step, t, nil
@@ -48,9 +50,9 @@ func DurationInterceptor(ctx *cli.Context) error {
startTime, endTime, step := ParseDuration(start, end, timezone)
- if err := ctx.Set("start", startTime.Format(schema.StepFormats[step])); err != nil {
+ if err := ctx.Set("start", startTime.Format(utils.StepFormats[step])); err != nil {
return err
- } else if err := ctx.Set("end", endTime.Format(schema.StepFormats[step])); err != nil {
+ } else if err := ctx.Set("end", endTime.Format(utils.StepFormats[step])); err != nil {
return err
} else if err := ctx.Set("step", step.String()); err != nil {
return err
@@ -103,12 +105,12 @@ func ParseDuration(start, end, timezone string) (startTime, endTime time.Time, s
if step, startTime, err = tryParseTime(start); err != nil {
logger.Log.Fatalln("Unsupported time format:", start, err)
}
- return startTime, startTime.Add(30 * schema.StepDuration[step]), step
+ return startTime, startTime.Add(30 * utils.StepDuration[step]), step
} else { // start is absent
if step, endTime, err = tryParseTime(end); err != nil {
logger.Log.Fatalln("Unsupported time format:", end, err)
}
- return endTime.Add(-30 * schema.StepDuration[step]), endTime, step
+ return endTime.Add(-30 * utils.StepDuration[step]), endTime, step
}
}
diff --git a/commands/metrics/linear/linear-metrics.go b/commands/metrics/linear/linear-metrics.go
index ceda447..ba88527 100644
--- a/commands/metrics/linear/linear-metrics.go
+++ b/commands/metrics/linear/linear-metrics.go
@@ -18,13 +18,19 @@
package linear
import (
+ "time"
+
"github.com/urfave/cli"
+ "github.com/apache/skywalking-cli/graphql/utils"
+ "github.com/apache/skywalking-cli/logger"
+
+ "github.com/apache/skywalking-cli/graphql/metrics"
+
"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/client"
"github.com/apache/skywalking-cli/graphql/schema"
)
@@ -36,7 +42,7 @@ var Command = cli.Command{
[]cli.Flag{
cli.StringFlag{
Name: "name",
- Usage: "metrics `NAME`, such as `all_p99`",
+ Usage: "metrics `NAME`, such as `all_percentile`",
Required: true,
},
cli.StringFlag{
@@ -44,6 +50,12 @@ var Command = cli.Command{
Usage: "`ID`, the related id if the metrics requires one",
Required: false,
},
+ cli.IntFlag{
+ Name: "num",
+ Usage: "`num`, the number of linear metrics to query, (default: 5)",
+ Required: false,
+ Value: 5,
+ },
},
),
Before: interceptor.BeforeChain([]cli.BeforeFunc{
@@ -55,6 +67,7 @@ var Command = cli.Command{
start := ctx.String("start")
step := ctx.Generic("step")
metricsName := ctx.String("name")
+ numOfLinear := ctx.Int("num")
var id *string = nil
@@ -62,15 +75,37 @@ var Command = cli.Command{
id = &idString
}
- metricsValues := client.LinearIntValues(ctx, schema.MetricCondition{
- Name: metricsName,
- ID: id,
- }, schema.Duration{
+ duration := schema.Duration{
Start: start,
End: end,
Step: step.(*model.StepEnumValue).Selected,
- })
+ }
- return display.Display(ctx, metricsValues)
+ values := metrics.MultipleLinearIntValues(ctx, schema.MetricCondition{
+ Name: metricsName,
+ ID: id,
+ }, numOfLinear, duration)
+
+ reshaped := make([]map[string]float64, len(values))
+
+ for index, value := range values {
+ reshaped[index] = metricsToMap(duration, value.Values)
+ }
+
+ return display.Display(ctx, reshaped)
},
}
+
+func metricsToMap(duration schema.Duration, kvInts []*schema.KVInt) map[string]float64 {
+ values := map[string]float64{}
+ format := utils.StepFormats[duration.Step]
+ startTime, err := time.Parse(format, duration.Start)
+ if err != nil {
+ logger.Log.Fatalln(err)
+ }
+ step := utils.StepDuration[duration.Step]
+ for idx, value := range kvInts {
+ values[startTime.Add(time.Duration(idx)*step).Format(format)] = float64(value.Value)
+ }
+ return values
+}
diff --git a/commands/metrics/single/single-metrics.go b/commands/metrics/single/single-metrics.go
index 99817da..3f04d92 100644
--- a/commands/metrics/single/single-metrics.go
+++ b/commands/metrics/single/single-metrics.go
@@ -20,13 +20,14 @@ package single
import (
"strings"
+ "github.com/apache/skywalking-cli/graphql/metrics"
+
"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/client"
"github.com/apache/skywalking-cli/graphql/schema"
)
@@ -65,7 +66,7 @@ var Command = cli.Command{
ids = append(ids, strings.Split(id, ",")...)
}
- metricsValues := client.IntValues(ctx, schema.BatchMetricConditions{
+ metricsValues := metrics.IntValues(ctx, schema.BatchMetricConditions{
Name: metricsName,
Ids: ids,
}, schema.Duration{
@@ -74,6 +75,6 @@ var Command = cli.Command{
Step: step.(*model.StepEnumValue).Selected,
})
- return display.Display(ctx, metricsValues)
+ return display.Display(ctx, metricsValues.Values)
},
}
diff --git a/commands/service/list.go b/commands/service/list.go
index 8400a47..2604a6f 100644
--- a/commands/service/list.go
+++ b/commands/service/list.go
@@ -20,11 +20,12 @@ package service
import (
"github.com/urfave/cli"
+ "github.com/apache/skywalking-cli/graphql/metadata"
+
"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/client"
"github.com/apache/skywalking-cli/graphql/schema"
)
@@ -47,13 +48,13 @@ var ListCommand = cli.Command{
var services []schema.Service
if args := ctx.Args(); len(args) == 0 {
- services = client.Services(ctx, schema.Duration{
+ services = metadata.AllServices(ctx, schema.Duration{
Start: start,
End: end,
Step: step.(*model.StepEnumValue).Selected,
})
} else {
- service, _ := client.SearchService(ctx, args.First())
+ service, _ := metadata.SearchService(ctx, args.First())
services = []schema.Service{service}
}
diff --git a/display/display.go b/display/display.go
index 48be6ab..e620673 100644
--- a/display/display.go
+++ b/display/display.go
@@ -31,10 +31,10 @@ import (
)
const (
- JSON string = "json"
- YAML string = "yaml"
- TABLE string = "table"
- GRAPH string = "graph"
+ JSON = "json"
+ YAML = "yaml"
+ TABLE = "table"
+ GRAPH = "graph"
)
// Display the object in the style specified in flag --display
diff --git a/display/graph/graph.go b/display/graph/graph.go
index 7184360..c27f835 100644
--- a/display/graph/graph.go
+++ b/display/graph/graph.go
@@ -25,11 +25,17 @@ import (
)
func Display(object interface{}) error {
- if reflect.TypeOf(object) != reflect.TypeOf(map[string]float64{}) {
- return fmt.Errorf("type of %T is not supported to be displayed as ascii graph", reflect.TypeOf(object))
+ if reflect.TypeOf(object) == reflect.TypeOf(map[string]float64{}) {
+ kvs := []map[string]float64{object.(map[string]float64)}
+
+ return linear.Display(kvs)
}
- kvs := object.(map[string]float64)
+ if reflect.TypeOf(object) == reflect.TypeOf([]map[string]float64{}) {
+ kvs := object.([]map[string]float64)
+
+ return linear.Display(kvs)
+ }
- return linear.Display(kvs)
+ return fmt.Errorf("type of %T is not supported to be displayed as ascii graph", reflect.TypeOf(object))
}
diff --git a/display/graph/linear/linear.go b/display/graph/linear/linear.go
index b6e6d07..c632112 100644
--- a/display/graph/linear/linear.go
+++ b/display/graph/linear/linear.go
@@ -19,14 +19,15 @@ package linear
import (
"context"
+ "fmt"
+ "math"
"strings"
- "github.com/mum4k/termdash/widgetapi"
+ "github.com/mum4k/termdash/linestyle"
"github.com/mum4k/termdash"
"github.com/mum4k/termdash/container"
"github.com/mum4k/termdash/container/grid"
- "github.com/mum4k/termdash/linestyle"
"github.com/mum4k/termdash/terminal/termbox"
"github.com/mum4k/termdash/terminal/terminalapi"
"github.com/mum4k/termdash/widgets/linechart"
@@ -34,20 +35,19 @@ import (
const RootID = "root"
-func newWidgets(inputs map[string]float64) (lineChart *linechart.LineChart, err error) {
+func newLineChart(inputs map[string]float64) (lineChart *linechart.LineChart, err error) {
index := 0
xLabels := map[int]string{}
- var yValues []float64
+ yValues := make([]float64, len(inputs))
+
for xLabel, yValue := range inputs {
xLabels[index] = xLabel
+ yValues[index] = yValue
index++
- yValues = append(yValues, yValue)
}
- if lineChart, err = linechart.New(
- linechart.YAxisAdaptive(),
- ); err != nil {
+ if lineChart, err = linechart.New(linechart.YAxisAdaptive()); err != nil {
return
}
@@ -56,21 +56,42 @@ func newWidgets(inputs map[string]float64) (lineChart *linechart.LineChart, err
return lineChart, err
}
-func gridLayout(lineChart widgetapi.Widget) ([]container.Option, error) {
- widget := grid.Widget(
- lineChart,
- container.Border(linestyle.Light),
- container.BorderTitleAlignCenter(),
- container.BorderTitle("Press q to quit"),
- )
+func layout(lineCharts ...*linechart.LineChart) ([]container.Option, error) {
+ cols := maxSqrt(len(lineCharts))
+
+ rows := make([][]grid.Element, int(math.Ceil(float64(len(lineCharts))/float64(cols))))
+
+ for r := 0; r < len(rows); r++ {
+ var row []grid.Element
+ for c := 0; c < cols && r*cols+c < len(lineCharts); c++ {
+ percentage := int(math.Floor(float64(100) / float64(cols)))
+ if r == len(rows)-1 {
+ percentage = int(math.Floor(float64(100) / float64(len(lineCharts)-r*cols)))
+ }
+ row = append(row, grid.ColWidthPerc(
+ int(math.Min(99, float64(percentage))),
+ grid.Widget(
+ lineCharts[r*cols+c],
+ container.Border(linestyle.Light),
+ container.BorderTitleAlignCenter(),
+ container.BorderTitle(fmt.Sprintf("#%v", r*cols+c)),
+ ),
+ ))
+ }
+ rows[r] = row
+ }
builder := grid.New()
- builder.Add(widget)
+
+ for _, row := range rows {
+ percentage := int(math.Min(99, float64(100/len(rows))))
+ builder.Add(grid.RowHeightPerc(percentage, row...))
+ }
return builder.Build()
}
-func Display(inputs map[string]float64) error {
+func Display(inputs []map[string]float64) error {
t, err := termbox.New()
if err != nil {
return err
@@ -80,26 +101,31 @@ func Display(inputs map[string]float64) error {
c, err := container.New(
t,
container.ID(RootID),
- container.PaddingTop(2),
- container.PaddingRight(2),
- container.PaddingBottom(2),
- container.PaddingLeft(2),
)
if err != nil {
return err
}
- w, err := newWidgets(inputs)
- if err != nil {
- return err
+ var elements []*linechart.LineChart
+
+ for _, input := range inputs {
+ w, e := newLineChart(input)
+ if e != nil {
+ return e
+ }
+ elements = append(elements, w)
}
- gridOpts, err := gridLayout(w)
+ gridOpts, err := layout(elements...)
if err != nil {
return err
}
- err = c.Update(RootID, gridOpts...)
+ err = c.Update(RootID, append(
+ gridOpts,
+ container.Border(linestyle.Light),
+ container.BorderTitle("PRESS Q TO QUIT"))...,
+ )
if err != nil {
return err
@@ -116,3 +142,7 @@ func Display(inputs map[string]float64) error {
return err
}
+
+func maxSqrt(num int) int {
+ return int(math.Ceil(math.Sqrt(float64(num))))
+}
diff --git a/graphql/client/client.go b/graphql/client/client.go
index a0766ef..a14f2f8 100644
--- a/graphql/client/client.go
+++ b/graphql/client/client.go
@@ -19,13 +19,10 @@ package client
import (
"context"
- "fmt"
- "time"
"github.com/machinebox/graphql"
"github.com/urfave/cli"
- "github.com/apache/skywalking-cli/graphql/schema"
"github.com/apache/skywalking-cli/logger"
)
@@ -37,6 +34,7 @@ func newClient(cliCtx *cli.Context) (client *graphql.Client) {
return
}
+// ExecuteQuery executes the `request` and parse to the `response`, returning `error` if there is any.
func ExecuteQuery(cliCtx *cli.Context, request *graphql.Request, response interface{}) error {
client := newClient(cliCtx)
ctx := context.Background()
@@ -44,151 +42,9 @@ func ExecuteQuery(cliCtx *cli.Context, request *graphql.Request, response interf
return err
}
+// ExecuteQuery executes the `request` and parse to the `response`, panic if there is any `error`.
func ExecuteQueryOrFail(cliCtx *cli.Context, request *graphql.Request, response interface{}) {
- client := newClient(cliCtx)
- ctx := context.Background()
- if err := client.Run(ctx, request, response); err != nil {
- logger.Log.Fatalln(err)
- }
-}
-
-func Services(cliCtx *cli.Context, duration schema.Duration) []schema.Service {
- var response map[string][]schema.Service
- request := graphql.NewRequest(`
- query ($duration: Duration!) {
- services: getAllServices(duration: $duration) {
- id name
- }
- }
- `)
- request.Var("duration", duration)
-
- ExecuteQueryOrFail(cliCtx, request, &response)
- return response["services"]
-}
-
-func SearchEndpoints(cliCtx *cli.Context, serviceID, keyword string, limit int) []schema.Endpoint {
- var response map[string][]schema.Endpoint
- request := graphql.NewRequest(`
- query ($keyword: String!, $serviceId: ID!, $limit: Int!) {
- endpoints: searchEndpoint(keyword: $keyword, serviceId: $serviceId, limit: $limit) {
- id name
- }
- }
- `)
- request.Var("serviceId", serviceID)
- request.Var("keyword", keyword)
- request.Var("limit", limit)
-
- ExecuteQueryOrFail(cliCtx, request, &response)
- return response["endpoints"]
-}
-
-func GetEndpointInfo(cliCtx *cli.Context, endpointID string) schema.Endpoint {
- var response map[string]schema.Endpoint
- request := graphql.NewRequest(`
- query ($endpointId: ID!) {
- endpoint: getEndpointInfo(endpointId: $endpointId) {
- id name
- }
- }
- `)
- request.Var("endpointId", endpointID)
-
- ExecuteQueryOrFail(cliCtx, request, &response)
- return response["endpoint"]
-}
-
-func Instances(cliCtx *cli.Context, serviceID string, duration schema.Duration) []schema.ServiceInstance {
- var response map[string][]schema.ServiceInstance
- request := graphql.NewRequest(`
- query ($serviceId: ID!, $duration: Duration!) {
- instances: getServiceInstances(duration: $duration, serviceId: $serviceId) {
- id
- name
- language
- instanceUUID
- attributes {
- name
- value
- }
- }
- }
- `)
- request.Var("serviceId", serviceID)
- request.Var("duration", duration)
-
- ExecuteQueryOrFail(cliCtx, request, &response)
- return response["instances"]
-}
-
-func SearchService(cliCtx *cli.Context, serviceCode string) (service schema.Service, err error) {
- var response map[string]schema.Service
- request := graphql.NewRequest(`
- query searchService($serviceCode: String!) {
- service: searchService(serviceCode: $serviceCode) {
- id name
- }
- }
- `)
- request.Var("serviceCode", serviceCode)
-
- ExecuteQueryOrFail(cliCtx, request, &response)
- service = response["service"]
- if service.ID == "" {
- return service, fmt.Errorf("no such service [%s]", serviceCode)
- }
- return service, nil
-}
-
-func LinearIntValues(ctx *cli.Context, condition schema.MetricCondition, duration schema.Duration) map[string]float64 {
- var response map[string]schema.IntValues
-
- request := graphql.NewRequest(`
- query ($metric: MetricCondition!, $duration: Duration!) {
- metrics: getLinearIntValues(metric: $metric, duration: $duration) {
- values { value }
- }
- }
- `)
- request.Var("metric", condition)
- request.Var("duration", duration)
-
- ExecuteQueryOrFail(ctx, request, &response)
-
- values := metricsToMap(duration, response["metrics"].Values)
-
- return values
-}
-
-func IntValues(ctx *cli.Context, condition schema.BatchMetricConditions, duration schema.Duration) []*schema.KVInt {
- var response map[string]schema.IntValues
-
- request := graphql.NewRequest(`
- query ($metric: BatchMetricConditions!, $duration: Duration!) {
- metrics: getValues(metric: $metric, duration: $duration) {
- values { id value }
- }
- }
- `)
- request.Var("metric", condition)
- request.Var("duration", duration)
-
- ExecuteQueryOrFail(ctx, request, &response)
-
- return response["metrics"].Values
-}
-
-func metricsToMap(duration schema.Duration, kvInts []*schema.KVInt) map[string]float64 {
- values := map[string]float64{}
- format := schema.StepFormats[duration.Step]
- startTime, err := time.Parse(format, duration.Start)
- if err != nil {
+ if err := ExecuteQuery(cliCtx, request, response); err != nil {
logger.Log.Fatalln(err)
}
- step := schema.StepDuration[duration.Step]
- for idx, value := range kvInts {
- values[startTime.Add(time.Duration(idx)*step).Format(format)] = float64(value.Value)
- }
- return values
}
diff --git a/graphql/metadata/metadata.go b/graphql/metadata/metadata.go
index 55a1bc7..93b6875 100644
--- a/graphql/metadata/metadata.go
+++ b/graphql/metadata/metadata.go
@@ -18,6 +18,8 @@
package metadata
import (
+ "fmt"
+
"github.com/machinebox/graphql"
"github.com/urfave/cli"
@@ -25,7 +27,97 @@ import (
"github.com/apache/skywalking-cli/graphql/schema"
)
+func AllServices(cliCtx *cli.Context, duration schema.Duration) []schema.Service {
+ var response map[string][]schema.Service
+ request := graphql.NewRequest(`
+ query ($duration: Duration!) {
+ services: getAllServices(duration: $duration) {
+ id name
+ }
+ }
+ `)
+ request.Var("duration", duration)
+
+ client.ExecuteQueryOrFail(cliCtx, request, &response)
+ return response["services"]
+}
+
+func SearchService(cliCtx *cli.Context, serviceCode string) (service schema.Service, err error) {
+ var response map[string]schema.Service
+ request := graphql.NewRequest(`
+ query searchService($serviceCode: String!) {
+ service: searchService(serviceCode: $serviceCode) {
+ id name
+ }
+ }
+ `)
+ request.Var("serviceCode", serviceCode)
+
+ client.ExecuteQueryOrFail(cliCtx, request, &response)
+ service = response["service"]
+ if service.ID == "" {
+ return service, fmt.Errorf("no such service [%s]", serviceCode)
+ }
+ return service, nil
+}
+
+func SearchEndpoints(cliCtx *cli.Context, serviceID, keyword string, limit int) []schema.Endpoint {
+ var response map[string][]schema.Endpoint
+ request := graphql.NewRequest(`
+ query ($keyword: String!, $serviceId: ID!, $limit: Int!) {
+ endpoints: searchEndpoint(keyword: $keyword, serviceId: $serviceId, limit: $limit) {
+ id name
+ }
+ }
+ `)
+ request.Var("serviceId", serviceID)
+ request.Var("keyword", keyword)
+ request.Var("limit", limit)
+
+ client.ExecuteQueryOrFail(cliCtx, request, &response)
+ return response["endpoints"]
+}
+
+func EndpointInfo(cliCtx *cli.Context, endpointID string) schema.Endpoint {
+ var response map[string]schema.Endpoint
+ request := graphql.NewRequest(`
+ query ($endpointId: ID!) {
+ endpoint: getEndpointInfo(endpointId: $endpointId) {
+ id name
+ }
+ }
+ `)
+ request.Var("endpointId", endpointID)
+
+ client.ExecuteQueryOrFail(cliCtx, request, &response)
+ return response["endpoint"]
+}
+
+func Instances(cliCtx *cli.Context, serviceID string, duration schema.Duration) []schema.ServiceInstance {
+ var response map[string][]schema.ServiceInstance
+ request := graphql.NewRequest(`
+ query ($serviceId: ID!, $duration: Duration!) {
+ instances: getServiceInstances(duration: $duration, serviceId: $serviceId) {
+ id
+ name
+ language
+ instanceUUID
+ attributes {
+ name
+ value
+ }
+ }
+ }
+ `)
+ request.Var("serviceId", serviceID)
+ request.Var("duration", duration)
+
+ client.ExecuteQueryOrFail(cliCtx, request, &response)
+ return response["instances"]
+}
+
func ServerTimeInfo(cliCtx *cli.Context) (schema.TimeInfo, error) {
+ var response map[string]schema.TimeInfo
request := graphql.NewRequest(`
query {
timeInfo: getTimeInfo {
@@ -34,7 +126,6 @@ func ServerTimeInfo(cliCtx *cli.Context) (schema.TimeInfo, error) {
}
`)
- var response map[string]schema.TimeInfo
if err := client.ExecuteQuery(cliCtx, request, &response); err != nil {
return schema.TimeInfo{}, err
}
diff --git a/graphql/metrics/metrics.go b/graphql/metrics/metrics.go
new file mode 100644
index 0000000..36187d1
--- /dev/null
+++ b/graphql/metrics/metrics.go
@@ -0,0 +1,64 @@
+// 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 metrics
+
+import (
+ "github.com/machinebox/graphql"
+ "github.com/urfave/cli"
+
+ "github.com/apache/skywalking-cli/graphql/client"
+
+ "github.com/apache/skywalking-cli/graphql/schema"
+)
+
+func IntValues(ctx *cli.Context, condition schema.BatchMetricConditions, duration schema.Duration) schema.IntValues {
+ var response map[string]schema.IntValues
+
+ request := graphql.NewRequest(`
+ query ($metric: BatchMetricConditions!, $duration: Duration!) {
+ metrics: getValues(metric: $metric, duration: $duration) {
+ values { id value }
+ }
+ }
+ `)
+ request.Var("metric", condition)
+ request.Var("duration", duration)
+
+ client.ExecuteQueryOrFail(ctx, request, &response)
+
+ return response["metrics"]
+}
+
+func MultipleLinearIntValues(ctx *cli.Context, condition schema.MetricCondition, numOfLinear int, duration schema.Duration) []schema.IntValues {
+ request := graphql.NewRequest(`
+ query ($metric: MetricCondition!, $numOfLinear: Int!, $duration: Duration!) {
+ metrics: getMultipleLinearIntValues(metric: $metric, numOfLinear: $numOfLinear, duration: $duration) {
+ values { value }
+ }
+ }
+ `)
+ request.Var("metric", condition)
+ request.Var("numOfLinear", numOfLinear)
+ request.Var("duration", duration)
+
+ var response map[string][]schema.IntValues
+
+ client.ExecuteQueryOrFail(ctx, request, &response)
+
+ return response["metrics"]
+}
diff --git a/graphql/schema/constants.go b/graphql/utils/constants.go
similarity index 64%
rename from graphql/schema/constants.go
rename to graphql/utils/constants.go
index f146338..b4f0f3d 100644
--- a/graphql/schema/constants.go
+++ b/graphql/utils/constants.go
@@ -15,24 +15,28 @@
// specific language governing permissions and limitations
// under the License.
-package schema
+package utils
-import "time"
+import (
+ "time"
+
+ "github.com/apache/skywalking-cli/graphql/schema"
+)
// StepFormats is a mapping from schema.Step to its time format
-var StepFormats = map[Step]string{
- StepSecond: "2006-01-02 150400",
- StepMinute: "2006-01-02 1504",
- StepHour: "2006-01-02 15",
- StepDay: "2006-01-02",
- StepMonth: "2006-01",
+var StepFormats = map[schema.Step]string{
+ schema.StepSecond: "2006-01-02 150400",
+ schema.StepMinute: "2006-01-02 1504",
+ schema.StepHour: "2006-01-02 15",
+ schema.StepDay: "2006-01-02",
+ schema.StepMonth: "2006-01",
}
// StepDuration is a mapping from schema.Step to its time.Duration
-var StepDuration = map[Step]time.Duration{
- StepSecond: time.Second,
- StepMinute: time.Minute,
- StepHour: time.Hour,
- StepDay: time.Hour * 24,
- StepMonth: time.Hour * 24 * 30,
+var StepDuration = map[schema.Step]time.Duration{
+ schema.StepSecond: time.Second,
+ schema.StepMinute: time.Minute,
+ schema.StepHour: time.Hour,
+ schema.StepDay: time.Hour * 24,
+ schema.StepMonth: time.Hour * 24 * 30,
}
diff --git a/display/graph/graph.go b/graphql/utils/strings.go
similarity index 69%
copy from display/graph/graph.go
copy to graphql/utils/strings.go
index 7184360..9e61143 100644
--- a/display/graph/graph.go
+++ b/graphql/utils/strings.go
@@ -15,21 +15,21 @@
// specific language governing permissions and limitations
// under the License.
-package graph
+package utils
import (
- "fmt"
- "reflect"
+ "encoding/json"
- "github.com/apache/skywalking-cli/display/graph/linear"
+ "github.com/apache/skywalking-cli/graphql/schema"
+ "github.com/apache/skywalking-cli/logger"
)
-func Display(object interface{}) error {
- if reflect.TypeOf(object) != reflect.TypeOf(map[string]float64{}) {
- return fmt.Errorf("type of %T is not supported to be displayed as ascii graph", reflect.TypeOf(object))
- }
-
- kvs := object.(map[string]float64)
+type IntValues schema.IntValues
- return linear.Display(kvs)
+func (intValues *IntValues) String() string {
+ bytes, err := json.Marshal(intValues.Values)
+ if err != nil {
+ logger.Log.Fatalln(err)
+ }
+ return string(bytes)
}