stats.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. package formatter
  2. import (
  3. "fmt"
  4. "sync"
  5. "github.com/docker/go-units"
  6. )
  7. const (
  8. defaultStatsTableFormat = "table {{.Container}}\t{{.CPUPrec}}\t{{.MemUsage}}\t{{.MemPrec}}\t{{.NetIO}}\t{{.BlockIO}}\t{{.PIDs}}"
  9. winDefaultStatsTableFormat = "table {{.Container}}\t{{.CPUPrec}}\t{{{.MemUsage}}\t{.NetIO}}\t{{.BlockIO}}"
  10. emptyStatsTableFormat = "Waiting for statistics..."
  11. containerHeader = "CONTAINER"
  12. cpuPrecHeader = "CPU %"
  13. netIOHeader = "NET I/O"
  14. blockIOHeader = "BLOCK I/O"
  15. winMemPrecHeader = "PRIV WORKING SET" // Used only on Window
  16. memPrecHeader = "MEM %" // Used only on Linux
  17. memUseHeader = "MEM USAGE / LIMIT" // Used only on Linux
  18. pidsHeader = "PIDS" // Used only on Linux
  19. )
  20. // ContainerStatsAttrs represents the statistics data collected from a container.
  21. type ContainerStatsAttrs struct {
  22. Windows bool
  23. Name string
  24. CPUPercentage float64
  25. Memory float64 // On Windows this is the private working set
  26. MemoryLimit float64 // Not used on Windows
  27. MemoryPercentage float64 // Not used on Windows
  28. NetworkRx float64
  29. NetworkTx float64
  30. BlockRead float64
  31. BlockWrite float64
  32. PidsCurrent uint64 // Not used on Windows
  33. }
  34. // ContainerStats represents the containers statistics data.
  35. type ContainerStats struct {
  36. Mu sync.RWMutex
  37. ContainerStatsAttrs
  38. Err error
  39. }
  40. // NewStatsFormat returns a format for rendering an CStatsContext
  41. func NewStatsFormat(source, osType string) Format {
  42. if source == TableFormatKey {
  43. if osType == "windows" {
  44. return Format(winDefaultStatsTableFormat)
  45. }
  46. return Format(defaultStatsTableFormat)
  47. }
  48. return Format(source)
  49. }
  50. // NewContainerStats returns a new ContainerStats entity and sets in it the given name
  51. func NewContainerStats(name, osType string) *ContainerStats {
  52. return &ContainerStats{
  53. ContainerStatsAttrs: ContainerStatsAttrs{
  54. Name: name,
  55. Windows: (osType == "windows"),
  56. },
  57. }
  58. }
  59. // ContainerStatsWrite renders the context for a list of containers statistics
  60. func ContainerStatsWrite(ctx Context, containerStats []*ContainerStats) error {
  61. render := func(format func(subContext subContext) error) error {
  62. for _, cstats := range containerStats {
  63. cstats.Mu.RLock()
  64. cstatsAttrs := cstats.ContainerStatsAttrs
  65. cstats.Mu.RUnlock()
  66. containerStatsCtx := &containerStatsContext{
  67. s: cstatsAttrs,
  68. }
  69. if err := format(containerStatsCtx); err != nil {
  70. return err
  71. }
  72. }
  73. return nil
  74. }
  75. return ctx.Write(&containerStatsContext{}, render)
  76. }
  77. type containerStatsContext struct {
  78. HeaderContext
  79. s ContainerStatsAttrs
  80. }
  81. func (c *containerStatsContext) Container() string {
  82. c.AddHeader(containerHeader)
  83. return c.s.Name
  84. }
  85. func (c *containerStatsContext) CPUPrec() string {
  86. c.AddHeader(cpuPrecHeader)
  87. return fmt.Sprintf("%.2f%%", c.s.CPUPercentage)
  88. }
  89. func (c *containerStatsContext) MemUsage() string {
  90. c.AddHeader(memUseHeader)
  91. if !c.s.Windows {
  92. return fmt.Sprintf("%s / %s", units.BytesSize(c.s.Memory), units.BytesSize(c.s.MemoryLimit))
  93. }
  94. return fmt.Sprintf("-- / --")
  95. }
  96. func (c *containerStatsContext) MemPrec() string {
  97. header := memPrecHeader
  98. if c.s.Windows {
  99. header = winMemPrecHeader
  100. }
  101. c.AddHeader(header)
  102. return fmt.Sprintf("%.2f%%", c.s.MemoryPercentage)
  103. }
  104. func (c *containerStatsContext) NetIO() string {
  105. c.AddHeader(netIOHeader)
  106. return fmt.Sprintf("%s / %s", units.HumanSizeWithPrecision(c.s.NetworkRx, 3), units.HumanSizeWithPrecision(c.s.NetworkTx, 3))
  107. }
  108. func (c *containerStatsContext) BlockIO() string {
  109. c.AddHeader(blockIOHeader)
  110. return fmt.Sprintf("%s / %s", units.HumanSizeWithPrecision(c.s.BlockRead, 3), units.HumanSizeWithPrecision(c.s.BlockWrite, 3))
  111. }
  112. func (c *containerStatsContext) PIDs() string {
  113. c.AddHeader(pidsHeader)
  114. if !c.s.Windows {
  115. return fmt.Sprintf("%d", c.s.PidsCurrent)
  116. }
  117. return fmt.Sprintf("-")
  118. }