@@ -4,27 +4,27 @@ import (
44 "fmt"
55 "sync"
66
7- " github.com/docker/go-units"
7+ units "src/ github.com/docker/go-units"
88)
99
1010const (
11- defaultStatsTableFormat = "table {{.Container}}\t {{.CPUPrec}}\t {{.MemUsage}}\t {{.MemPrec}}\t {{.NetIO}}\t {{.BlockIO}}\t {{.PIDs}}"
12- winDefaultStatsTableFormat = "table {{.Container}}\t {{.CPUPrec}}\t {{{.MemUsage}}\t {.NetIO}}\t {{.BlockIO}}"
11+ winOSType = "windows"
12+ defaultStatsTableFormat = "table {{.Container}}\t {{.CPUPerc}}\t {{.MemUsage}}\t {{.MemPerc}}\t {{.NetIO}}\t {{.BlockIO}}\t {{.PIDs}}"
13+ winDefaultStatsTableFormat = "table {{.Container}}\t {{.CPUPerc}}\t {{{.MemUsage}}\t {.NetIO}}\t {{.BlockIO}}"
1314 emptyStatsTableFormat = "Waiting for statistics..."
1415
1516 containerHeader = "CONTAINER"
16- cpuPrecHeader = "CPU %"
17+ cpuPercHeader = "CPU %"
1718 netIOHeader = "NET I/O"
1819 blockIOHeader = "BLOCK I/O"
19- winMemPrecHeader = "PRIV WORKING SET" // Used only on Window
20- memPrecHeader = "MEM %" // Used only on Linux
20+ winMemPercHeader = "PRIV WORKING SET" // Used only on Window
21+ memPercHeader = "MEM %" // Used only on Linux
2122 memUseHeader = "MEM USAGE / LIMIT" // Used only on Linux
2223 pidsHeader = "PIDS" // Used only on Linux
2324)
2425
25- // ContainerStatsAttrs represents the statistics data collected from a container.
26- type ContainerStatsAttrs struct {
27- Windows bool
26+ // StatsEntry represents represents the statistics data collected from a container
27+ type StatsEntry struct {
2828 Name string
2929 CPUPercentage float64
3030 Memory float64 // On Windows this is the private working set
@@ -35,19 +35,73 @@ type ContainerStatsAttrs struct {
3535 BlockRead float64
3636 BlockWrite float64
3737 PidsCurrent uint64 // Not used on Windows
38+ IsInvalid bool
39+ OSType string
3840}
3941
40- // ContainerStats represents the containers statistics data.
42+ // ContainerStats represents an entity to store containers statistics synchronously
4143type ContainerStats struct {
42- Mu sync.RWMutex
43- ContainerStatsAttrs
44- Err error
44+ mutex sync.Mutex
45+ StatsEntry
46+ err error
47+ }
48+
49+ // GetError returns the container statistics error.
50+ // This is used to determine whether the statistics are valid or not
51+ func (cs * ContainerStats ) GetError () error {
52+ cs .mutex .Lock ()
53+ defer cs .mutex .Unlock ()
54+ return cs .err
55+ }
56+
57+ // SetErrorAndReset zeroes all the container statistics and store the error.
58+ // It is used when receiving time out error during statistics collecting to reduce lock overhead
59+ func (cs * ContainerStats ) SetErrorAndReset (err error ) {
60+ cs .mutex .Lock ()
61+ defer cs .mutex .Unlock ()
62+ cs .CPUPercentage = 0
63+ cs .Memory = 0
64+ cs .MemoryPercentage = 0
65+ cs .MemoryLimit = 0
66+ cs .NetworkRx = 0
67+ cs .NetworkTx = 0
68+ cs .BlockRead = 0
69+ cs .BlockWrite = 0
70+ cs .PidsCurrent = 0
71+ cs .err = err
72+ cs .IsInvalid = true
73+ }
74+
75+ // SetError sets container statistics error
76+ func (cs * ContainerStats ) SetError (err error ) {
77+ cs .mutex .Lock ()
78+ defer cs .mutex .Unlock ()
79+ cs .err = err
80+ if err != nil {
81+ cs .IsInvalid = true
82+ }
83+ }
84+
85+ // SetStatistics set the container statistics
86+ func (cs * ContainerStats ) SetStatistics (s StatsEntry ) {
87+ cs .mutex .Lock ()
88+ defer cs .mutex .Unlock ()
89+ s .Name = cs .Name
90+ s .OSType = cs .OSType
91+ cs .StatsEntry = s
92+ }
93+
94+ // GetStatistics returns container statistics with other meta data such as the container name
95+ func (cs * ContainerStats ) GetStatistics () StatsEntry {
96+ cs .mutex .Lock ()
97+ defer cs .mutex .Unlock ()
98+ return cs .StatsEntry
4599}
46100
47101// NewStatsFormat returns a format for rendering an CStatsContext
48102func NewStatsFormat (source , osType string ) Format {
49103 if source == TableFormatKey {
50- if osType == "windows" {
104+ if osType == winOSType {
51105 return Format (winDefaultStatsTableFormat )
52106 }
53107 return Format (defaultStatsTableFormat )
@@ -58,22 +112,16 @@ func NewStatsFormat(source, osType string) Format {
58112// NewContainerStats returns a new ContainerStats entity and sets in it the given name
59113func NewContainerStats (name , osType string ) * ContainerStats {
60114 return & ContainerStats {
61- ContainerStatsAttrs : ContainerStatsAttrs {
62- Name : name ,
63- Windows : (osType == "windows" ),
64- },
115+ StatsEntry : StatsEntry {Name : name , OSType : osType },
65116 }
66117}
67118
68119// ContainerStatsWrite renders the context for a list of containers statistics
69- func ContainerStatsWrite (ctx Context , containerStats []* ContainerStats ) error {
120+ func ContainerStatsWrite (ctx Context , containerStats []StatsEntry ) error {
70121 render := func (format func (subContext subContext ) error ) error {
71122 for _ , cstats := range containerStats {
72- cstats .Mu .RLock ()
73- cstatsAttrs := cstats .ContainerStatsAttrs
74- cstats .Mu .RUnlock ()
75123 containerStatsCtx := & containerStatsContext {
76- s : cstatsAttrs ,
124+ s : cstats ,
77125 }
78126 if err := format (containerStatsCtx ); err != nil {
79127 return err
@@ -86,50 +134,62 @@ func ContainerStatsWrite(ctx Context, containerStats []*ContainerStats) error {
86134
87135type containerStatsContext struct {
88136 HeaderContext
89- s ContainerStatsAttrs
137+ s StatsEntry
90138}
91139
92140func (c * containerStatsContext ) Container () string {
93141 c .AddHeader (containerHeader )
94142 return c .s .Name
95143}
96144
97- func (c * containerStatsContext ) CPUPrec () string {
98- c .AddHeader (cpuPrecHeader )
145+ func (c * containerStatsContext ) CPUPerc () string {
146+ c .AddHeader (cpuPercHeader )
147+ if c .s .IsInvalid {
148+ return fmt .Sprintf ("--" )
149+ }
99150 return fmt .Sprintf ("%.2f%%" , c .s .CPUPercentage )
100151}
101152
102153func (c * containerStatsContext ) MemUsage () string {
103154 c .AddHeader (memUseHeader )
104- if ! c .s .Windows {
105- return fmt .Sprintf ("%s / %s" , units . BytesSize ( c . s . Memory ), units . BytesSize ( c . s . MemoryLimit ) )
155+ if c .s .IsInvalid || c . s . OSType == winOSType {
156+ return fmt .Sprintf ("-- / --" )
106157 }
107- return fmt .Sprintf ("-- / --" )
158+ return fmt .Sprintf ("%s / %s" , units . BytesSize ( c . s . Memory ), units . BytesSize ( c . s . MemoryLimit ) )
108159}
109160
110- func (c * containerStatsContext ) MemPrec () string {
111- header := memPrecHeader
112- if c .s .Windows {
113- header = winMemPrecHeader
161+ func (c * containerStatsContext ) MemPerc () string {
162+ header := memPercHeader
163+ if c .s .OSType == winOSType {
164+ header = winMemPercHeader
114165 }
115166 c .AddHeader (header )
167+ if c .s .IsInvalid {
168+ return fmt .Sprintf ("--" )
169+ }
116170 return fmt .Sprintf ("%.2f%%" , c .s .MemoryPercentage )
117171}
118172
119173func (c * containerStatsContext ) NetIO () string {
120174 c .AddHeader (netIOHeader )
175+ if c .s .IsInvalid {
176+ return fmt .Sprintf ("--" )
177+ }
121178 return fmt .Sprintf ("%s / %s" , units .HumanSizeWithPrecision (c .s .NetworkRx , 3 ), units .HumanSizeWithPrecision (c .s .NetworkTx , 3 ))
122179}
123180
124181func (c * containerStatsContext ) BlockIO () string {
125182 c .AddHeader (blockIOHeader )
183+ if c .s .IsInvalid {
184+ return fmt .Sprintf ("--" )
185+ }
126186 return fmt .Sprintf ("%s / %s" , units .HumanSizeWithPrecision (c .s .BlockRead , 3 ), units .HumanSizeWithPrecision (c .s .BlockWrite , 3 ))
127187}
128188
129189func (c * containerStatsContext ) PIDs () string {
130190 c .AddHeader (pidsHeader )
131- if ! c .s .Windows {
132- return fmt .Sprintf ("%d" , c . s . PidsCurrent )
191+ if c .s .IsInvalid || c . s . OSType == winOSType {
192+ return fmt .Sprintf ("--" )
133193 }
134- return fmt .Sprintf ("-" )
194+ return fmt .Sprintf ("%d" , c . s . PidsCurrent )
135195}
0 commit comments