2018-10-23 11:05:44 -04:00
|
|
|
package container
|
2016-07-18 14:30:15 -04:00
|
|
|
|
|
|
|
import (
|
2022-03-28 05:26:39 -04:00
|
|
|
"strconv"
|
2016-07-18 14:30:15 -04:00
|
|
|
"sync"
|
|
|
|
|
2018-10-23 11:05:44 -04:00
|
|
|
"github.com/docker/cli/cli/command/formatter"
|
2017-09-27 12:24:26 -04:00
|
|
|
"github.com/docker/docker/pkg/stringid"
|
2016-10-24 18:06:33 -04:00
|
|
|
units "github.com/docker/go-units"
|
2016-07-18 14:30:15 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2016-09-22 08:54:41 -04:00
|
|
|
winOSType = "windows"
|
2017-09-27 12:05:51 -04:00
|
|
|
defaultStatsTableFormat = "table {{.ID}}\t{{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.NetIO}}\t{{.BlockIO}}\t{{.PIDs}}"
|
|
|
|
winDefaultStatsTableFormat = "table {{.ID}}\t{{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}\t{{.BlockIO}}"
|
2016-10-25 19:19:14 -04:00
|
|
|
|
|
|
|
containerHeader = "CONTAINER"
|
|
|
|
cpuPercHeader = "CPU %"
|
|
|
|
netIOHeader = "NET I/O"
|
|
|
|
blockIOHeader = "BLOCK I/O"
|
|
|
|
memPercHeader = "MEM %" // Used only on Linux
|
|
|
|
winMemUseHeader = "PRIV WORKING SET" // Used only on Windows
|
|
|
|
memUseHeader = "MEM USAGE / LIMIT" // Used only on Linux
|
|
|
|
pidsHeader = "PIDS" // Used only on Linux
|
2016-07-18 14:30:15 -04:00
|
|
|
)
|
|
|
|
|
2023-11-20 08:41:32 -05:00
|
|
|
// StatsEntry represents the statistics data collected from a container
|
2016-09-22 08:54:41 -04:00
|
|
|
type StatsEntry struct {
|
2016-11-03 02:20:46 -04:00
|
|
|
Container string
|
2016-07-18 14:30:15 -04:00
|
|
|
Name string
|
2016-11-03 02:20:46 -04:00
|
|
|
ID string
|
2016-07-18 14:30:15 -04:00
|
|
|
CPUPercentage float64
|
|
|
|
Memory float64 // On Windows this is the private working set
|
|
|
|
MemoryLimit float64 // Not used on Windows
|
|
|
|
MemoryPercentage float64 // Not used on Windows
|
|
|
|
NetworkRx float64
|
|
|
|
NetworkTx float64
|
|
|
|
BlockRead float64
|
|
|
|
BlockWrite float64
|
|
|
|
PidsCurrent uint64 // Not used on Windows
|
2016-09-22 08:54:41 -04:00
|
|
|
IsInvalid bool
|
2016-07-18 14:30:15 -04:00
|
|
|
}
|
|
|
|
|
2018-10-23 11:05:44 -04:00
|
|
|
// Stats represents an entity to store containers statistics synchronously
|
|
|
|
type Stats struct {
|
2022-03-28 05:29:06 -04:00
|
|
|
mutex sync.RWMutex
|
2016-09-22 08:54:41 -04:00
|
|
|
StatsEntry
|
|
|
|
err error
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetError returns the container statistics error.
|
|
|
|
// This is used to determine whether the statistics are valid or not
|
2018-10-23 11:05:44 -04:00
|
|
|
func (cs *Stats) GetError() error {
|
2022-03-28 05:29:06 -04:00
|
|
|
cs.mutex.RLock()
|
|
|
|
defer cs.mutex.RUnlock()
|
2016-09-22 08:54:41 -04:00
|
|
|
return cs.err
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetErrorAndReset zeroes all the container statistics and store the error.
|
|
|
|
// It is used when receiving time out error during statistics collecting to reduce lock overhead
|
2018-10-23 11:05:44 -04:00
|
|
|
func (cs *Stats) SetErrorAndReset(err error) {
|
2016-09-22 08:54:41 -04:00
|
|
|
cs.mutex.Lock()
|
|
|
|
defer cs.mutex.Unlock()
|
|
|
|
cs.CPUPercentage = 0
|
|
|
|
cs.Memory = 0
|
|
|
|
cs.MemoryPercentage = 0
|
|
|
|
cs.MemoryLimit = 0
|
|
|
|
cs.NetworkRx = 0
|
|
|
|
cs.NetworkTx = 0
|
|
|
|
cs.BlockRead = 0
|
|
|
|
cs.BlockWrite = 0
|
|
|
|
cs.PidsCurrent = 0
|
|
|
|
cs.err = err
|
|
|
|
cs.IsInvalid = true
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetError sets container statistics error
|
2018-10-23 11:05:44 -04:00
|
|
|
func (cs *Stats) SetError(err error) {
|
2016-09-22 08:54:41 -04:00
|
|
|
cs.mutex.Lock()
|
|
|
|
defer cs.mutex.Unlock()
|
|
|
|
cs.err = err
|
|
|
|
if err != nil {
|
|
|
|
cs.IsInvalid = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetStatistics set the container statistics
|
2018-10-23 11:05:44 -04:00
|
|
|
func (cs *Stats) SetStatistics(s StatsEntry) {
|
2016-09-22 08:54:41 -04:00
|
|
|
cs.mutex.Lock()
|
|
|
|
defer cs.mutex.Unlock()
|
2016-11-03 02:20:46 -04:00
|
|
|
s.Container = cs.Container
|
2016-09-22 08:54:41 -04:00
|
|
|
cs.StatsEntry = s
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetStatistics returns container statistics with other meta data such as the container name
|
2018-10-23 11:05:44 -04:00
|
|
|
func (cs *Stats) GetStatistics() StatsEntry {
|
2022-03-28 05:29:06 -04:00
|
|
|
cs.mutex.RLock()
|
|
|
|
defer cs.mutex.RUnlock()
|
2016-09-22 08:54:41 -04:00
|
|
|
return cs.StatsEntry
|
2016-07-18 14:30:15 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewStatsFormat returns a format for rendering an CStatsContext
|
2018-10-23 11:05:44 -04:00
|
|
|
func NewStatsFormat(source, osType string) formatter.Format {
|
|
|
|
if source == formatter.TableFormatKey {
|
2016-09-22 08:54:41 -04:00
|
|
|
if osType == winOSType {
|
2020-08-28 17:09:27 -04:00
|
|
|
return winDefaultStatsTableFormat
|
2016-07-18 14:30:15 -04:00
|
|
|
}
|
2020-08-28 17:09:27 -04:00
|
|
|
return defaultStatsTableFormat
|
2016-07-18 14:30:15 -04:00
|
|
|
}
|
2018-10-23 11:05:44 -04:00
|
|
|
return formatter.Format(source)
|
2016-07-18 14:30:15 -04:00
|
|
|
}
|
|
|
|
|
2018-10-23 11:05:44 -04:00
|
|
|
// NewStats returns a new Stats entity and sets in it the given name
|
|
|
|
func NewStats(container string) *Stats {
|
|
|
|
return &Stats{StatsEntry: StatsEntry{Container: container}}
|
2016-07-18 14:30:15 -04:00
|
|
|
}
|
|
|
|
|
2018-10-23 11:05:44 -04:00
|
|
|
// statsFormatWrite renders the context for a list of containers statistics
|
linting: address assorted issues found by gocritic
internal/test/builders/config.go:36:15: captLocal: `ID' should not be capitalized (gocritic)
func ConfigID(ID string) func(config *swarm.Config) {
^
internal/test/builders/secret.go:45:15: captLocal: `ID' should not be capitalized (gocritic)
func SecretID(ID string) func(secret *swarm.Secret) {
^
internal/test/builders/service.go:21:16: captLocal: `ID' should not be capitalized (gocritic)
func ServiceID(ID string) func(*swarm.Service) {
^
cli/command/image/formatter_history.go:100:15: wrapperFunc: use strings.ReplaceAll method in `strings.Replace(c.h.CreatedBy, "\t", " ", -1)` (gocritic)
createdBy := strings.Replace(c.h.CreatedBy, "\t", " ", -1)
^
e2e/image/push_test.go:246:34: badCall: suspicious Join on 1 argument (gocritic)
assert.NilError(t, os.RemoveAll(filepath.Join(dir.Join("trust"))))
^
e2e/image/push_test.go:313:34: badCall: suspicious Join on 1 argument (gocritic)
assert.NilError(t, os.RemoveAll(filepath.Join(dir.Join("trust"))))
^
cli/config/configfile/file_test.go:185:2: assignOp: replace `c.GetAllCallCount = c.GetAllCallCount + 1` with `c.GetAllCallCount++` (gocritic)
c.GetAllCallCount = c.GetAllCallCount + 1
^
cli/command/context/inspect_test.go:20:58: wrapperFunc: use strings.ReplaceAll method in `strings.Replace(si.MetadataPath, `\`, `\\`, -1)` (gocritic)
expected = strings.Replace(expected, "<METADATA_PATH>", strings.Replace(si.MetadataPath, `\`, `\\`, -1), 1)
^
cli/command/context/inspect_test.go:21:53: wrapperFunc: use strings.ReplaceAll method in `strings.Replace(si.TLSPath, `\`, `\\`, -1)` (gocritic)
expected = strings.Replace(expected, "<TLS_PATH>", strings.Replace(si.TLSPath, `\`, `\\`, -1), 1)
^
cli/command/container/formatter_stats.go:119:46: captLocal: `Stats' should not be capitalized (gocritic)
func statsFormatWrite(ctx formatter.Context, Stats []StatsEntry, osType string, trunc bool) error {
^
cli/command/container/stats_helpers.go:209:4: assignOp: replace `blkRead = blkRead + bioEntry.Value` with `blkRead += bioEntry.Value` (gocritic)
blkRead = blkRead + bioEntry.Value
^
cli/command/container/stats_helpers.go:211:4: assignOp: replace `blkWrite = blkWrite + bioEntry.Value` with `blkWrite += bioEntry.Value` (gocritic)
blkWrite = blkWrite + bioEntry.Value
^
cli/command/registry/formatter_search.go:67:10: wrapperFunc: use strings.ReplaceAll method in `strings.Replace(c.s.Description, "\n", " ", -1)` (gocritic)
desc := strings.Replace(c.s.Description, "\n", " ", -1)
^
cli/command/registry/formatter_search.go:68:9: wrapperFunc: use strings.ReplaceAll method in `strings.Replace(desc, "\r", " ", -1)` (gocritic)
desc = strings.Replace(desc, "\r", " ", -1)
^
cli/command/service/list_test.go:164:5: assignOp: replace `tc.doc = tc.doc + " with quiet"` with `tc.doc += " with quiet"` (gocritic)
tc.doc = tc.doc + " with quiet"
^
cli/command/service/progress/progress.go:274:11: wrapperFunc: use strings.ReplaceAll method in `strings.Replace(errMsg, "\n", " ", -1)` (gocritic)
errMsg = strings.Replace(errMsg, "\n", " ", -1)
^
cli/manifest/store/store.go:153:9: wrapperFunc: use strings.ReplaceAll method in `strings.Replace(fileName, "/", "_", -1)` (gocritic)
return strings.Replace(fileName, "/", "_", -1)
^
cli/manifest/store/store.go:152:14: wrapperFunc: use strings.ReplaceAll method in `strings.Replace(ref, ":", "-", -1)` (gocritic)
fileName := strings.Replace(ref, ":", "-", -1)
^
cli/command/plugin/formatter.go:79:10: wrapperFunc: use strings.ReplaceAll method in `strings.Replace(c.p.Config.Description, "\n", "", -1)` (gocritic)
desc := strings.Replace(c.p.Config.Description, "\n", "", -1)
^
cli/command/plugin/formatter.go:80:9: wrapperFunc: use strings.ReplaceAll method in `strings.Replace(desc, "\r", "", -1)` (gocritic)
desc = strings.Replace(desc, "\r", "", -1)
^
cli/compose/convert/service.go:642:23: captLocal: `DNS' should not be capitalized (gocritic)
func convertDNSConfig(DNS []string, DNSSearch []string) *swarm.DNSConfig {
^
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-11-20 07:30:05 -05:00
|
|
|
func statsFormatWrite(ctx formatter.Context, stats []StatsEntry, osType string, trunc bool) error {
|
2018-10-23 11:05:44 -04:00
|
|
|
render := func(format func(subContext formatter.SubContext) error) error {
|
linting: address assorted issues found by gocritic
internal/test/builders/config.go:36:15: captLocal: `ID' should not be capitalized (gocritic)
func ConfigID(ID string) func(config *swarm.Config) {
^
internal/test/builders/secret.go:45:15: captLocal: `ID' should not be capitalized (gocritic)
func SecretID(ID string) func(secret *swarm.Secret) {
^
internal/test/builders/service.go:21:16: captLocal: `ID' should not be capitalized (gocritic)
func ServiceID(ID string) func(*swarm.Service) {
^
cli/command/image/formatter_history.go:100:15: wrapperFunc: use strings.ReplaceAll method in `strings.Replace(c.h.CreatedBy, "\t", " ", -1)` (gocritic)
createdBy := strings.Replace(c.h.CreatedBy, "\t", " ", -1)
^
e2e/image/push_test.go:246:34: badCall: suspicious Join on 1 argument (gocritic)
assert.NilError(t, os.RemoveAll(filepath.Join(dir.Join("trust"))))
^
e2e/image/push_test.go:313:34: badCall: suspicious Join on 1 argument (gocritic)
assert.NilError(t, os.RemoveAll(filepath.Join(dir.Join("trust"))))
^
cli/config/configfile/file_test.go:185:2: assignOp: replace `c.GetAllCallCount = c.GetAllCallCount + 1` with `c.GetAllCallCount++` (gocritic)
c.GetAllCallCount = c.GetAllCallCount + 1
^
cli/command/context/inspect_test.go:20:58: wrapperFunc: use strings.ReplaceAll method in `strings.Replace(si.MetadataPath, `\`, `\\`, -1)` (gocritic)
expected = strings.Replace(expected, "<METADATA_PATH>", strings.Replace(si.MetadataPath, `\`, `\\`, -1), 1)
^
cli/command/context/inspect_test.go:21:53: wrapperFunc: use strings.ReplaceAll method in `strings.Replace(si.TLSPath, `\`, `\\`, -1)` (gocritic)
expected = strings.Replace(expected, "<TLS_PATH>", strings.Replace(si.TLSPath, `\`, `\\`, -1), 1)
^
cli/command/container/formatter_stats.go:119:46: captLocal: `Stats' should not be capitalized (gocritic)
func statsFormatWrite(ctx formatter.Context, Stats []StatsEntry, osType string, trunc bool) error {
^
cli/command/container/stats_helpers.go:209:4: assignOp: replace `blkRead = blkRead + bioEntry.Value` with `blkRead += bioEntry.Value` (gocritic)
blkRead = blkRead + bioEntry.Value
^
cli/command/container/stats_helpers.go:211:4: assignOp: replace `blkWrite = blkWrite + bioEntry.Value` with `blkWrite += bioEntry.Value` (gocritic)
blkWrite = blkWrite + bioEntry.Value
^
cli/command/registry/formatter_search.go:67:10: wrapperFunc: use strings.ReplaceAll method in `strings.Replace(c.s.Description, "\n", " ", -1)` (gocritic)
desc := strings.Replace(c.s.Description, "\n", " ", -1)
^
cli/command/registry/formatter_search.go:68:9: wrapperFunc: use strings.ReplaceAll method in `strings.Replace(desc, "\r", " ", -1)` (gocritic)
desc = strings.Replace(desc, "\r", " ", -1)
^
cli/command/service/list_test.go:164:5: assignOp: replace `tc.doc = tc.doc + " with quiet"` with `tc.doc += " with quiet"` (gocritic)
tc.doc = tc.doc + " with quiet"
^
cli/command/service/progress/progress.go:274:11: wrapperFunc: use strings.ReplaceAll method in `strings.Replace(errMsg, "\n", " ", -1)` (gocritic)
errMsg = strings.Replace(errMsg, "\n", " ", -1)
^
cli/manifest/store/store.go:153:9: wrapperFunc: use strings.ReplaceAll method in `strings.Replace(fileName, "/", "_", -1)` (gocritic)
return strings.Replace(fileName, "/", "_", -1)
^
cli/manifest/store/store.go:152:14: wrapperFunc: use strings.ReplaceAll method in `strings.Replace(ref, ":", "-", -1)` (gocritic)
fileName := strings.Replace(ref, ":", "-", -1)
^
cli/command/plugin/formatter.go:79:10: wrapperFunc: use strings.ReplaceAll method in `strings.Replace(c.p.Config.Description, "\n", "", -1)` (gocritic)
desc := strings.Replace(c.p.Config.Description, "\n", "", -1)
^
cli/command/plugin/formatter.go:80:9: wrapperFunc: use strings.ReplaceAll method in `strings.Replace(desc, "\r", "", -1)` (gocritic)
desc = strings.Replace(desc, "\r", "", -1)
^
cli/compose/convert/service.go:642:23: captLocal: `DNS' should not be capitalized (gocritic)
func convertDNSConfig(DNS []string, DNSSearch []string) *swarm.DNSConfig {
^
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-11-20 07:30:05 -05:00
|
|
|
for _, cstats := range stats {
|
2018-10-23 11:05:44 -04:00
|
|
|
statsCtx := &statsContext{
|
2017-09-27 12:24:26 -04:00
|
|
|
s: cstats,
|
|
|
|
os: osType,
|
|
|
|
trunc: trunc,
|
2016-07-18 14:30:15 -04:00
|
|
|
}
|
2018-10-23 11:05:44 -04:00
|
|
|
if err := format(statsCtx); err != nil {
|
2016-07-18 14:30:15 -04:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2017-02-03 19:48:46 -05:00
|
|
|
memUsage := memUseHeader
|
|
|
|
if osType == winOSType {
|
|
|
|
memUsage = winMemUseHeader
|
|
|
|
}
|
2018-10-23 11:05:44 -04:00
|
|
|
statsCtx := statsContext{}
|
|
|
|
statsCtx.Header = formatter.SubHeaderContext{
|
2017-02-03 19:48:46 -05:00
|
|
|
"Container": containerHeader,
|
2018-10-23 11:05:44 -04:00
|
|
|
"Name": formatter.NameHeader,
|
|
|
|
"ID": formatter.ContainerIDHeader,
|
2017-02-03 19:48:46 -05:00
|
|
|
"CPUPerc": cpuPercHeader,
|
|
|
|
"MemUsage": memUsage,
|
|
|
|
"MemPerc": memPercHeader,
|
|
|
|
"NetIO": netIOHeader,
|
|
|
|
"BlockIO": blockIOHeader,
|
|
|
|
"PIDs": pidsHeader,
|
|
|
|
}
|
2018-10-23 11:05:44 -04:00
|
|
|
statsCtx.os = osType
|
|
|
|
return ctx.Write(&statsCtx, render)
|
2016-07-18 14:30:15 -04:00
|
|
|
}
|
|
|
|
|
2018-10-23 11:05:44 -04:00
|
|
|
type statsContext struct {
|
|
|
|
formatter.HeaderContext
|
2017-09-27 12:24:26 -04:00
|
|
|
s StatsEntry
|
|
|
|
os string
|
|
|
|
trunc bool
|
2016-07-18 14:30:15 -04:00
|
|
|
}
|
|
|
|
|
2018-10-23 11:05:44 -04:00
|
|
|
func (c *statsContext) MarshalJSON() ([]byte, error) {
|
|
|
|
return formatter.MarshalJSON(c)
|
2017-01-19 04:50:28 -05:00
|
|
|
}
|
|
|
|
|
2018-10-23 11:05:44 -04:00
|
|
|
func (c *statsContext) Container() string {
|
2016-11-03 02:20:46 -04:00
|
|
|
return c.s.Container
|
|
|
|
}
|
|
|
|
|
2018-10-23 11:05:44 -04:00
|
|
|
func (c *statsContext) Name() string {
|
Fix panic of "docker stats --format {{.Name}} --all"
This commit fixes panic when execute stats command:
* use --format {{.Name}} with --all when there're exited containers.
* use --format {{.Name}} while stating exited container.
The root cause is when stating an exited container, the result from the
api didn't contain the Name and ID field, which will make format
process panic.
Panic log is like this:
```
panic: runtime error: slice bounds out of range [recovered]
panic: runtime error: slice bounds out of range
goroutine 1 [running]:
panic(0xb20f80, 0xc420014110)
/usr/local/go/src/runtime/panic.go:500 +0x1a1
text/template.errRecover(0xc4201773e8)
/usr/local/go/src/text/template/exec.go:140 +0x2ad
panic(0xb20f80, 0xc420014110)
/usr/local/go/src/runtime/panic.go:458 +0x243
github.com/docker/docker/cli/command/formatter.(*containerStatsContext).Name(0xc420430160,
0x0, 0x0)
/go/src/github.com/docker/docker/cli/command/formatter/stats.go:148
+0x86
reflect.Value.call(0xb9a3a0, 0xc420430160, 0x2213, 0xbe3657, 0x4,
0x11bc9f8, 0x0, 0x0, 0x4d75b3, 0x1198940, ...)
/usr/local/go/src/reflect/value.go:434 +0x5c8
reflect.Value.Call(0xb9a3a0, 0xc420430160, 0x2213, 0x11bc9f8, 0x0, 0x0,
0xc420424028, 0xb, 0xb)
/usr/local/go/src/reflect/value.go:302 +0xa4
text/template.(*state).evalCall(0xc420177368, 0xb9a3a0, 0xc420430160,
0x16, 0xb9a3a0, 0xc420430160, 0x2213, 0x1178fa0, 0xc4203ea330,
0xc4203de283, ...)
/usr/local/go/src/text/template/exec.go:658 +0x530
```
Signed-off-by: Zhang Wei <zhangwei555@huawei.com>
2017-02-06 21:27:40 -05:00
|
|
|
if len(c.s.Name) > 1 {
|
|
|
|
return c.s.Name[1:]
|
|
|
|
}
|
|
|
|
return "--"
|
2016-11-03 02:20:46 -04:00
|
|
|
}
|
|
|
|
|
2018-10-23 11:05:44 -04:00
|
|
|
func (c *statsContext) ID() string {
|
2017-09-27 12:24:26 -04:00
|
|
|
if c.trunc {
|
|
|
|
return stringid.TruncateID(c.s.ID)
|
|
|
|
}
|
2016-11-03 02:20:46 -04:00
|
|
|
return c.s.ID
|
2016-07-18 14:30:15 -04:00
|
|
|
}
|
|
|
|
|
2018-10-23 11:05:44 -04:00
|
|
|
func (c *statsContext) CPUPerc() string {
|
2016-09-22 08:54:41 -04:00
|
|
|
if c.s.IsInvalid {
|
2022-03-27 13:48:55 -04:00
|
|
|
return "--"
|
2016-09-22 08:54:41 -04:00
|
|
|
}
|
2022-03-28 05:26:39 -04:00
|
|
|
return formatPercentage(c.s.CPUPercentage)
|
2016-07-18 14:30:15 -04:00
|
|
|
}
|
|
|
|
|
2018-10-23 11:05:44 -04:00
|
|
|
func (c *statsContext) MemUsage() string {
|
2016-10-25 19:19:14 -04:00
|
|
|
if c.s.IsInvalid {
|
2022-03-27 13:48:55 -04:00
|
|
|
return "-- / --"
|
2016-07-18 14:30:15 -04:00
|
|
|
}
|
2017-02-05 11:55:30 -05:00
|
|
|
if c.os == winOSType {
|
2017-07-11 14:19:02 -04:00
|
|
|
return units.BytesSize(c.s.Memory)
|
2016-10-25 19:19:14 -04:00
|
|
|
}
|
2022-03-28 05:26:39 -04:00
|
|
|
return units.BytesSize(c.s.Memory) + " / " + units.BytesSize(c.s.MemoryLimit)
|
2016-07-18 14:30:15 -04:00
|
|
|
}
|
|
|
|
|
2018-10-23 11:05:44 -04:00
|
|
|
func (c *statsContext) MemPerc() string {
|
2017-02-05 11:55:30 -05:00
|
|
|
if c.s.IsInvalid || c.os == winOSType {
|
2022-03-27 13:48:55 -04:00
|
|
|
return "--"
|
2016-09-22 08:54:41 -04:00
|
|
|
}
|
2022-03-28 05:26:39 -04:00
|
|
|
return formatPercentage(c.s.MemoryPercentage)
|
2016-07-18 14:30:15 -04:00
|
|
|
}
|
|
|
|
|
2018-10-23 11:05:44 -04:00
|
|
|
func (c *statsContext) NetIO() string {
|
2016-09-22 08:54:41 -04:00
|
|
|
if c.s.IsInvalid {
|
2022-03-27 13:48:55 -04:00
|
|
|
return "--"
|
2016-09-22 08:54:41 -04:00
|
|
|
}
|
2022-03-28 05:26:39 -04:00
|
|
|
return units.HumanSizeWithPrecision(c.s.NetworkRx, 3) + " / " + units.HumanSizeWithPrecision(c.s.NetworkTx, 3)
|
2016-07-18 14:30:15 -04:00
|
|
|
}
|
|
|
|
|
2018-10-23 11:05:44 -04:00
|
|
|
func (c *statsContext) BlockIO() string {
|
2016-09-22 08:54:41 -04:00
|
|
|
if c.s.IsInvalid {
|
2022-03-27 13:48:55 -04:00
|
|
|
return "--"
|
2016-09-22 08:54:41 -04:00
|
|
|
}
|
2022-03-28 05:26:39 -04:00
|
|
|
return units.HumanSizeWithPrecision(c.s.BlockRead, 3) + " / " + units.HumanSizeWithPrecision(c.s.BlockWrite, 3)
|
2016-07-18 14:30:15 -04:00
|
|
|
}
|
|
|
|
|
2018-10-23 11:05:44 -04:00
|
|
|
func (c *statsContext) PIDs() string {
|
2017-02-05 11:55:30 -05:00
|
|
|
if c.s.IsInvalid || c.os == winOSType {
|
2022-03-27 13:48:55 -04:00
|
|
|
return "--"
|
2016-07-18 14:30:15 -04:00
|
|
|
}
|
2022-03-28 05:26:39 -04:00
|
|
|
return strconv.FormatUint(c.s.PidsCurrent, 10)
|
|
|
|
}
|
|
|
|
|
|
|
|
func formatPercentage(val float64) string {
|
|
|
|
return strconv.FormatFloat(val, 'f', 2, 64) + "%"
|
2016-07-18 14:30:15 -04:00
|
|
|
}
|