github.com/dinever/docker@v1.11.1/daemon/stats.go (about)

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