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

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

commit 1e82b663d9dc7f4f9ecb8133cf0b5bbbde847cd6
Author: kezhenxu94 <kezhenx...@apache.org>
AuthorDate: Wed Oct 13 16:55:45 2021 +0800

    fix: `multiple-linear` command's `labels` type can be string type
---
 .../metrics/linear/multiple-linear-metrics.go      | 37 +++++++++++++++++++---
 pkg/display/graph/dashboard/global.go              | 14 +++-----
 pkg/display/graph/graph.go                         | 10 ++----
 pkg/display/graph/linear/linear.go                 | 32 +++++++++++--------
 pkg/graphql/dashboard/global.go                    | 18 +++++++----
 pkg/graphql/utils/adapter.go                       | 15 ++++-----
 6 files changed, 77 insertions(+), 49 deletions(-)

diff --git a/internal/commands/metrics/linear/multiple-linear-metrics.go 
b/internal/commands/metrics/linear/multiple-linear-metrics.go
index af4a407..8ac636b 100644
--- a/internal/commands/metrics/linear/multiple-linear-metrics.go
+++ b/internal/commands/metrics/linear/multiple-linear-metrics.go
@@ -41,7 +41,11 @@ var Multiple = &cli.Command{
 
 Examples:
 1. Query the global percentiles:
-$ swctl metrics multiple-linear --name all_percentile`,
+$ swctl metrics multiple-linear --name all_percentile
+
+2. Relabel the labels for better readability:
+$ swctl metrics multiple-linear --name all_percentile --labels=0,1,2,3,4 
--relabels=P50,P75,P90,P95,P99
+`,
        Flags: flags.Flags(
                flags.DurationFlags,
                flags.MetricsFlags,
@@ -52,7 +56,13 @@ $ swctl metrics multiple-linear --name all_percentile`,
                                Name:     "labels",
                                Usage:    "the labels you need to query",
                                Required: false,
-                               Value:    "0,1,2,3,4",
+                       },
+               },
+               []cli.Flag{
+                       &cli.StringFlag{
+                               Name:     "relabels",
+                               Usage:    `the new labels to map to the 
original "--labels", must be in same size and is order-sensitive. "labels[i]" 
will be mapped to "relabels[i]"`,
+                               Required: false,
                        },
                },
        ),
@@ -67,7 +77,24 @@ $ swctl metrics multiple-linear --name all_percentile`,
                step := ctx.Generic("step")
 
                metricsName := ctx.String("name")
-               labels := ctx.String("labels")
+               labelsString := ctx.String("labels")
+               relabelsString := ctx.String("relabels")
+
+               labels := strings.Split(labelsString, ",")
+               relabels := strings.Split(relabelsString, ",")
+
+               labelMapping := make(map[string]string)
+               switch {
+               case labelsString == "" && relabelsString != "":
+                       return fmt.Errorf(`"--labels" cannot be empty when 
"--relabels" is given`)
+               case labelsString != "" && relabelsString != "" && len(labels) 
!= len(relabels):
+                       return fmt.Errorf(`"--labels" and "--relabels" must be 
in same size if both specified, but was %v != %v`, len(labels), len(relabels))
+               case relabelsString != "":
+                       for i := 0; i < len(labels); i++ {
+                               labelMapping[labels[i]] = relabels[i]
+                       }
+               }
+
                entity, err := interceptor.ParseEntity(ctx)
                if err != nil {
                        return err
@@ -86,13 +113,13 @@ $ swctl metrics multiple-linear --name all_percentile`,
                metricsValuesArray, err := metrics.MultipleLinearIntValues(ctx, 
api.MetricsCondition{
                        Name:   metricsName,
                        Entity: entity,
-               }, strings.Split(labels, ","), duration)
+               }, labels, duration)
 
                if err != nil {
                        return err
                }
 
-               reshaped := utils.MetricsValuesArrayToMap(duration, 
metricsValuesArray)
+               reshaped := utils.MetricsValuesArrayToMap(duration, 
metricsValuesArray, labelMapping)
                return display.Display(ctx, &displayable.Displayable{Data: 
reshaped})
        },
 }
diff --git a/pkg/display/graph/dashboard/global.go 
b/pkg/display/graph/dashboard/global.go
index 97c1801..6e2be86 100644
--- a/pkg/display/graph/dashboard/global.go
+++ b/pkg/display/graph/dashboard/global.go
@@ -75,16 +75,13 @@ var strToLayoutType = map[string]layoutType{
 // widgets holds the widgets used by the dashboard.
 type widgets struct {
        gauges  []*gauge.MetricColumn
-       linears []*linechart.LineChart
+       linears map[string]*linechart.LineChart
        heatmap *lib.HeatMap
 
        // buttons are used to change the layout.
        buttons []*button.Button
 }
 
-// linearTitles are titles of each line chart, load from the template file.
-var linearTitles []string
-
 // template determines how the global dashboard is displayed.
 var template *dashboard.GlobalTemplate
 
@@ -164,7 +161,7 @@ func gridLayout(lt layoutType) ([]container.Option, error) {
                )
 
        case layoutLineChart:
-               lcElements := linear.LineChartElements(allWidgets.linears, 
linearTitles)
+               lcElements := linear.LineChartElements(allWidgets.linears)
                percentage := int(math.Min(99, 
float64((100-buttonRowHeight)/len(lcElements))))
 
                for _, e := range lcElements {
@@ -200,7 +197,7 @@ func gridLayout(lt layoutType) ([]container.Option, error) {
 // newWidgets creates all widgets used by the dashboard.
 func newWidgets(data *dashboard.GlobalData) error {
        var columns []*gauge.MetricColumn
-       var linears []*linechart.LineChart
+       var linears map[string]*linechart.LineChart
 
        // Create gauges to display global metrics.
        for i := range template.Metrics {
@@ -212,12 +209,12 @@ func newWidgets(data *dashboard.GlobalData) error {
        }
 
        // Create line charts to display global response latency.
-       for _, input := range data.ResponseLatency {
+       for label, input := range data.ResponseLatency {
                l, err := linear.NewLineChart(input)
                if err != nil {
                        return err
                }
-               linears = append(linears, l)
+               linears[label] = l
        }
 
        // Create a heat map.
@@ -253,7 +250,6 @@ func Display(ctx *cli.Context, data *dashboard.GlobalData) 
error {
                return err
        }
        template = te
-       linearTitles = strings.Split(template.ResponseLatency.Labels, ", ")
 
        // Initialization
        allWidgets = &widgets{
diff --git a/pkg/display/graph/graph.go b/pkg/display/graph/graph.go
index 8334048..4f9db13 100644
--- a/pkg/display/graph/graph.go
+++ b/pkg/display/graph/graph.go
@@ -20,7 +20,6 @@ package graph
 import (
        "fmt"
        "reflect"
-       "strings"
 
        api "skywalking.apache.org/repo/goapi/query"
 
@@ -38,7 +37,7 @@ import (
 type (
        Thermodynamic      = api.HeatMap
        LinearMetrics      = map[string]float64
-       MultiLinearMetrics = []LinearMetrics
+       MultiLinearMetrics = map[string]LinearMetrics
        Trace              = api.Trace
        TraceBrief         = api.TraceBrief
        GlobalMetrics      = [][]*api.SelectedRecord
@@ -55,8 +54,6 @@ var (
        GlobalDataType         = reflect.TypeOf(&GlobalData{})
 )
 
-const multipleLinearTitles = "P50, P75, P90, P95, P99"
-
 func Display(ctx *cli.Context, displayable *d.Displayable) error {
        data := displayable.Data
 
@@ -65,12 +62,11 @@ func Display(ctx *cli.Context, displayable *d.Displayable) 
error {
                return heatmap.Display(displayable)
 
        case LinearMetricsType:
-               return linear.Display(ctx, 
[]LinearMetrics{data.(LinearMetrics)}, nil)
+               return linear.Display(ctx, map[string]LinearMetrics{"": 
data.(LinearMetrics)})
 
        case MultiLinearMetricsType:
                inputs := data.(MultiLinearMetrics)
-               titles := strings.Split(multipleLinearTitles, ", 
")[:len(inputs)]
-               return linear.Display(ctx, inputs, titles)
+               return linear.Display(ctx, inputs)
 
        case TraceType:
                return tree.Display(tree.Adapt(data.(Trace)))
diff --git a/pkg/display/graph/linear/linear.go 
b/pkg/display/graph/linear/linear.go
index 5dc443f..0186b4d 100644
--- a/pkg/display/graph/linear/linear.go
+++ b/pkg/display/graph/linear/linear.go
@@ -78,11 +78,21 @@ func processInputs(inputs map[string]float64) (xLabels 
map[int]string, yValues [
 
 // LineChartElements is the part that separated from layout,
 // which can be reused by global dashboard.
-func LineChartElements(lineCharts []*linechart.LineChart, titles []string) 
[][]grid.Element {
+func LineChartElements(lineCharts map[string]*linechart.LineChart) 
[][]grid.Element {
        cols := maxSqrt(len(lineCharts))
 
        rows := make([][]grid.Element, 
int(math.Ceil(float64(len(lineCharts))/float64(cols))))
 
+       var charts []*linechart.LineChart
+       var titles []string
+       for t := range lineCharts {
+               titles = append(titles, t)
+       }
+       sort.Strings(titles)
+       for _, title := range titles {
+               charts = append(charts, lineCharts[title])
+       }
+
        for r := 0; r < len(rows); r++ {
                var row []grid.Element
                for c := 0; c < cols && r*cols+c < len(lineCharts); c++ {
@@ -91,17 +101,13 @@ func LineChartElements(lineCharts []*linechart.LineChart, 
titles []string) [][]g
                                percentage = int(math.Floor(float64(100) / 
float64(len(lineCharts)-r*cols)))
                        }
 
-                       var title string
-                       if titles == nil {
-                               title = fmt.Sprintf("#%v", r*cols+c)
-                       } else {
-                               title = titles[r*cols+c]
-                       }
+                       title := titles[r*cols+c]
+                       chart := charts[r*cols+c]
 
                        row = append(row, grid.ColWidthPerc(
                                int(math.Min(99, float64(percentage))),
                                grid.Widget(
-                                       lineCharts[r*cols+c],
+                                       chart,
                                        container.Border(linestyle.Light),
                                        container.BorderTitleAlignCenter(),
                                        container.BorderTitle(title),
@@ -125,7 +131,7 @@ func layout(rows [][]grid.Element) ([]container.Option, 
error) {
        return builder.Build()
 }
 
-func Display(cliCtx *cli.Context, inputs []map[string]float64, titles 
[]string) error {
+func Display(cliCtx *cli.Context, inputs map[string]map[string]float64) error {
        t, err := termbox.New()
        if err != nil {
                return err
@@ -140,17 +146,17 @@ func Display(cliCtx *cli.Context, inputs 
[]map[string]float64, titles []string)
                return err
        }
 
-       var elements []*linechart.LineChart
+       elements := make(map[string]*linechart.LineChart)
 
-       for _, input := range inputs {
+       for title, input := range inputs {
                w, e := NewLineChart(input)
                if e != nil {
                        return e
                }
-               elements = append(elements, w)
+               elements[title] = w
        }
 
-       gridOpts, err := layout(LineChartElements(elements, titles))
+       gridOpts, err := layout(LineChartElements(elements))
        if err != nil {
                return err
        }
diff --git a/pkg/graphql/dashboard/global.go b/pkg/graphql/dashboard/global.go
index eb0b2fc..3a4fc96 100644
--- a/pkg/graphql/dashboard/global.go
+++ b/pkg/graphql/dashboard/global.go
@@ -65,9 +65,9 @@ type GlobalTemplate struct {
 }
 
 type GlobalData struct {
-       Metrics         [][]*api.SelectedRecord `json:"metrics"`
-       ResponseLatency []map[string]float64    `json:"responseLatency"`
-       HeatMap         api.HeatMap             `json:"heatMap"`
+       Metrics         [][]*api.SelectedRecord       `json:"metrics"`
+       ResponseLatency map[string]map[string]float64 `json:"responseLatency"`
+       HeatMap         api.HeatMap                   `json:"heatMap"`
 }
 
 // Use singleton pattern to make sure to load template only once.
@@ -164,7 +164,7 @@ func Metrics(ctx *cli.Context, duration api.Duration) 
([][]*api.SelectedRecord,
        return ret, nil
 }
 
-func responseLatency(ctx *cli.Context, duration api.Duration) 
[]map[string]float64 {
+func responseLatency(ctx *cli.Context, duration api.Duration) 
map[string]map[string]float64 {
        template, err := LoadTemplate(ctx.String("template"))
        if err != nil {
                return nil
@@ -178,6 +178,7 @@ func responseLatency(ctx *cli.Context, duration 
api.Duration) []map[string]float
        // LabelsIndex in the template file is string type, like "0, 1, 2",
        // need use ", " to split into string array for graphql query.
        labelsIndex := strings.Split(template.ResponseLatency.LabelsIndex, ", ")
+       newLabels := strings.Split(template.ResponseLatency.Labels, ",")
 
        responseLatency, err := metrics.MultipleLinearIntValues(ctx, 
template.ResponseLatency.Condition, labelsIndex, duration)
 
@@ -185,8 +186,13 @@ func responseLatency(ctx *cli.Context, duration 
api.Duration) []map[string]float
                logger.Log.Fatalln(err)
        }
 
+       mapping := make(map[string]string, len(labelsIndex))
+       for i := 0; i < len(labelsIndex); i++ {
+               mapping[labelsIndex[i]] = newLabels[i]
+       }
+
        // Convert metrics values to map type data.
-       return utils.MetricsValuesArrayToMap(duration, responseLatency)
+       return utils.MetricsValuesArrayToMap(duration, responseLatency, mapping)
 }
 
 func heatMap(ctx *cli.Context, duration api.Duration) (api.HeatMap, error) {
@@ -224,7 +230,7 @@ func Global(ctx *cli.Context, duration api.Duration) 
(*GlobalData, error) {
                }
                wg.Done()
        }()
-       var rl []map[string]float64
+       var rl map[string]map[string]float64
        go func() {
                rl = responseLatency(ctx, duration)
                wg.Done()
diff --git a/pkg/graphql/utils/adapter.go b/pkg/graphql/utils/adapter.go
index 129d902..f8af462 100644
--- a/pkg/graphql/utils/adapter.go
+++ b/pkg/graphql/utils/adapter.go
@@ -18,8 +18,6 @@
 package utils
 
 import (
-       "strconv"
-       "strings"
        "time"
 
        api "skywalking.apache.org/repo/goapi/query"
@@ -28,15 +26,14 @@ import (
 )
 
 // MetricsValuesArrayToMap converts Array of MetricsValues into a map that 
uses time as key.
-func MetricsValuesArrayToMap(duration api.Duration, mvArray 
[]api.MetricsValues) []map[string]float64 {
-       ret := make([]map[string]float64, len(mvArray))
+func MetricsValuesArrayToMap(duration api.Duration, mvArray 
[]api.MetricsValues, labelsMap map[string]string) map[string]map[string]float64 
{
+       ret := make(map[string]map[string]float64, len(mvArray))
        for _, mvs := range mvArray {
-               index, err := strconv.Atoi(strings.TrimSpace(*mvs.Label))
-               if err != nil {
-                       logger.Log.Fatalln(err)
-                       return nil
+               label := *mvs.Label
+               if l, ok := labelsMap[label]; ok {
+                       label = l
                }
-               ret[index] = MetricsValuesToMap(duration, mvs)
+               ret[label] = MetricsValuesToMap(duration, mvs)
        }
        return ret
 }

Reply via email to