From e31520dddd6204e70744b0abac843bf858c81bb0 Mon Sep 17 00:00:00 2001 From: Paul Bellamy Date: Wed, 20 Jan 2016 15:33:16 +0000 Subject: [PATCH] refactor detailed key label rendering into a single dictionary --- render/detailed/labels.go | 58 +++++++++++++++++++++++ render/detailed/metadata.go | 80 ++++++++++++++++++-------------- render/detailed/metadata_test.go | 7 ++- render/detailed/metrics.go | 22 ++++----- render/detailed/metrics_test.go | 9 ---- render/detailed/node_test.go | 26 ++++------- 6 files changed, 125 insertions(+), 77 deletions(-) create mode 100644 render/detailed/labels.go diff --git a/render/detailed/labels.go b/render/detailed/labels.go new file mode 100644 index 000000000..f40ab7961 --- /dev/null +++ b/render/detailed/labels.go @@ -0,0 +1,58 @@ +package detailed + +import ( + "fmt" + "strings" + + "github.com/weaveworks/scope/probe/docker" + "github.com/weaveworks/scope/probe/host" + "github.com/weaveworks/scope/probe/kubernetes" + "github.com/weaveworks/scope/probe/overlay" + "github.com/weaveworks/scope/probe/process" +) + +var labels = map[string]string{ + docker.CPUTotalUsage: "CPU", + docker.ContainerCommand: "Command", + docker.ContainerCreated: "Created", + docker.ContainerHostname: "Hostname", + docker.ContainerID: "ID", + docker.ContainerIPs: "IPs", + docker.ContainerPorts: "Ports", + docker.ContainerState: "State", + docker.ImageID: "Image ID", + docker.MemoryUsage: "Memory", + host.CPUUsage: "CPU", + host.HostName: "Hostname", + host.KernelVersion: "Kernel version", + host.Load15: "Load (15m)", + host.Load1: "Load (1m)", + host.Load5: "Load (5m)", + host.LocalNetworks: "Local Networks", + host.MemUsage: "Memory", + host.OS: "Operating system", + host.Uptime: "Uptime", + kubernetes.Namespace: "Namespace", + kubernetes.PodCreated: "Created", + kubernetes.PodID: "ID", + overlay.WeaveDNSHostname: "Weave DNS Hostname", + overlay.WeaveMACAddress: "Weave MAC", + // process.CPUUsage: "CPU", // Duplicate key! + process.Cmdline: "Command", + process.MemoryUsage: "Memory", + process.PID: "PID", + process.PPID: "Parent PID", + process.Threads: "# Threads", +} + +// Label maps from the internal keys to the human-readable label for a piece +// of metadata/set/etc. If none is found the raw key will be returned. +func Label(key string) string { + if label, ok := labels[key]; ok { + return label + } + if strings.HasPrefix(key, "label_") { + return fmt.Sprintf("Label %q", strings.TrimPrefix(key, "label_")) + } + return key +} diff --git a/render/detailed/metadata.go b/render/detailed/metadata.go index 55ae0c09d..c5efada4c 100644 --- a/render/detailed/metadata.go +++ b/render/detailed/metadata.go @@ -1,7 +1,7 @@ package detailed import ( - "fmt" + "encoding/json" "sort" "strings" @@ -15,57 +15,69 @@ import ( var ( processNodeMetadata = renderMetadata( - meta(process.PID, "PID"), - meta(process.PPID, "Parent PID"), - meta(process.Cmdline, "Command"), - meta(process.Threads, "# Threads"), + meta(process.PID), + meta(process.PPID), + meta(process.Cmdline), + meta(process.Threads), ) containerNodeMetadata = renderMetadata( - meta(docker.ContainerID, "ID"), - meta(docker.ImageID, "Image ID"), - ltst(docker.ContainerState, "State"), - sets(docker.ContainerIPs, "IPs"), - sets(docker.ContainerPorts, "Ports"), - meta(docker.ContainerCreated, "Created"), - meta(docker.ContainerCommand, "Command"), - meta(overlay.WeaveMACAddress, "Weave MAC"), - meta(overlay.WeaveDNSHostname, "Weave DNS Hostname"), + meta(docker.ContainerID), + meta(docker.ImageID), + ltst(docker.ContainerState), + sets(docker.ContainerIPs), + sets(docker.ContainerPorts), + meta(docker.ContainerCreated), + meta(docker.ContainerCommand), + meta(overlay.WeaveMACAddress), + meta(overlay.WeaveDNSHostname), getDockerLabelRows, ) containerImageNodeMetadata = renderMetadata( - meta(docker.ImageID, "Image ID"), + meta(docker.ImageID), getDockerLabelRows, ) podNodeMetadata = renderMetadata( - meta(kubernetes.PodID, "ID"), - meta(kubernetes.Namespace, "Namespace"), - meta(kubernetes.PodCreated, "Created"), + meta(kubernetes.PodID), + meta(kubernetes.Namespace), + meta(kubernetes.PodCreated), ) hostNodeMetadata = renderMetadata( - meta(host.HostName, "Hostname"), - meta(host.OS, "Operating system"), - meta(host.KernelVersion, "Kernel version"), - meta(host.Uptime, "Uptime"), - sets(host.LocalNetworks, "Local Networks"), + meta(host.HostName), + meta(host.OS), + meta(host.KernelVersion), + meta(host.Uptime), + sets(host.LocalNetworks), ) ) // MetadataRow is a row for the metadata table. type MetadataRow struct { - ID string `json:"id"` - Label string `json:"label"` - Value string `json:"value"` + ID string + Value string } // Copy returns a value copy of a metadata row. func (m MetadataRow) Copy() MetadataRow { return MetadataRow{ ID: m.ID, - Label: m.Label, Value: m.Value, } } +// MarshalJSON marshals this MetadataRow to json. It adds a label before +// rendering. +func (m MetadataRow) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + ID string `json:"id"` + Label string `json:"label"` + Value string `json:"value"` + }{ + ID: m.ID, + Label: Label(m.ID), + Value: m.Value, + }) +} + // NodeMetadata 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 NodeMetadata(n report.Node) []MetadataRow { @@ -92,28 +104,28 @@ func renderMetadata(templates ...func(report.Node) []MetadataRow) func(report.No } } -func meta(id, label string) func(report.Node) []MetadataRow { +func meta(id string) func(report.Node) []MetadataRow { return func(n report.Node) []MetadataRow { if val, ok := n.Metadata[id]; ok { - return []MetadataRow{{ID: id, Label: label, Value: val}} + return []MetadataRow{{ID: id, Value: val}} } return nil } } -func sets(id, label string) func(report.Node) []MetadataRow { +func sets(id string) func(report.Node) []MetadataRow { return func(n report.Node) []MetadataRow { if val, ok := n.Sets[id]; ok && len(val) > 0 { - return []MetadataRow{{ID: id, Label: label, Value: strings.Join(val, ", ")}} + return []MetadataRow{{ID: id, Value: strings.Join(val, ", ")}} } return nil } } -func ltst(id, label string) func(report.Node) []MetadataRow { +func ltst(id string) func(report.Node) []MetadataRow { return func(n report.Node) []MetadataRow { if val, ok := n.Latest.Lookup(id); ok { - return []MetadataRow{{ID: id, Label: label, Value: val}} + return []MetadataRow{{ID: id, Value: val}} } return nil } @@ -129,7 +141,7 @@ func getDockerLabelRows(nmd report.Node) []MetadataRow { } sort.Strings(labelKeys) for _, labelKey := range labelKeys { - rows = append(rows, MetadataRow{ID: "label_" + labelKey, Label: fmt.Sprintf("Label %q", labelKey), Value: labels[labelKey]}) + rows = append(rows, MetadataRow{ID: "label_" + labelKey, Value: labels[labelKey]}) } return rows } diff --git a/render/detailed/metadata_test.go b/render/detailed/metadata_test.go index 9d2622a06..e79f8b4cf 100644 --- a/render/detailed/metadata_test.go +++ b/render/detailed/metadata_test.go @@ -26,12 +26,11 @@ func TestNodeMetadata(t *testing.T) { docker.ContainerIPs: report.MakeStringSet("10.10.10.0/24", "10.10.10.1/24"), }).WithLatest(docker.ContainerState, fixture.Now, docker.StateRunning), want: []detailed.MetadataRow{ - {ID: docker.ContainerID, Label: "ID", Value: fixture.ClientContainerID}, - {ID: docker.ContainerState, Label: "State", Value: "running"}, - {ID: docker.ContainerIPs, Label: "IPs", Value: "10.10.10.0/24, 10.10.10.1/24"}, + {ID: docker.ContainerID, Value: fixture.ClientContainerID}, + {ID: docker.ContainerState, Value: "running"}, + {ID: docker.ContainerIPs, Value: "10.10.10.0/24, 10.10.10.1/24"}, { ID: "label_label1", - Label: "Label \"label1\"", Value: "label1value", }, }, diff --git a/render/detailed/metrics.go b/render/detailed/metrics.go index c023f3862..81e3cd4f3 100644 --- a/render/detailed/metrics.go +++ b/render/detailed/metrics.go @@ -18,19 +18,19 @@ const ( var ( processNodeMetrics = renderMetrics( - MetricRow{ID: process.CPUUsage, Label: "CPU", Format: percentFormat}, - MetricRow{ID: process.MemoryUsage, Label: "Memory", Format: filesizeFormat}, + MetricRow{ID: process.CPUUsage, Format: percentFormat}, + MetricRow{ID: process.MemoryUsage, Format: filesizeFormat}, ) containerNodeMetrics = renderMetrics( - MetricRow{ID: docker.CPUTotalUsage, Label: "CPU", Format: percentFormat}, - MetricRow{ID: docker.MemoryUsage, Label: "Memory", Format: filesizeFormat}, + MetricRow{ID: docker.CPUTotalUsage, Format: percentFormat}, + MetricRow{ID: docker.MemoryUsage, 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{ID: host.CPUUsage, Format: percentFormat}, + MetricRow{ID: host.MemUsage, Format: filesizeFormat}, + MetricRow{ID: host.Load1, Format: defaultFormat, Group: "load"}, + MetricRow{ID: host.Load5, Format: defaultFormat, Group: "load"}, + MetricRow{ID: host.Load15, Format: defaultFormat, Group: "load"}, ) ) @@ -38,7 +38,6 @@ var ( // accoutrements. type MetricRow struct { ID string - Label string Format string Group string Value float64 @@ -49,7 +48,6 @@ type MetricRow struct { func (m MetricRow) Copy() MetricRow { row := MetricRow{ ID: m.ID, - Label: m.Label, Format: m.Format, Group: m.Group, Value: m.Value, @@ -73,7 +71,7 @@ func (m MetricRow) MarshalJSON() ([]byte, error) { report.WireMetrics }{ ID: m.ID, - Label: m.Label, + Label: Label(m.ID), Format: m.Format, Group: m.Group, Value: m.Value, diff --git a/render/detailed/metrics_test.go b/render/detailed/metrics_test.go index a199ee0ca..beeb7c7d2 100644 --- a/render/detailed/metrics_test.go +++ b/render/detailed/metrics_test.go @@ -25,7 +25,6 @@ func TestNodeMetrics(t *testing.T) { want: []detailed.MetricRow{ { ID: process.CPUUsage, - Label: "CPU", Format: "percent", Group: "", Value: 0.01, @@ -33,7 +32,6 @@ func TestNodeMetrics(t *testing.T) { }, { ID: process.MemoryUsage, - Label: "Memory", Format: "filesize", Group: "", Value: 0.01, @@ -47,7 +45,6 @@ func TestNodeMetrics(t *testing.T) { want: []detailed.MetricRow{ { ID: docker.CPUTotalUsage, - Label: "CPU", Format: "percent", Group: "", Value: 0.01, @@ -55,7 +52,6 @@ func TestNodeMetrics(t *testing.T) { }, { ID: docker.MemoryUsage, - Label: "Memory", Format: "filesize", Group: "", Value: 0.01, @@ -69,7 +65,6 @@ func TestNodeMetrics(t *testing.T) { want: []detailed.MetricRow{ { ID: host.CPUUsage, - Label: "CPU", Format: "percent", Group: "", Value: 0.01, @@ -77,7 +72,6 @@ func TestNodeMetrics(t *testing.T) { }, { ID: host.MemUsage, - Label: "Memory", Format: "filesize", Group: "", Value: 0.01, @@ -85,21 +79,18 @@ func TestNodeMetrics(t *testing.T) { }, { ID: host.Load1, - Label: "Load (1m)", Group: "load", Value: 0.01, Metric: &fixture.LoadMetric, }, { ID: host.Load5, - Label: "Load (5m)", Group: "load", Value: 0.01, Metric: &fixture.LoadMetric, }, { ID: host.Load15, - Label: "Load (15m)", Group: "load", Value: 0.01, Metric: &fixture.LoadMetric, diff --git a/render/detailed/node_test.go b/render/detailed/node_test.go index 127817fcb..8f09cecb7 100644 --- a/render/detailed/node_test.go +++ b/render/detailed/node_test.go @@ -32,17 +32,14 @@ func TestMakeDetailedHostNode(t *testing.T) { Metadata: []detailed.MetadataRow{ { ID: "host_name", - Label: "Hostname", Value: "client.hostname.com", }, { ID: "os", - Label: "Operating system", Value: "Linux", }, { ID: "local_networks", - Label: "Local Networks", Value: "10.10.10.0/24", }, }, @@ -50,34 +47,29 @@ func TestMakeDetailedHostNode(t *testing.T) { { ID: host.CPUUsage, Format: "percent", - Label: "CPU", Value: 0.01, Metric: &fixture.CPUMetric, }, { ID: host.MemUsage, Format: "filesize", - Label: "Memory", Value: 0.01, Metric: &fixture.MemoryMetric, }, { ID: host.Load1, Group: "load", - Label: "Load (1m)", Value: 0.01, Metric: &fixture.LoadMetric, }, { ID: host.Load5, Group: "load", - Label: "Load (5m)", Value: 0.01, Metric: &fixture.LoadMetric, }, { ID: host.Load15, - Label: "Load (15m)", Group: "load", Value: 0.01, Metric: &fixture.LoadMetric, @@ -126,26 +118,24 @@ func TestMakeDetailedContainerNode(t *testing.T) { Label: "server", Linkable: true, Metadata: []detailed.MetadataRow{ - {ID: "docker_container_id", Label: "ID", Value: fixture.ServerContainerID}, - {ID: "docker_image_id", Label: "Image ID", Value: fixture.ServerContainerImageID}, - {ID: "docker_container_state", Label: "State", Value: "running"}, - {ID: "label_" + render.AmazonECSContainerNameLabel, Label: fmt.Sprintf(`Label %q`, render.AmazonECSContainerNameLabel), Value: `server`}, - {ID: "label_foo1", Label: `Label "foo1"`, Value: `bar1`}, - {ID: "label_foo2", Label: `Label "foo2"`, Value: `bar2`}, - {ID: "label_io.kubernetes.pod.name", Label: `Label "io.kubernetes.pod.name"`, Value: "ping/pong-b"}, + {ID: "docker_container_id", Value: fixture.ServerContainerID}, + {ID: "docker_image_id", Value: fixture.ServerContainerImageID}, + {ID: "docker_container_state", Value: "running"}, + {ID: "label_" + render.AmazonECSContainerNameLabel, Value: `server`}, + {ID: "label_foo1", Value: `bar1`}, + {ID: "label_foo2", Value: `bar2`}, + {ID: "label_io.kubernetes.pod.name", Value: "ping/pong-b"}, }, Metrics: []detailed.MetricRow{ { ID: docker.CPUTotalUsage, Format: "percent", - Label: "CPU", Value: 0.01, Metric: &fixture.CPUMetric, }, { ID: docker.MemoryUsage, Format: "filesize", - Label: "Memory", Value: 0.01, Metric: &fixture.MemoryMetric, }, @@ -165,7 +155,7 @@ func TestMakeDetailedContainerNode(t *testing.T) { Label: "apache", Linkable: true, Metadata: []detailed.MetadataRow{ - {ID: process.PID, Label: "PID", Value: fixture.ServerPID}, + {ID: process.PID, Value: fixture.ServerPID}, }, Metrics: []detailed.MetricRow{}, },