github.com/uppal0016/docker_new@v0.0.0-20240123060250-1c98be13ac2c/daemon/stats.go (about)

     1  package daemon
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"runtime"
     7  
     8  	"golang.org/x/net/context"
     9  
    10  	"github.com/docker/docker/api/types/backend"
    11  	"github.com/docker/docker/pkg/ioutils"
    12  	"github.com/docker/docker/pkg/version"
    13  	"github.com/docker/engine-api/types"
    14  	"github.com/docker/engine-api/types/versions/v1p20"
    15  )
    16  
    17  // ContainerStats writes information about the container to the stream
    18  // given in the config object.
    19  func (daemon *Daemon) ContainerStats(ctx context.Context, prefixOrName string, config *backend.ContainerStatsConfig) error {
    20  	if runtime.GOOS == "windows" {
    21  		return errors.New("Windows does not support stats")
    22  	}
    23  	// Remote API version (used for backwards compatibility)
    24  	apiVersion := version.Version(config.Version)
    25  
    26  	container, err := daemon.GetContainer(prefixOrName)
    27  	if err != nil {
    28  		return err
    29  	}
    30  
    31  	// If the container is not running and requires no stream, return an empty stats.
    32  	if !container.IsRunning() && !config.Stream {
    33  		return json.NewEncoder(config.OutStream).Encode(&types.Stats{})
    34  	}
    35  
    36  	outStream := config.OutStream
    37  	if config.Stream {
    38  		wf := ioutils.NewWriteFlusher(outStream)
    39  		defer wf.Close()
    40  		wf.Flush()
    41  		outStream = wf
    42  	}
    43  
    44  	var preCPUStats types.CPUStats
    45  	getStatJSON := func(v interface{}) *types.StatsJSON {
    46  		ss := v.(*types.StatsJSON)
    47  		ss.PreCPUStats = preCPUStats
    48  		// ss.MemoryStats.Limit = uint64(update.MemoryLimit)
    49  		preCPUStats = ss.CPUStats
    50  		return ss
    51  	}
    52  
    53  	enc := json.NewEncoder(outStream)
    54  
    55  	updates := daemon.subscribeToContainerStats(container)
    56  	defer daemon.unsubscribeToContainerStats(container, updates)
    57  
    58  	noStreamFirstFrame := true
    59  	for {
    60  		select {
    61  		case v, ok := <-updates:
    62  			if !ok {
    63  				return nil
    64  			}
    65  
    66  			var statsJSON interface{}
    67  			statsJSONPost120 := getStatJSON(v)
    68  			if apiVersion.LessThan("1.21") {
    69  				var (
    70  					rxBytes   uint64
    71  					rxPackets uint64
    72  					rxErrors  uint64
    73  					rxDropped uint64
    74  					txBytes   uint64
    75  					txPackets uint64
    76  					txErrors  uint64
    77  					txDropped uint64
    78  				)
    79  				for _, v := range statsJSONPost120.Networks {
    80  					rxBytes += v.RxBytes
    81  					rxPackets += v.RxPackets
    82  					rxErrors += v.RxErrors
    83  					rxDropped += v.RxDropped
    84  					txBytes += v.TxBytes
    85  					txPackets += v.TxPackets
    86  					txErrors += v.TxErrors
    87  					txDropped += v.TxDropped
    88  				}
    89  				statsJSON = &v1p20.StatsJSON{
    90  					Stats: statsJSONPost120.Stats,
    91  					Network: types.NetworkStats{
    92  						RxBytes:   rxBytes,
    93  						RxPackets: rxPackets,
    94  						RxErrors:  rxErrors,
    95  						RxDropped: rxDropped,
    96  						TxBytes:   txBytes,
    97  						TxPackets: txPackets,
    98  						TxErrors:  txErrors,
    99  						TxDropped: txDropped,
   100  					},
   101  				}
   102  			} else {
   103  				statsJSON = statsJSONPost120
   104  			}
   105  
   106  			if !config.Stream && noStreamFirstFrame {
   107  				// prime the cpu stats so they aren't 0 in the final output
   108  				noStreamFirstFrame = false
   109  				continue
   110  			}
   111  
   112  			if err := enc.Encode(statsJSON); err != nil {
   113  				return err
   114  			}
   115  
   116  			if !config.Stream {
   117  				return nil
   118  			}
   119  		case <-ctx.Done():
   120  			return nil
   121  		}
   122  	}
   123  }