summaryrefslogtreecommitdiff
path: root/api
diff options
context:
space:
mode:
authorZhang Wei <zhangwei555@huawei.com>2016-03-01 15:09:48 +0800
committerZhang Wei <zhangwei555@huawei.com>2016-03-05 13:22:26 +0800
commitea86c30a4acd53ef626d4c53aaf8f91134173948 (patch)
treeba79dc2195d0163793a6328ffa5ae12110294c9c /api
parent361a63e5f2b12c62bc3d9d7393129b323b41694a (diff)
downloaddocker-ea86c30a4acd53ef626d4c53aaf8f91134173948.tar.gz
Bug fix: stats --no-stream always print zero values
`docker stats --no-stream` always print zero values. ``` $ docker stats --no-stream CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O 7f4ef234ca8c 0.00% 0 B / 0 B 0.00% 0 B / 0 B 0 B / 0 B f05bd18819aa 0.00% 0 B / 0 B 0.00% 0 B / 0 B 0 B / 0 B ``` This commit will let docker client wait until it gets correct stat data before print it on screen. Signed-off-by: Zhang Wei <zhangwei555@huawei.com>
Diffstat (limited to 'api')
-rw-r--r--api/client/stats.go33
-rw-r--r--api/client/stats_helpers.go40
2 files changed, 55 insertions, 18 deletions
diff --git a/api/client/stats.go b/api/client/stats.go
index ff45f4d418..208396b193 100644
--- a/api/client/stats.go
+++ b/api/client/stats.go
@@ -4,6 +4,7 @@ import (
"fmt"
"io"
"strings"
+ "sync"
"text/tabwriter"
"time"
@@ -59,6 +60,9 @@ func (cli *DockerCli) CmdStats(args ...string) error {
})
}
+ // waitFirst is a WaitGroup to wait first stat data's reach for each container
+ waitFirst := &sync.WaitGroup{}
+
cStats := stats{}
// getContainerList simulates creation event for all previously existing
// containers (only used when calling `docker stats` without arguments).
@@ -72,8 +76,10 @@ func (cli *DockerCli) CmdStats(args ...string) error {
}
for _, container := range cs {
s := &containerStats{Name: container.ID[:12]}
- cStats.add(s)
- go s.Collect(cli.client, !*noStream)
+ if cStats.add(s) {
+ waitFirst.Add(1)
+ go s.Collect(cli.client, !*noStream, waitFirst)
+ }
}
}
@@ -87,15 +93,19 @@ func (cli *DockerCli) CmdStats(args ...string) error {
eh.Handle("create", func(e events.Message) {
if *all {
s := &containerStats{Name: e.ID[:12]}
- cStats.add(s)
- go s.Collect(cli.client, !*noStream)
+ if cStats.add(s) {
+ waitFirst.Add(1)
+ go s.Collect(cli.client, !*noStream, waitFirst)
+ }
}
})
eh.Handle("start", func(e events.Message) {
s := &containerStats{Name: e.ID[:12]}
- cStats.add(s)
- go s.Collect(cli.client, !*noStream)
+ if cStats.add(s) {
+ waitFirst.Add(1)
+ go s.Collect(cli.client, !*noStream, waitFirst)
+ }
})
eh.Handle("die", func(e events.Message) {
@@ -112,14 +122,16 @@ func (cli *DockerCli) CmdStats(args ...string) error {
// Start a short-lived goroutine to retrieve the initial list of
// containers.
- go getContainerList()
+ getContainerList()
} else {
// Artificially send creation events for the containers we were asked to
// monitor (same code path than we use when monitoring all containers).
for _, name := range names {
s := &containerStats{Name: name}
- cStats.add(s)
- go s.Collect(cli.client, !*noStream)
+ if cStats.add(s) {
+ waitFirst.Add(1)
+ go s.Collect(cli.client, !*noStream, waitFirst)
+ }
}
// We don't expect any asynchronous errors: closeChan can be closed.
@@ -143,6 +155,9 @@ func (cli *DockerCli) CmdStats(args ...string) error {
}
}
+ // before print to screen, make sure each container get at least one valid stat data
+ waitFirst.Wait()
+
w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
printHeader := func() {
if !*noStream {
diff --git a/api/client/stats_helpers.go b/api/client/stats_helpers.go
index 985a83fb0e..a02531ce5f 100644
--- a/api/client/stats_helpers.go
+++ b/api/client/stats_helpers.go
@@ -33,12 +33,14 @@ type stats struct {
cs []*containerStats
}
-func (s *stats) add(cs *containerStats) {
+func (s *stats) add(cs *containerStats) bool {
s.mu.Lock()
+ defer s.mu.Unlock()
if _, exists := s.isKnownContainer(cs.Name); !exists {
s.cs = append(s.cs, cs)
+ return true
}
- s.mu.Unlock()
+ return false
}
func (s *stats) remove(id string) {
@@ -58,7 +60,22 @@ func (s *stats) isKnownContainer(cid string) (int, bool) {
return -1, false
}
-func (s *containerStats) Collect(cli client.APIClient, streamStats bool) {
+func (s *containerStats) Collect(cli client.APIClient, streamStats bool, waitFirst *sync.WaitGroup) {
+ var (
+ getFirst bool
+ previousCPU uint64
+ previousSystem uint64
+ u = make(chan error, 1)
+ )
+
+ defer func() {
+ // if error happens and we get nothing of stats, release wait group whatever
+ if !getFirst {
+ getFirst = true
+ waitFirst.Done()
+ }
+ }()
+
responseBody, err := cli.ContainerStats(context.Background(), s.Name, streamStats)
if err != nil {
s.mu.Lock()
@@ -68,12 +85,7 @@ func (s *containerStats) Collect(cli client.APIClient, streamStats bool) {
}
defer responseBody.Close()
- var (
- previousCPU uint64
- previousSystem uint64
- dec = json.NewDecoder(responseBody)
- u = make(chan error, 1)
- )
+ dec := json.NewDecoder(responseBody)
go func() {
for {
var v *types.StatsJSON
@@ -125,6 +137,11 @@ func (s *containerStats) Collect(cli client.APIClient, streamStats bool) {
s.BlockRead = 0
s.BlockWrite = 0
s.mu.Unlock()
+ // if this is the first stat you get, release WaitGroup
+ if !getFirst {
+ getFirst = true
+ waitFirst.Done()
+ }
case err := <-u:
if err != nil {
s.mu.Lock()
@@ -132,6 +149,11 @@ func (s *containerStats) Collect(cli client.APIClient, streamStats bool) {
s.mu.Unlock()
return
}
+ // if this is the first stat you get, release WaitGroup
+ if !getFirst {
+ getFirst = true
+ waitFirst.Done()
+ }
}
if !streamStats {
return