From ef915fd036d9ea5263f9370dce490ef97ea0618d Mon Sep 17 00:00:00 2001 From: Vincent Demeester Date: Thu, 3 Nov 2016 07:20:46 +0100 Subject: [PATCH] Add support for Names and ID in stats format This adds support to display names or id of container instead of what was provided in the request. This keeps the default behavior (`docker stats byname` will display `byname` in the `CONTAINER` colmun and `docker stats byid` will display the id in the `CONTAINER` column) but adds two new format directive. Signed-off-by: Vincent Demeester --- api/types/stats.go | 3 +++ cli/command/container/stats_helpers.go | 10 ++++++---- cli/command/formatter/stats.go | 21 +++++++++++++++++---- cli/command/formatter/stats_test.go | 10 +++++----- daemon/stats.go | 2 ++ 5 files changed, 33 insertions(+), 13 deletions(-) diff --git a/api/types/stats.go b/api/types/stats.go index c3eab8e971..9bf1928b8c 100644 --- a/api/types/stats.go +++ b/api/types/stats.go @@ -170,6 +170,9 @@ type Stats struct { type StatsJSON struct { Stats + Name string `json:"name,omitempty"` + ID string `json:"id,omitempty"` + // Networks request version >=1.21 Networks map[string]NetworkStats `json:"networks,omitempty"` } diff --git a/cli/command/container/stats_helpers.go b/cli/command/container/stats_helpers.go index 32ad84841b..8bc537ad3c 100644 --- a/cli/command/container/stats_helpers.go +++ b/cli/command/container/stats_helpers.go @@ -29,7 +29,7 @@ var daemonOSType string func (s *stats) add(cs *formatter.ContainerStats) bool { s.mu.Lock() defer s.mu.Unlock() - if _, exists := s.isKnownContainer(cs.Name); !exists { + if _, exists := s.isKnownContainer(cs.Container); !exists { s.cs = append(s.cs, cs) return true } @@ -46,7 +46,7 @@ func (s *stats) remove(id string) { func (s *stats) isKnownContainer(cid string) (int, bool) { for i, c := range s.cs { - if c.Name == cid { + if c.Container == cid { return i, true } } @@ -54,7 +54,7 @@ func (s *stats) isKnownContainer(cid string) (int, bool) { } func collect(s *formatter.ContainerStats, ctx context.Context, cli client.APIClient, streamStats bool, waitFirst *sync.WaitGroup) { - logrus.Debugf("collecting stats for %s", s.Name) + logrus.Debugf("collecting stats for %s", s.Container) var ( getFirst bool previousCPU uint64 @@ -70,7 +70,7 @@ func collect(s *formatter.ContainerStats, ctx context.Context, cli client.APICli } }() - response, err := cli.ContainerStats(ctx, s.Name, streamStats) + response, err := cli.ContainerStats(ctx, s.Container, streamStats) if err != nil { s.SetError(err) return @@ -125,6 +125,8 @@ func collect(s *formatter.ContainerStats, ctx context.Context, cli client.APICli } netRx, netTx := calculateNetwork(v.Networks) s.SetStatistics(formatter.StatsEntry{ + Name: v.Name, + ID: v.ID, CPUPercentage: cpuPercent, Memory: mem, MemoryPercentage: memPerc, diff --git a/cli/command/formatter/stats.go b/cli/command/formatter/stats.go index b2c972251f..7997f996d8 100644 --- a/cli/command/formatter/stats.go +++ b/cli/command/formatter/stats.go @@ -24,7 +24,9 @@ const ( // StatsEntry represents represents the statistics data collected from a container type StatsEntry struct { + Container string Name string + ID string CPUPercentage float64 Memory float64 // On Windows this is the private working set MemoryLimit float64 // Not used on Windows @@ -85,7 +87,7 @@ func (cs *ContainerStats) SetError(err error) { func (cs *ContainerStats) SetStatistics(s StatsEntry) { cs.mutex.Lock() defer cs.mutex.Unlock() - s.Name = cs.Name + s.Container = cs.Container s.OSType = cs.OSType cs.StatsEntry = s } @@ -109,9 +111,9 @@ func NewStatsFormat(source, osType string) Format { } // NewContainerStats returns a new ContainerStats entity and sets in it the given name -func NewContainerStats(name, osType string) *ContainerStats { +func NewContainerStats(container, osType string) *ContainerStats { return &ContainerStats{ - StatsEntry: StatsEntry{Name: name, OSType: osType}, + StatsEntry: StatsEntry{Container: container, OSType: osType}, } } @@ -138,7 +140,18 @@ type containerStatsContext struct { func (c *containerStatsContext) Container() string { c.AddHeader(containerHeader) - return c.s.Name + return c.s.Container +} + +func (c *containerStatsContext) Name() string { + c.AddHeader(nameHeader) + name := c.s.Name[1:] + return name +} + +func (c *containerStatsContext) ID() string { + c.AddHeader(containerIDHeader) + return c.s.ID } func (c *containerStatsContext) CPUPerc() string { diff --git a/cli/command/formatter/stats_test.go b/cli/command/formatter/stats_test.go index f1f449e71a..d5a17cc70e 100644 --- a/cli/command/formatter/stats_test.go +++ b/cli/command/formatter/stats_test.go @@ -18,7 +18,7 @@ func TestContainerStatsContext(t *testing.T) { expHeader string call func() string }{ - {StatsEntry{Name: containerID}, containerID, containerHeader, ctx.Container}, + {StatsEntry{Container: containerID}, containerID, containerHeader, ctx.Container}, {StatsEntry{CPUPercentage: 5.5}, "5.50%", cpuPercHeader, ctx.CPUPerc}, {StatsEntry{CPUPercentage: 5.5, IsInvalid: true}, "--", cpuPercHeader, ctx.CPUPerc}, {StatsEntry{NetworkRx: 0.31, NetworkTx: 12.3}, "0.31 B / 12.3 B", netIOHeader, ctx.NetIO}, @@ -82,7 +82,7 @@ container2 -- for _, te := range tt { stats := []StatsEntry{ { - Name: "container1", + Container: "container1", CPUPercentage: 20, Memory: 20, MemoryLimit: 20, @@ -96,7 +96,7 @@ container2 -- OSType: "linux", }, { - Name: "container2", + Container: "container2", CPUPercentage: 30, Memory: 30, MemoryLimit: 30, @@ -150,7 +150,7 @@ container2 -- -- for _, te := range tt { stats := []StatsEntry{ { - Name: "container1", + Container: "container1", CPUPercentage: 20, Memory: 20, MemoryLimit: 20, @@ -164,7 +164,7 @@ container2 -- -- OSType: "windows", }, { - Name: "container2", + Container: "container2", CPUPercentage: 30, Memory: 30, MemoryLimit: 30, diff --git a/daemon/stats.go b/daemon/stats.go index 2db6852560..1b8572849b 100644 --- a/daemon/stats.go +++ b/daemon/stats.go @@ -44,6 +44,8 @@ func (daemon *Daemon) ContainerStats(ctx context.Context, prefixOrName string, c var preRead time.Time getStatJSON := func(v interface{}) *types.StatsJSON { ss := v.(types.StatsJSON) + ss.Name = container.Name + ss.ID = container.ID ss.PreCPUStats = preCPUStats ss.PreRead = preRead preCPUStats = ss.CPUStats