github.com/containerd/nerdctl@v1.7.7/pkg/statsutil/stats.go (about)

     1  /*
     2     Copyright The containerd Authors.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package statsutil
    18  
    19  import (
    20  	"fmt"
    21  	"strconv"
    22  	"sync"
    23  	"time"
    24  
    25  	units "github.com/docker/go-units"
    26  )
    27  
    28  // StatsEntry represents the statistics data collected from a container
    29  type StatsEntry struct {
    30  	Container        string
    31  	Name             string
    32  	ID               string
    33  	CPUPercentage    float64
    34  	Memory           float64
    35  	MemoryLimit      float64
    36  	MemoryPercentage float64
    37  	NetworkRx        float64
    38  	NetworkTx        float64
    39  	BlockRead        float64
    40  	BlockWrite       float64
    41  	PidsCurrent      uint64
    42  	IsInvalid        bool
    43  }
    44  
    45  // FormattedStatsEntry represents a formatted StatsEntry
    46  type FormattedStatsEntry struct {
    47  	Name     string
    48  	ID       string
    49  	CPUPerc  string
    50  	MemUsage string
    51  	MemPerc  string
    52  	NetIO    string
    53  	BlockIO  string
    54  	PIDs     string
    55  }
    56  
    57  // Stats represents an entity to store containers statistics synchronously
    58  type Stats struct {
    59  	mutex sync.RWMutex
    60  	StatsEntry
    61  	err error
    62  }
    63  
    64  // ContainerStats represents the runtime container stats
    65  type ContainerStats struct {
    66  	Time                        time.Time
    67  	CgroupCPU, Cgroup2CPU       uint64
    68  	CgroupSystem, Cgroup2System uint64
    69  }
    70  
    71  // NewStats is from https://github.com/docker/cli/blob/3fb4fb83dfb5db0c0753a8316f21aea54dab32c5/cli/command/container/formatter_stats.go#L113-L116
    72  func NewStats(container string) *Stats {
    73  	return &Stats{StatsEntry: StatsEntry{Container: container}}
    74  }
    75  
    76  // SetStatistics is from https://github.com/docker/cli/blob/3fb4fb83dfb5db0c0753a8316f21aea54dab32c5/cli/command/container/formatter_stats.go#L87-L93
    77  func (cs *Stats) SetStatistics(s StatsEntry) {
    78  	cs.mutex.Lock()
    79  	defer cs.mutex.Unlock()
    80  	s.Container = cs.Container
    81  	cs.StatsEntry = s
    82  }
    83  
    84  // GetStatistics is from https://github.com/docker/cli/blob/3fb4fb83dfb5db0c0753a8316f21aea54dab32c5/cli/command/container/formatter_stats.go#L95-L100
    85  func (cs *Stats) GetStatistics() StatsEntry {
    86  	cs.mutex.Lock()
    87  	defer cs.mutex.Unlock()
    88  	return cs.StatsEntry
    89  }
    90  
    91  // GetError is from https://github.com/docker/cli/blob/3fb4fb83dfb5db0c0753a8316f21aea54dab32c5/cli/command/container/formatter_stats.go#L51-L57
    92  func (cs *Stats) GetError() error {
    93  	cs.mutex.Lock()
    94  	defer cs.mutex.Unlock()
    95  	return cs.err
    96  }
    97  
    98  // SetErrorAndReset is from https://github.com/docker/cli/blob/3fb4fb83dfb5db0c0753a8316f21aea54dab32c5/cli/command/container/formatter_stats.go#L59-L75
    99  func (cs *Stats) SetErrorAndReset(err error) {
   100  	cs.mutex.Lock()
   101  	defer cs.mutex.Unlock()
   102  	cs.CPUPercentage = 0
   103  	cs.Memory = 0
   104  	cs.MemoryPercentage = 0
   105  	cs.MemoryLimit = 0
   106  	cs.NetworkRx = 0
   107  	cs.NetworkTx = 0
   108  	cs.BlockRead = 0
   109  	cs.BlockWrite = 0
   110  	cs.PidsCurrent = 0
   111  	cs.err = err
   112  	cs.IsInvalid = true
   113  }
   114  
   115  // SetError is from https://github.com/docker/cli/blob/3fb4fb83dfb5db0c0753a8316f21aea54dab32c5/cli/command/container/formatter_stats.go#L77-L85
   116  func (cs *Stats) SetError(err error) {
   117  	cs.mutex.Lock()
   118  	defer cs.mutex.Unlock()
   119  	cs.err = err
   120  	if err != nil {
   121  		cs.IsInvalid = true
   122  	}
   123  }
   124  
   125  func calculateMemPercent(limit float64, usedNo float64) float64 {
   126  	// Limit will never be 0 unless the container is not running and we haven't
   127  	// got any data from cgroup
   128  	if limit != 0 {
   129  		return usedNo / limit * 100.0
   130  	}
   131  	return 0
   132  }
   133  
   134  // Rendering a FormattedStatsEntry from StatsEntry
   135  func RenderEntry(in *StatsEntry, noTrunc bool) FormattedStatsEntry {
   136  	return FormattedStatsEntry{
   137  		Name:     in.EntryName(),
   138  		ID:       in.EntryID(noTrunc),
   139  		CPUPerc:  in.CPUPerc(),
   140  		MemUsage: in.MemUsage(),
   141  		MemPerc:  in.MemPerc(),
   142  		NetIO:    in.NetIO(),
   143  		BlockIO:  in.BlockIO(),
   144  		PIDs:     in.PIDs(),
   145  	}
   146  }
   147  
   148  /*
   149  a set of functions to format container stats
   150  */
   151  func (s *StatsEntry) EntryName() string {
   152  	if len(s.Name) > 1 {
   153  		if len(s.Name) > 12 {
   154  			return s.Name[:12]
   155  		}
   156  		return s.Name
   157  	}
   158  	return "--"
   159  }
   160  
   161  func (s *StatsEntry) EntryID(noTrunc bool) string {
   162  	if !noTrunc {
   163  		if len(s.ID) > 12 {
   164  			return s.ID[:12]
   165  		}
   166  	}
   167  	return s.ID
   168  }
   169  
   170  func (s *StatsEntry) CPUPerc() string {
   171  	if s.IsInvalid {
   172  		return "--"
   173  	}
   174  	return fmt.Sprintf("%.2f%%", s.CPUPercentage)
   175  }
   176  
   177  func (s *StatsEntry) MemUsage() string {
   178  	if s.IsInvalid {
   179  		return "-- / --"
   180  	}
   181  	return fmt.Sprintf("%s / %s", units.BytesSize(s.Memory), units.BytesSize(s.MemoryLimit))
   182  }
   183  
   184  func (s *StatsEntry) MemPerc() string {
   185  	if s.IsInvalid {
   186  		return "--"
   187  	}
   188  	return fmt.Sprintf("%.2f%%", s.MemoryPercentage)
   189  }
   190  
   191  func (s *StatsEntry) NetIO() string {
   192  	if s.IsInvalid {
   193  		return "--"
   194  	}
   195  	return fmt.Sprintf("%s / %s", units.HumanSizeWithPrecision(s.NetworkRx, 3), units.HumanSizeWithPrecision(s.NetworkTx, 3))
   196  }
   197  
   198  func (s *StatsEntry) BlockIO() string {
   199  	if s.IsInvalid {
   200  		return "--"
   201  	}
   202  	return fmt.Sprintf("%s / %s", units.HumanSizeWithPrecision(s.BlockRead, 3), units.HumanSizeWithPrecision(s.BlockWrite, 3))
   203  }
   204  
   205  func (s *StatsEntry) PIDs() string {
   206  	if s.IsInvalid {
   207  		return "--"
   208  	}
   209  	return strconv.FormatUint(s.PidsCurrent, 10)
   210  }