Browse code

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 <vincent@sbr.pm>

Vincent Demeester authored on 2016/11/03 15:20:46
Showing 5 changed files
... ...
@@ -170,6 +170,9 @@ type Stats struct {
170 170
 type StatsJSON struct {
171 171
 	Stats
172 172
 
173
+	Name string `json:"name,omitempty"`
174
+	ID   string `json:"id,omitempty"`
175
+
173 176
 	// Networks request version >=1.21
174 177
 	Networks map[string]NetworkStats `json:"networks,omitempty"`
175 178
 }
... ...
@@ -29,7 +29,7 @@ var daemonOSType string
29 29
 func (s *stats) add(cs *formatter.ContainerStats) bool {
30 30
 	s.mu.Lock()
31 31
 	defer s.mu.Unlock()
32
-	if _, exists := s.isKnownContainer(cs.Name); !exists {
32
+	if _, exists := s.isKnownContainer(cs.Container); !exists {
33 33
 		s.cs = append(s.cs, cs)
34 34
 		return true
35 35
 	}
... ...
@@ -46,7 +46,7 @@ func (s *stats) remove(id string) {
46 46
 
47 47
 func (s *stats) isKnownContainer(cid string) (int, bool) {
48 48
 	for i, c := range s.cs {
49
-		if c.Name == cid {
49
+		if c.Container == cid {
50 50
 			return i, true
51 51
 		}
52 52
 	}
... ...
@@ -54,7 +54,7 @@ func (s *stats) isKnownContainer(cid string) (int, bool) {
54 54
 }
55 55
 
56 56
 func collect(s *formatter.ContainerStats, ctx context.Context, cli client.APIClient, streamStats bool, waitFirst *sync.WaitGroup) {
57
-	logrus.Debugf("collecting stats for %s", s.Name)
57
+	logrus.Debugf("collecting stats for %s", s.Container)
58 58
 	var (
59 59
 		getFirst       bool
60 60
 		previousCPU    uint64
... ...
@@ -70,7 +70,7 @@ func collect(s *formatter.ContainerStats, ctx context.Context, cli client.APICli
70 70
 		}
71 71
 	}()
72 72
 
73
-	response, err := cli.ContainerStats(ctx, s.Name, streamStats)
73
+	response, err := cli.ContainerStats(ctx, s.Container, streamStats)
74 74
 	if err != nil {
75 75
 		s.SetError(err)
76 76
 		return
... ...
@@ -125,6 +125,8 @@ func collect(s *formatter.ContainerStats, ctx context.Context, cli client.APICli
125 125
 			}
126 126
 			netRx, netTx := calculateNetwork(v.Networks)
127 127
 			s.SetStatistics(formatter.StatsEntry{
128
+				Name:             v.Name,
129
+				ID:               v.ID,
128 130
 				CPUPercentage:    cpuPercent,
129 131
 				Memory:           mem,
130 132
 				MemoryPercentage: memPerc,
... ...
@@ -24,7 +24,9 @@ const (
24 24
 
25 25
 // StatsEntry represents represents the statistics data collected from a container
26 26
 type StatsEntry struct {
27
+	Container        string
27 28
 	Name             string
29
+	ID               string
28 30
 	CPUPercentage    float64
29 31
 	Memory           float64 // On Windows this is the private working set
30 32
 	MemoryLimit      float64 // Not used on Windows
... ...
@@ -85,7 +87,7 @@ func (cs *ContainerStats) SetError(err error) {
85 85
 func (cs *ContainerStats) SetStatistics(s StatsEntry) {
86 86
 	cs.mutex.Lock()
87 87
 	defer cs.mutex.Unlock()
88
-	s.Name = cs.Name
88
+	s.Container = cs.Container
89 89
 	s.OSType = cs.OSType
90 90
 	cs.StatsEntry = s
91 91
 }
... ...
@@ -109,9 +111,9 @@ func NewStatsFormat(source, osType string) Format {
109 109
 }
110 110
 
111 111
 // NewContainerStats returns a new ContainerStats entity and sets in it the given name
112
-func NewContainerStats(name, osType string) *ContainerStats {
112
+func NewContainerStats(container, osType string) *ContainerStats {
113 113
 	return &ContainerStats{
114
-		StatsEntry: StatsEntry{Name: name, OSType: osType},
114
+		StatsEntry: StatsEntry{Container: container, OSType: osType},
115 115
 	}
116 116
 }
117 117
 
... ...
@@ -138,7 +140,18 @@ type containerStatsContext struct {
138 138
 
139 139
 func (c *containerStatsContext) Container() string {
140 140
 	c.AddHeader(containerHeader)
141
-	return c.s.Name
141
+	return c.s.Container
142
+}
143
+
144
+func (c *containerStatsContext) Name() string {
145
+	c.AddHeader(nameHeader)
146
+	name := c.s.Name[1:]
147
+	return name
148
+}
149
+
150
+func (c *containerStatsContext) ID() string {
151
+	c.AddHeader(containerIDHeader)
152
+	return c.s.ID
142 153
 }
143 154
 
144 155
 func (c *containerStatsContext) CPUPerc() string {
... ...
@@ -18,7 +18,7 @@ func TestContainerStatsContext(t *testing.T) {
18 18
 		expHeader string
19 19
 		call      func() string
20 20
 	}{
21
-		{StatsEntry{Name: containerID}, containerID, containerHeader, ctx.Container},
21
+		{StatsEntry{Container: containerID}, containerID, containerHeader, ctx.Container},
22 22
 		{StatsEntry{CPUPercentage: 5.5}, "5.50%", cpuPercHeader, ctx.CPUPerc},
23 23
 		{StatsEntry{CPUPercentage: 5.5, IsInvalid: true}, "--", cpuPercHeader, ctx.CPUPerc},
24 24
 		{StatsEntry{NetworkRx: 0.31, NetworkTx: 12.3}, "0.31 B / 12.3 B", netIOHeader, ctx.NetIO},
... ...
@@ -82,7 +82,7 @@ container2  --
82 82
 	for _, te := range tt {
83 83
 		stats := []StatsEntry{
84 84
 			{
85
-				Name:             "container1",
85
+				Container:        "container1",
86 86
 				CPUPercentage:    20,
87 87
 				Memory:           20,
88 88
 				MemoryLimit:      20,
... ...
@@ -96,7 +96,7 @@ container2  --
96 96
 				OSType:           "linux",
97 97
 			},
98 98
 			{
99
-				Name:             "container2",
99
+				Container:        "container2",
100 100
 				CPUPercentage:    30,
101 101
 				Memory:           30,
102 102
 				MemoryLimit:      30,
... ...
@@ -150,7 +150,7 @@ container2  --  --
150 150
 	for _, te := range tt {
151 151
 		stats := []StatsEntry{
152 152
 			{
153
-				Name:             "container1",
153
+				Container:        "container1",
154 154
 				CPUPercentage:    20,
155 155
 				Memory:           20,
156 156
 				MemoryLimit:      20,
... ...
@@ -164,7 +164,7 @@ container2  --  --
164 164
 				OSType:           "windows",
165 165
 			},
166 166
 			{
167
-				Name:             "container2",
167
+				Container:        "container2",
168 168
 				CPUPercentage:    30,
169 169
 				Memory:           30,
170 170
 				MemoryLimit:      30,
... ...
@@ -44,6 +44,8 @@ func (daemon *Daemon) ContainerStats(ctx context.Context, prefixOrName string, c
44 44
 	var preRead time.Time
45 45
 	getStatJSON := func(v interface{}) *types.StatsJSON {
46 46
 		ss := v.(types.StatsJSON)
47
+		ss.Name = container.Name
48
+		ss.ID = container.ID
47 49
 		ss.PreCPUStats = preCPUStats
48 50
 		ss.PreRead = preRead
49 51
 		preCPUStats = ss.CPUStats