|
@@ -4,6 +4,7 @@ import (
|
|
"encoding/json"
|
|
"encoding/json"
|
|
"fmt"
|
|
"fmt"
|
|
"io"
|
|
"io"
|
|
|
|
+ "net/url"
|
|
"sort"
|
|
"sort"
|
|
"strings"
|
|
"strings"
|
|
"sync"
|
|
"sync"
|
|
@@ -27,8 +28,14 @@ type containerStats struct {
|
|
err error
|
|
err error
|
|
}
|
|
}
|
|
|
|
|
|
-func (s *containerStats) Collect(cli *DockerCli) {
|
|
|
|
- stream, _, err := cli.call("GET", "/containers/"+s.Name+"/stats", nil, nil)
|
|
|
|
|
|
+func (s *containerStats) Collect(cli *DockerCli, streamStats bool) {
|
|
|
|
+ v := url.Values{}
|
|
|
|
+ if streamStats {
|
|
|
|
+ v.Set("stream", "1")
|
|
|
|
+ } else {
|
|
|
|
+ v.Set("stream", "0")
|
|
|
|
+ }
|
|
|
|
+ stream, _, err := cli.call("GET", "/containers/"+s.Name+"/stats?"+v.Encode(), nil, nil)
|
|
if err != nil {
|
|
if err != nil {
|
|
s.err = err
|
|
s.err = err
|
|
return
|
|
return
|
|
@@ -67,6 +74,9 @@ func (s *containerStats) Collect(cli *DockerCli) {
|
|
previousCPU = v.CpuStats.CpuUsage.TotalUsage
|
|
previousCPU = v.CpuStats.CpuUsage.TotalUsage
|
|
previousSystem = v.CpuStats.SystemUsage
|
|
previousSystem = v.CpuStats.SystemUsage
|
|
u <- nil
|
|
u <- nil
|
|
|
|
+ if !streamStats {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}()
|
|
}()
|
|
for {
|
|
for {
|
|
@@ -87,6 +97,9 @@ func (s *containerStats) Collect(cli *DockerCli) {
|
|
return
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ if !streamStats {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -112,6 +125,7 @@ func (s *containerStats) Display(w io.Writer) error {
|
|
// Usage: docker stats CONTAINER [CONTAINER...]
|
|
// Usage: docker stats CONTAINER [CONTAINER...]
|
|
func (cli *DockerCli) CmdStats(args ...string) error {
|
|
func (cli *DockerCli) CmdStats(args ...string) error {
|
|
cmd := cli.Subcmd("stats", "CONTAINER [CONTAINER...]", "Display a live stream of one or more containers' resource usage statistics", true)
|
|
cmd := cli.Subcmd("stats", "CONTAINER [CONTAINER...]", "Display a live stream of one or more containers' resource usage statistics", true)
|
|
|
|
+ noStream := cmd.Bool([]string{"-no-stream"}, false, "Disable streaming stats and only pull the first result")
|
|
cmd.Require(flag.Min, 1)
|
|
cmd.Require(flag.Min, 1)
|
|
cmd.ParseFlags(args, true)
|
|
cmd.ParseFlags(args, true)
|
|
|
|
|
|
@@ -122,14 +136,16 @@ func (cli *DockerCli) CmdStats(args ...string) error {
|
|
w = tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
|
|
w = tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
|
|
)
|
|
)
|
|
printHeader := func() {
|
|
printHeader := func() {
|
|
- io.WriteString(cli.out, "\033[2J")
|
|
|
|
- io.WriteString(cli.out, "\033[H")
|
|
|
|
|
|
+ if !*noStream {
|
|
|
|
+ fmt.Fprint(cli.out, "\033[2J")
|
|
|
|
+ fmt.Fprint(cli.out, "\033[H")
|
|
|
|
+ }
|
|
io.WriteString(w, "CONTAINER\tCPU %\tMEM USAGE/LIMIT\tMEM %\tNET I/O\n")
|
|
io.WriteString(w, "CONTAINER\tCPU %\tMEM USAGE/LIMIT\tMEM %\tNET I/O\n")
|
|
}
|
|
}
|
|
for _, n := range names {
|
|
for _, n := range names {
|
|
s := &containerStats{Name: n}
|
|
s := &containerStats{Name: n}
|
|
cStats = append(cStats, s)
|
|
cStats = append(cStats, s)
|
|
- go s.Collect(cli)
|
|
|
|
|
|
+ go s.Collect(cli, !*noStream)
|
|
}
|
|
}
|
|
// do a quick pause so that any failed connections for containers that do not exist are able to be
|
|
// do a quick pause so that any failed connections for containers that do not exist are able to be
|
|
// evicted before we display the initial or default values.
|
|
// evicted before we display the initial or default values.
|
|
@@ -149,7 +165,7 @@ func (cli *DockerCli) CmdStats(args ...string) error {
|
|
printHeader()
|
|
printHeader()
|
|
toRemove := []int{}
|
|
toRemove := []int{}
|
|
for i, s := range cStats {
|
|
for i, s := range cStats {
|
|
- if err := s.Display(w); err != nil {
|
|
|
|
|
|
+ if err := s.Display(w); err != nil && !*noStream {
|
|
toRemove = append(toRemove, i)
|
|
toRemove = append(toRemove, i)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -161,6 +177,9 @@ func (cli *DockerCli) CmdStats(args ...string) error {
|
|
return nil
|
|
return nil
|
|
}
|
|
}
|
|
w.Flush()
|
|
w.Flush()
|
|
|
|
+ if *noStream {
|
|
|
|
+ break
|
|
|
|
+ }
|
|
}
|
|
}
|
|
return nil
|
|
return nil
|
|
}
|
|
}
|