Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions assets/templates/dashboard/global.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ responseLatency:
entity:
scope: "All"
normal: true
labels: "P50, P75, P90, P95, P99"
labelsIndex: "0, 1, 2, 3, 4"
relabels: "P50,P75,P90,P95,P99"
labels: "0,1,2,3,4"
title: "Global Response Latency"
unit: "percentile in ms"

Expand All @@ -89,4 +89,4 @@ heatMap:
scope: "All"
normal: true
title: "Global Heatmap"
unit: "ms"
unit: "ms"
6 changes: 3 additions & 3 deletions examples/global.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ responseLatency:
entity:
scope: "All"
normal: true
labels: "P50, P75, P90, P95, P99"
labelsIndex: "0, 1, 2, 3, 4"
relabels: "P50, P75, P90, P95, P99"
labels: "0,1,2,3,4"
title: "Global Response Latency"
unit: "percentile in ms"

Expand All @@ -89,4 +89,4 @@ heatMap:
scope: "All"
normal: true
title: "Global Heatmap"
unit: "ms"
unit: "ms"
38 changes: 33 additions & 5 deletions internal/commands/metrics/linear/multiple-linear-metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -52,7 +56,14 @@ $ 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,
},
},
),
Expand All @@ -67,7 +78,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
Expand All @@ -86,13 +114,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})
},
}
14 changes: 5 additions & 9 deletions pkg/display/graph/dashboard/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
linears := make(map[string]*linechart.LineChart)

// Create gauges to display global metrics.
for i := range template.Metrics {
Expand All @@ -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.
Expand Down Expand Up @@ -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{
Expand Down
10 changes: 3 additions & 7 deletions pkg/display/graph/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ package graph
import (
"fmt"
"reflect"
"strings"

api "skywalking.apache.org/repo/goapi/query"

Expand All @@ -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
Expand All @@ -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

Expand All @@ -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)))
Expand Down
32 changes: 19 additions & 13 deletions pkg/display/graph/linear/linear.go
Original file line number Diff line number Diff line change
Expand Up @@ -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++ {
Expand All @@ -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),
Expand All @@ -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
Expand All @@ -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
}
Expand Down
34 changes: 20 additions & 14 deletions pkg/graphql/dashboard/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ type MetricTemplate struct {
}

type ChartTemplate struct {
Condition api.MetricsCondition `mapstructure:"condition"`
Title string `mapstructure:"title"`
Unit string `mapstructure:"unit"`
Labels string `mapstructure:"labels"`
LabelsIndex string `mapstructure:"labelsIndex"`
Condition api.MetricsCondition `mapstructure:"condition"`
Title string `mapstructure:"title"`
Unit string `mapstructure:"unit"`
Relabels string `mapstructure:"relabels"`
Labels string `mapstructure:"labels"`
}

type GlobalTemplate struct {
Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -175,18 +175,24 @@ func responseLatency(ctx *cli.Context, duration api.Duration) []map[string]float
return nil
}

// LabelsIndex in the template file is string type, like "0, 1, 2",
// Labels 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, ", ")
labels := strings.Split(template.ResponseLatency.Labels, ",")
relabels := strings.Split(template.ResponseLatency.Relabels, ",")

responseLatency, err := metrics.MultipleLinearIntValues(ctx, template.ResponseLatency.Condition, labelsIndex, duration)
responseLatency, err := metrics.MultipleLinearIntValues(ctx, template.ResponseLatency.Condition, labels, duration)

if err != nil {
logger.Log.Fatalln(err)
}

mapping := make(map[string]string, len(labels))
for i := 0; i < len(labels); i++ {
mapping[labels[i]] = relabels[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) {
Expand Down Expand Up @@ -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()
Expand Down
15 changes: 6 additions & 9 deletions pkg/graphql/utils/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
package utils

import (
"strconv"
"strings"
"time"

api "skywalking.apache.org/repo/goapi/query"
Expand All @@ -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
}
Expand Down
Loading