From 54d0db04418ee6fe0f4c2d850560e0f141b4ebd8 Mon Sep 17 00:00:00 2001 From: Paul Bellamy Date: Mon, 18 Jan 2016 11:33:25 +0000 Subject: [PATCH] templatize metric rendering and shorten column names --- render/detailed/metrics.go | 139 ++++++++++---------------------- render/detailed/metrics_test.go | 12 +-- render/detailed/node_test.go | 8 +- 3 files changed, 52 insertions(+), 107 deletions(-) diff --git a/render/detailed/metrics.go b/render/detailed/metrics.go index 2a110d077..c023f3862 100644 --- a/render/detailed/metrics.go +++ b/render/detailed/metrics.go @@ -16,6 +16,24 @@ const ( percentFormat = "percent" ) +var ( + processNodeMetrics = renderMetrics( + MetricRow{ID: process.CPUUsage, Label: "CPU", Format: percentFormat}, + MetricRow{ID: process.MemoryUsage, Label: "Memory", Format: filesizeFormat}, + ) + containerNodeMetrics = renderMetrics( + MetricRow{ID: docker.CPUTotalUsage, Label: "CPU", Format: percentFormat}, + MetricRow{ID: docker.MemoryUsage, Label: "Memory", Format: filesizeFormat}, + ) + hostNodeMetrics = renderMetrics( + MetricRow{ID: host.CPUUsage, Label: "CPU", Format: percentFormat}, + MetricRow{ID: host.MemUsage, Label: "Memory", Format: filesizeFormat}, + MetricRow{ID: host.Load1, Label: "Load (1m)", Format: defaultFormat, Group: "load"}, + MetricRow{ID: host.Load5, Label: "Load (5m)", Format: defaultFormat, Group: "load"}, + MetricRow{ID: host.Load15, Label: "Load (15m)", Format: defaultFormat, Group: "load"}, + ) +) + // MetricRow is a tuple of data used to render a metric as a sparkline and // accoutrements. type MetricRow struct { @@ -29,15 +47,18 @@ type MetricRow struct { // Copy returns a value copy of the MetricRow func (m MetricRow) Copy() MetricRow { - metric := m.Metric.Copy() - return MetricRow{ + row := MetricRow{ ID: m.ID, Label: m.Label, Format: m.Format, Group: m.Group, Value: m.Value, - Metric: &metric, } + if m.Metric != nil { + var metric = m.Metric.Copy() + row.Metric = &metric + } + return row } // MarshalJSON marshals this MetricRow to json. It takes the basic Metric @@ -60,27 +81,6 @@ func (m MetricRow) MarshalJSON() ([]byte, error) { }) } -func metricRow(id, label string, metric report.Metric, format, group string) MetricRow { - var last float64 - if s := metric.LastSample(); s != nil { - last = s.Value - } - return MetricRow{ - ID: id, - Label: label, - Format: format, - Group: group, - Value: toFixed(last, 2), - Metric: &metric, - } -} - -// toFixed truncates decimals of float64 down to specified precision -func toFixed(num float64, precision int) float64 { - output := math.Pow(10, float64(precision)) - return float64(int64(num*output)) / output -} - // NodeMetrics produces a table (to be consumed directly by the UI) based on // an origin ID, which is (optimistically) a node ID in one of our topologies. func NodeMetrics(n report.Node) []MetricRow { @@ -95,82 +95,27 @@ func NodeMetrics(n report.Node) []MetricRow { return nil } -func processNodeMetrics(nmd report.Node) []MetricRow { - rows := []MetricRow{} - for _, tuple := range []struct { - ID, Label, fmt string - }{ - {process.CPUUsage, "CPU Usage", percentFormat}, - {process.MemoryUsage, "Memory Usage", filesizeFormat}, - } { - if val, ok := nmd.Metrics[tuple.ID]; ok { - rows = append(rows, metricRow( - tuple.ID, - tuple.Label, - val, - tuple.fmt, - "", - )) - } - } - return rows -} - -func containerNodeMetrics(nmd report.Node) []MetricRow { - rows := []MetricRow{} - if val, ok := nmd.Metrics[docker.CPUTotalUsage]; ok { - rows = append(rows, metricRow( - docker.CPUTotalUsage, - "CPU Usage", - val, - percentFormat, - "", - )) - } - if val, ok := nmd.Metrics[docker.MemoryUsage]; ok { - rows = append(rows, metricRow( - docker.MemoryUsage, - "Memory Usage", - val, - filesizeFormat, - "", - )) - } - return rows -} - -func hostNodeMetrics(nmd report.Node) []MetricRow { - // Ensure that all metrics have the same max - maxLoad := 0.0 - for _, id := range []string{host.Load1, host.Load5, host.Load15} { - if metric, ok := nmd.Metrics[id]; ok { - if metric.Len() == 0 { +func renderMetrics(templates ...MetricRow) func(report.Node) []MetricRow { + return func(n report.Node) []MetricRow { + rows := []MetricRow{} + for _, template := range templates { + metric, ok := n.Metrics[template.ID] + if !ok { continue } - if metric.Max > maxLoad { - maxLoad = metric.Max + t := template.Copy() + if s := metric.LastSample(); s != nil { + t.Value = toFixed(s.Value, 2) } + t.Metric = &metric + rows = append(rows, t) } + return rows } - - rows := []MetricRow{} - for _, tuple := range []struct{ ID, Label, fmt string }{ - {host.CPUUsage, "CPU Usage", percentFormat}, - {host.MemUsage, "Memory Usage", filesizeFormat}, - } { - if val, ok := nmd.Metrics[tuple.ID]; ok { - rows = append(rows, metricRow(tuple.ID, tuple.Label, val, tuple.fmt, "")) - } - } - for _, tuple := range []struct{ ID, Label string }{ - {host.Load1, "Load (1m)"}, - {host.Load5, "Load (5m)"}, - {host.Load15, "Load (15m)"}, - } { - if val, ok := nmd.Metrics[tuple.ID]; ok { - val.Max = maxLoad - rows = append(rows, metricRow(tuple.ID, tuple.Label, val, defaultFormat, "load")) - } - } - return rows +} + +// toFixed truncates decimals of float64 down to specified precision +func toFixed(num float64, precision int) float64 { + output := math.Pow(10, float64(precision)) + return float64(int64(num*output)) / output } diff --git a/render/detailed/metrics_test.go b/render/detailed/metrics_test.go index f61c8c5f4..a199ee0ca 100644 --- a/render/detailed/metrics_test.go +++ b/render/detailed/metrics_test.go @@ -25,7 +25,7 @@ func TestNodeMetrics(t *testing.T) { want: []detailed.MetricRow{ { ID: process.CPUUsage, - Label: "CPU Usage", + Label: "CPU", Format: "percent", Group: "", Value: 0.01, @@ -33,7 +33,7 @@ func TestNodeMetrics(t *testing.T) { }, { ID: process.MemoryUsage, - Label: "Memory Usage", + Label: "Memory", Format: "filesize", Group: "", Value: 0.01, @@ -47,7 +47,7 @@ func TestNodeMetrics(t *testing.T) { want: []detailed.MetricRow{ { ID: docker.CPUTotalUsage, - Label: "CPU Usage", + Label: "CPU", Format: "percent", Group: "", Value: 0.01, @@ -55,7 +55,7 @@ func TestNodeMetrics(t *testing.T) { }, { ID: docker.MemoryUsage, - Label: "Memory Usage", + Label: "Memory", Format: "filesize", Group: "", Value: 0.01, @@ -69,7 +69,7 @@ func TestNodeMetrics(t *testing.T) { want: []detailed.MetricRow{ { ID: host.CPUUsage, - Label: "CPU Usage", + Label: "CPU", Format: "percent", Group: "", Value: 0.01, @@ -77,7 +77,7 @@ func TestNodeMetrics(t *testing.T) { }, { ID: host.MemUsage, - Label: "Memory Usage", + Label: "Memory", Format: "filesize", Group: "", Value: 0.01, diff --git a/render/detailed/node_test.go b/render/detailed/node_test.go index 04051fdc9..2cd49bf68 100644 --- a/render/detailed/node_test.go +++ b/render/detailed/node_test.go @@ -51,14 +51,14 @@ func TestMakeDetailedHostNode(t *testing.T) { { ID: host.CPUUsage, Format: "percent", - Label: "CPU Usage", + Label: "CPU", Value: 0.01, Metric: &fixture.CPUMetric, }, { ID: host.MemUsage, Format: "filesize", - Label: "Memory Usage", + Label: "Memory", Value: 0.01, Metric: &fixture.MemoryMetric, }, @@ -136,14 +136,14 @@ func TestMakeDetailedContainerNode(t *testing.T) { { ID: docker.CPUTotalUsage, Format: "percent", - Label: "CPU Usage", + Label: "CPU", Value: 0.01, Metric: &fixture.CPUMetric, }, { ID: docker.MemoryUsage, Format: "filesize", - Label: "Memory Usage", + Label: "Memory", Value: 0.01, Metric: &fixture.MemoryMetric, },